diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index f96d0c9..0000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -.github diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 59f25f9..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - 'semistandard' - ] -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..9905628 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "semistandard" + ] +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index be113be..99877da 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: - node-version: [12.x, 14.x] + node-version: [14.x, 16.x] steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index b730740..0cab1c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +node_modules canhazdata certs -node_modules +coverage +web/public +web/meta.json diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index cb07f68..0000000 --- a/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM node:14-alpine - -WORKDIR /app - -RUN apk upgrade --update-cache --available && \ - apk add openssl && \ - rm -rf /var/cache/apk/* - -COPY package.json package.json -COPY package-lock.json package-lock.json - -RUN npm ci -RUN npm install canhazdb-driver-ejdb - -COPY . . - -RUN ln -s /app/lib/cli.js /bin/canhazdb - -ENTRYPOINT ["canhazdb"] - diff --git a/README.md b/README.md index 1421dad..b50b105 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ [![GitHub](https://img.shields.io/github/license/canhazdb/server)](https://github.com/canhazdb/server/blob/master/LICENSE) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg)](https://github.com/standard/semistandard) -A sharded and clustered database communicated over http rest with notifications included. +An embeddable or standalone database, that shards data across a cluster of nodes, with eventing. ## Getting Started -You must have a minimum version of Node 12 installed. +You must have a minimum version of Node 16 installed. Create the tls files you need to secure your cluster. @@ -17,35 +17,18 @@ A bash script `./makeCerts.sh` provided will create a folder with test certs you You can opt out of tls by omitting the tls option from canhazdb. -### Client -You can talk to the database via http/https using your favourite http client, or -you can use the [official client](https://github.com/canhazdb/client). - -### Drivers -As of version 5.0.0, drivers have been abstracted out and installed separately. - -The current official drivers are: -- [canhazdb-driver-ejdb](https://github.com/canhazdb/driver-ejdb) -- [canhazdb-driver-nedb](https://github.com/canhazdb/driver-nedb) -- [canhazdb-driver-sqlite](https://github.com/canhazdb/driver-sqlite) - -It should be fairly trivial to implement a driver for other databases. If -you would like to create a custom driver, take a look at the -[nedb driver index file](https://github.com/canhazdb/driver-nedb/blob/master/lib/index.js) -for an example. - ### Server Via Docker The quickest way to setup a test server is via: ```bash docker run -itp 8060:8060 canhazdb/server --single ``` -Then visit http://localhost:8060 +Then visit http://localhost:8080 But you can create a production ready and scalable stack by -using the [stack.yml](stack.yml) file as an example. +using the [demo.sh](demo.sh) file as an example. -This will give you TLS authenication and encryption along with +This will give you TLS authentication and encryption along with persistent storage. ### Server Via the CLI @@ -56,10 +39,8 @@ npm install --global canhazdb-server #### Create a single node server ```bash canhazdb-server \ - --driver canhazdb-driver-ejdb \ --host localhost \ --port 7061 \ - --query-port 8061 \ --data-dir ./canhazdb/one \ --tls-ca ./certs/ca.cert.pem \ --tls-cert ./certs/localhost.cert.pem \ @@ -69,10 +50,8 @@ canhazdb-server \ #### Add some more to the cluster ```bash canhazdb-server \ - --driver canhazdb-driver-ejdb \ --host localhost \ --port 7062 \ - --query-port 8062 \ --data-dir ./canhazdb/two \ --tls-ca ./certs/ca.cert.pem \ --tls-cert ./certs/localhost.cert.pem \ @@ -80,10 +59,8 @@ canhazdb-server \ --join localhost:7061 canhazdb-server \ - --driver canhazdb-driver-ejdb \ --host localhost \ --port 7063 \ - --query-port 8063 \ --data-dir ./canhazdb/three \ --tls-ca ./certs/ca.cert.pem \ --tls-cert ./certs/localhost.cert.pem \ @@ -93,14 +70,13 @@ canhazdb-server \ ### Server Via NodeJS ```bash -npm install --save canhazdb-server canhazdb-driver-ejdb +npm install --save canhazdb-server canhazdb-client ``` ```javascript const fs = require('fs'); -const https = require('https'); -const axios = require('axios'); -const canhazdb = require('canhazdb-server'); +const createServer = require('canhazdb-server'); +const createClient = require('canhazdb-client'); async function main () { const tls = { @@ -110,40 +86,36 @@ async function main () { requestCert: true /* this denys any cert not signed with our ca above */ }; - const node1 = await canhazdb({ - driver: 'canhazdb-driver-ejdb', + const node1 = await createServer({ host: 'localhost', - port: 7061, queryPort: 8061, + port: 7061, dataDirectory: './canhazdata/one', - tls, single: true + tls }); - const node2 = await canhazdb({ - driver: 'canhazdb-driver-ejdb', + + const node2 = await createServer({ host: 'localhost', - port: 7062, queryPort: 8062, + port: 7062, dataDirectory: './canhazdata/two', tls, join: ['localhost:7061'] }); // You can join to other nodes after starting: - // await node2.join({ host: 'otherhost', port: 7063 }) + // await node2.join({ host: 'otherhost', port: 8060 }) - const postRequest = await axios(`${node1.url}/tests`, { - httpsAgent: new https.Agent(tls), - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } + const db = await createClient({ host: 'localhost', port: 8060, ...tls }); + const postedDocument = await db.post('tests', { + a: 1, + b: 2, + c: 3 }); - // node2.url === 'https://localhost:8061' - const result = await axios(`${node2.url}/tests/${postRequest.data.id}`, { - httpsAgent: new https.Agent(tls) + const result = await db.getOne('tests', { + query: { + id: postedDocument.id + } }); - - console.log(result.data); + console.log(result); /* { @@ -165,454 +137,19 @@ The `system.collections` collection contains a document for each collection, alo amount of documents that stores. ```javascript -axios('/system.collections', { - httpsAgent: new https.Agent(tls) -}) === [{ - id: 'uuid-uuid-uuid-uuid', - collectionId: 'tests', - documentCount: 1 -}] -``` - -## Endpoints - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodPathDescription
1GET/:collectionId?fieldsList all documents for a collection
2GET/:collectionId/:documentId?query&count&fields&limit&orderGet a document by id
3POST/:collectionIdCreate a new document
4PUT/:collectionId/:documentIdReplace a document by id
5PUT/:collectionId/:documentId?queryReplace multiple document matching query
6PATCH/:collectionId/:documentIdPartially update a document by id
7PATCH/:collectionId/:documentId?queryPartially update multiple document matching query
8DELETE/:collectionId/:documentIdDelete a document by id
9DELETE/:collectionId/:documentId?queryDelete multiple document matching query
10POST/_/locksLock a collection/document/field combination
11DELETE/_/locks/:lockIdRelease a lock
- -### Examples -
-1. Get item by id - - - - - -
MethodGET
URL/collectionId
FieldsJSON Array
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests/example-uuid-paramater?fields=["firstName"]', -}) -``` - -**Client:** -```javascript -client.get('tests', { - query: { - id: 'example-uuid-paramater' - } -}); -``` -
- -
-2. Get document count in a collection - - - - - -
MethodGET
URL/collectionId?count=true
QueryMongo Query Syntax
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests?count=true&query={"firstName":"Joe"}', -}) -``` +await db.getAll('system.collections') -**Client:** -```javascript -client.count('tests', { - query: { - firstName: 'Joe' - } -}); +/* + [{ + id: 'uuid-uuid-uuid-uuid', + collectionId: 'tests', + documentCount: 1 + }] +*/ ``` -
- -
-3. Get items in a collection - - - - - - - -
MethodGET
URL/collectionId
QueryMongo Query Syntax
FieldsJSON Array
LimitNumber
OrderDirection(fieldName)
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests?query={"firstName":"Joe"}&fields=["firstName"]&limit=10&order=desc(firstName)', -}) -``` - -**Client:** -```javascript -client.get('tests', { - query: { - firstName: 'Joe' - }, - limit: 10, - order: 'desc(firstName)' -}); -``` -
- -
-4. Create a new document in a collection - - - - - -
MethodPOST
URL/collectionId
DataJSON
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests', - method: 'POST', - data: { - firstName: 'Joe' - } -}) -``` - -**Client:** -```javascript -client.post('tests', { - firstName: 'Joe' -}); -``` -
- -
-5. Replace a document by id - - - - - -
MethodPUT
URL/collectionId/documentId
DataJSON
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests/example-uuid-paramater', - method: 'PUT', - data: { - firstName: 'Zoe' - } -}) -``` - -**Client:** -```javascript -client.put('tests', { - firstName: 'Joe' -}); -``` -
- -
-6. Replace multiple documents by query - - - - - -
MethodPUT
URL/collectionId/documentId
DataJSON
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests?query={"location":"GB"}', - method: 'PUT', - data: { - firstName: 'Zoe', - location: 'GB', - timezone: 'GMT' - } -}) -``` - -**Client:** -```javascript -client.put('tests', { - firstName: 'Zoe', - location: 'GB', - timezone: 'GMT' -}, { - query: { - location: 'GB' - } -}); -``` -
- -
-7. Partially update multiple documents by id - - - - - -
MethodPATCH
URL/collectionId/documentId
DataJSON
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests/example-uuid-paramater', - method: 'PATCH', - data: { - timezone: 'GMT' - } -}) -``` - -**Client:** -```javascript -client.patch('tests', { - timezone: 'GMT' -}, { - query: { - location: 'GB' - } -}); -``` -
- -
-8. Partially update multiple documents by query - - - - - -
MethodPATCH
URL/collectionId/documentId
DataJSON
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests?query={"location":"GB"}', - method: 'PATCH', - data: { - timezone: 'GMT' - } -}) -``` - -**Client:** -```javascript -client.patch('tests', { - timezone: 'GMT' -}, { - query: { - location: 'GB' - } -}); -``` -
- -
-9. Delete a document by id - - - - -
MethodDELETE
URL/collectionId/documentId
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests/example-uuid-paramater', - method: 'DELETE' -}) -``` - -**Client:** -```javascript -client.delete('tests', { - query: { - id: 'example-uuid-paramater' - } -}); -``` - -
- -
-10. Delete multiple documents by query - - - - -
MethodDELETE
URL/collectionId/documentId
- -**HTTP Request:** -```javascript -axios({ - url: 'https://localhost:8061/tests?query={"location":"GB"}', - method: 'DELETE' -}) -``` - -**Client:** -```javascript -client.delete('tests', { - query: { - location: 'GB' - } -}); -``` -
- -
-11. Lock a collection/document/field combination - - - - - -
MethodPOST
URL/_/locks
DataJSON Array
- -**HTTP Request:** -```javascript -const lock = await axios({ - url: 'https://localhost:8061/_/locks', - method: 'POST', - data: ['users'] -}); -const lockId = lock.data.id; -``` - -**Client:** -```javascript -const lockId = await client.lock('users'); -``` -
- -
-12. Release a lock - - - - -
MethodDELETE
URL/_/locks/:lockId
- -**HTTP Request:** -```javascript -const lock = await axios({ - url: 'https://localhost:8061/_/locks', - method: 'POST', - data: ['users'] -}); -const lockId = lock.data.id; - -const lock = await axios({ - url: 'https://localhost:8061/users', - method: 'POST', - headers: { - 'x-lock-id': lockId, - 'x-lock-strategy': 'wait' // optional: can be 'fail' or 'wait'. default is 'wait'. - } -}); - -await axios({ - url: `https://localhost:8061/_/locks/${lockId}`, - method: 'DELETE' -}); -``` - -**Client:** -```javascript -const lockId = await client.lock(['users']); -const newDocument = await client.post('users', { - name: 'mark' -}, { - lockId, - lockStrategy: 'wait' // optional: can be 'fail' or 'wait'. default is 'wait'. -}); -await client.unlock(lockId); -``` -
+## API +See the API documentation for the [client docs](https://canhazdb.github.io/client/modules/index.html). ## License This project is licensed under the terms of the AGPL-3.0 license. diff --git a/demo.sh b/demo.sh new file mode 100755 index 0000000..d3afcbc --- /dev/null +++ b/demo.sh @@ -0,0 +1,8 @@ +node lib/cli.js \ + --tls-ca ./certs/ca.cert.pem \ + --tls-cert ./certs/localhost.cert.pem \ + --tls-key ./certs/localhost.privkey.pem \ + --http-host localhost \ + --http-port 8001 \ + --web-host localhost \ + --web-port 8080 diff --git a/docs/consistency.md b/docs/consistency.md new file mode 100644 index 0000000..7b44caf --- /dev/null +++ b/docs/consistency.md @@ -0,0 +1,83 @@ +# Terminology +## Route Types +- external +- internal +- system + +## Node States +connected = true if a socket is open, false if not. +online = true if has connected and had at least one full sync + +## Node Health +healthy = node is fully functional, accept all routes +unhealthy = node has conflicts, accepts only system routes +critical = node had conflicts, but could not resolve them + +# Node Workflow +- Process starts +- Status is unhealthy +- Attempts to join any previous known nodes +- Attempts to join any specified nodes in options +- Server is started, for system communication only +- Wait until 51% of node are online +- Resolve any conflicts +- Status is healthy +- Server accepts all communication + +# Health +When a node comes online, it's default state is "unhealthy". + +A node can be in only one of the following states: +- healthy = is online, can communicate and is ready for querying +- unhealthy = is online, can communicate but only for system commands +- fatal = is online, but has conflicts that it's unable to resolve +- offline = is offline and can't do anything + +When a node establishes a connection with another node, it learns about any conflicts that node knows about, and adds them to it's own conflict array. + +If there are any conflicts, they are resolved (see [conflicts](#conflicts) section). If there are none, or once they are all resolved, the node will broadcast to all other node that it's state is "healthy" during the next sync. + +# Conflicts +When a node goes offline, is unresponsive or has some sort of internal error, it's possible for it's data to become out of sync with the cluster. + +Every node keeps an inmemory array of all conflicts. + +When an external query attempts to mutate a record, but one of the replica nodes fail to respond, it will: +- Add an item to the conflicts array +- Tell all other online nodes about the conflict + +If a node learns it has a conflict, from another node or during startup, it will change it's health to 'unhealthy' and attempt to resolve the conflicts. + +## Resolutions +When a node learns it has a conflict, it changes it's state to 'unhealthy', therefore refusing to answer any internal or external actions. + +A conflict contains a `uuid`, `nodeName`, `method`, `collectionId`, `documentId`, `data` and `timestamp`. + +For each conflict, the owning node, will try to sync it's own data with the other nodes. + +Conflicts can only be resolved if more than 51% of the cluster is online. + +The process is: +1. Replace own data record, or delete, as stated via the `method` +2. Broadcasts the conflict `uuid` has been resolved +3. Each node then removes the conflict + +# External Actions + +## post /test { color: 'blue' } +- selects 3 nodes +- all 3 nodes respond with STATUS_CREATED + +## get /test { color: 'blue } +- receives 1 document out of 3 replications + +## put /test { color: 'red' } +### full green +- all 3 nodes respond with STATUS_OK +- put was successful +### partial green +- 2 nodes respond with STATUS_OK +- 1 node does not respond +- adds new conflict [{ method, collectionId, documentId, data, timestamp }] +- other nodes change unresponsive node's health to "unhealthy" +- put was successful diff --git a/index.js b/index.js deleted file mode 100644 index bb0a047..0000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib'); diff --git a/lib/actions/http/getAll.js b/lib/actions/http/getAll.js deleted file mode 100644 index 83c4a79..0000000 --- a/lib/actions/http/getAll.js +++ /dev/null @@ -1,67 +0,0 @@ -const writeResponse = require('write-response'); - -const orderByFields = require('../../../utils/orderByFields'); - -const { - COMMAND, - GET, - STATUS, - DATA, - COLLECTION_ID, - QUERY, - DOCUMENTS, - FIELDS, - ORDER, - LIMIT -} = require('../../constants'); - -function askOnAllNodes (state, data) { - return Promise.all( - state.nodes.map(node => node.connection.send(data)) - ); -} - -async function handleGetAll (state, request, response, { collectionId, url }) { - const limit = url.searchParams.get('limit') && JSON.parse(url.searchParams.get('limit')); - const orders = url.searchParams.get('order') && JSON.parse(url.searchParams.get('order')); - - const responses = await askOnAllNodes(state, { - [COMMAND]: GET, - [DATA]: { - [COLLECTION_ID]: collectionId, - [QUERY]: url.searchParams.get('query') && JSON.parse(url.searchParams.get('query')), - [FIELDS]: url.searchParams.get('fields') && JSON.parse(url.searchParams.get('fields')), - [ORDER]: orders || undefined, - [LIMIT]: limit || undefined - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - if (!responses.find(response => response[STATUS] === 200)) { - writeResponse(200, [], response); - return; - } - - let results = responses - .map(response => response[DOCUMENTS]) - .flat() - .filter(item => !!item); - - if (limit) { - results = results.slice(0, limit); - } - - if (orders) { - orders.forEach(order => { - orderByFields(results, order); - }); - } - - writeResponse(200, results, response); -} - -module.exports = handleGetAll; diff --git a/lib/actions/http/getOne.js b/lib/actions/http/getOne.js deleted file mode 100644 index 7e09e24..0000000 --- a/lib/actions/http/getOne.js +++ /dev/null @@ -1,56 +0,0 @@ -const writeResponse = require('write-response'); - -const { - COMMAND, - GET, - STATUS, - DATA, - COLLECTION_ID, - RESOURCE_ID, - QUERY, - LIMIT, - DOCUMENTS, - FIELDS -} = require('../../constants'); - -function askOnAllNodes (state, data) { - return Promise.all( - state.nodes.map(node => node.connection.send(data)) - ); -} - -async function handleGetOne (state, request, response, { collectionId, resourceId, url }) { - const responses = await askOnAllNodes(state, { - [COMMAND]: GET, - [DATA]: { - [COLLECTION_ID]: collectionId, - [QUERY]: url.searchParams.get('query') && JSON.parse(url.searchParams.get('query')), - [RESOURCE_ID]: resourceId, - [LIMIT]: 1, - [FIELDS]: url.searchParams.get('fields') && JSON.parse(url.searchParams.get('fields')) - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - if (!responses.find(response => response[STATUS] === 200)) { - writeResponse(404, {}, response); - return; - } - - const results = responses - .map(response => response[DOCUMENTS] || []) - .flat(); - - if (results.length === 0) { - writeResponse(404, {}, response); - return; - } - - writeResponse(200, results[0], response); -} - -module.exports = handleGetOne; diff --git a/lib/actions/http/post.js b/lib/actions/http/post.js deleted file mode 100644 index 2cded77..0000000 --- a/lib/actions/http/post.js +++ /dev/null @@ -1,52 +0,0 @@ -const writeResponse = require('write-response'); -const finalStream = require('final-stream'); - -const selectRandomItemFromArray = require('../../../utils/selectRandomItemFromArray'); -const handleInvalidRequestBody = require('../../handleInvalidRequestBody'); - -const { - COMMAND, - STATUS, - DATA, - DOCUMENT, - POST, - LOCK_ID, - COLLECTION_ID, - LOCK_STRATEGY, - LOCK_STRATEGY_FAIL, - LOCK_STRATEGY_WAIT -} = require('../../constants'); - -async function handlePost (state, request, response, { collectionId }) { - const body = await finalStream(request).then(JSON.parse) - .catch(handleInvalidRequestBody); - - const documents = Array.isArray(body) ? body : [body]; - - const promises = documents.map(document => { - const node = selectRandomItemFromArray(state.nodes); - - return node.connection.send({ - [COMMAND]: POST, - [DATA]: { - [COLLECTION_ID]: collectionId, - [LOCK_ID]: request.headers['x-lock-id'], - [LOCK_STRATEGY]: request.headers['x-lock-strategy'] === 'fail' ? LOCK_STRATEGY_FAIL : LOCK_STRATEGY_WAIT, - [DOCUMENT]: document - } - }); - }); - - const results = await Promise.all(promises); - if (results.length === 1) { - writeResponse(results[0][STATUS], results[0][DOCUMENT] || results[0][DATA], response); - return; - } - - writeResponse(201, results.map(result => ({ - status: result[STATUS], - document: result[DOCUMENT] - })), response); -} - -module.exports = handlePost; diff --git a/lib/actions/ws/getAll.js b/lib/actions/ws/getAll.js deleted file mode 100644 index c310a5b..0000000 --- a/lib/actions/ws/getAll.js +++ /dev/null @@ -1,56 +0,0 @@ -const { - COMMAND, - DATA, - GET, - STATUS, - DOCUMENTS, - LIMIT, - ORDER -} = require('../../constants'); - -const orderByFields = require('../../../utils/orderByFields'); - -function askOnAllNodes (state, data) { - return Promise.all( - state.nodes.map(node => node.connection.send(data)) - ); -} - -async function handleGetAll (acceptId, state, data, socket) { - const responses = await askOnAllNodes(state, { - [COMMAND]: GET, - [DATA]: data - }); - - if (responses.find(response => response[STATUS] >= 500)) { - socket.send(JSON.stringify(['A', acceptId, responses[0]])); - return; - } - - if (!responses.find(response => response[STATUS] === 200)) { - socket.send(JSON.stringify(['A', acceptId, []])); - return; - } - - let results = responses - .map(response => response[DOCUMENTS]) - .flat() - .filter(item => !!item); - - if (data[LIMIT]) { - results = results.slice(0, data[LIMIT]); - } - - if (data[ORDER]) { - data[ORDER].forEach(order => { - orderByFields(results, order); - }); - } - - socket.send(JSON.stringify(['A', acceptId, { - [STATUS]: 200, - [DOCUMENTS]: results - }])); -} - -module.exports = handleGetAll; diff --git a/lib/actions/ws/post.js b/lib/actions/ws/post.js deleted file mode 100644 index 66eb528..0000000 --- a/lib/actions/ws/post.js +++ /dev/null @@ -1,20 +0,0 @@ -const selectRandomItemFromArray = require('../../../utils/selectRandomItemFromArray'); - -const { - COMMAND, - DATA, - POST -} = require('../../constants'); - -async function handlePost (acceptId, state, data, socket) { - const node = selectRandomItemFromArray(state.nodes); - - const result = await node.connection.send({ - [COMMAND]: POST, - [DATA]: data - }); - - socket.send(JSON.stringify(['A', acceptId, result])); -} - -module.exports = handlePost; diff --git a/lib/cli.js b/lib/cli.js old mode 100755 new mode 100644 index f3dd06d..5ed7623 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,111 +1,98 @@ #!/usr/bin/env node -const packageJson = require('../package.json'); +import process from 'process'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; -const process = require('process'); -const fs = require('fs'); -const os = require('os'); +import logslot from 'logslot'; +import chalk from 'chalk'; +import minimist from 'minimist'; -const npm = require('npm'); -const path = require('path'); +import canhazdb from './index.js'; +import startRepl from './startRepl.js'; -const chalk = require('chalk'); -const argv = require('minimist')(process.argv.slice(2)); +const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')); -const canhazdb = require('./'); +const argv = minimist(process.argv.slice(2)); +const log = logslot('canhazdb.cli'); function showHelp () { console.log(` -The scalable, sharded database engine. +The scalable, sharded, clustered database engine. https://canhazdb.com The following commands and arguments are available when starting Bitabase Arguments: - --node-name optional Unique name for the node in the cluster (default: $HOSTNAME) - --data-dir optional The port to bind the https query server on (default: ./canhazdata) + --tls-ca required The certificate authority to use for the certs + --tls-cert required The public certificate for the server + --tls-key required The private key for the server - --driver optional The driver to use for data storage (default: canhazdb-driver-ejdb) + --host optional The host to bind the server on (default: localhost) + --port optional The port to bind the server on (default: 7060) - --host optional The host to bind the internal and query server on (default: localhost) - --port optional The port to bind the internal server on (default: 7060) - --query-port optional The port to bind the https query server on (default: 8060) + --http-host optional The host to bind the http server on (default: off) + --http-port optional The port to bind the http server on (default: off) - --tls-ca optional The certificate authority to use for the certs - --tls-cert optional The public certificate for the internal and query servers - --tls-key optional The private key for the internal and query servers + --web-host optional The host to bind the web html gui server on (default: off) + --web-port optional The port to bind the web html gui server on (default: off) --join optional Join another canhazdb node --join-from-dns optional Lookup other canhazdb nodes to join from a dns lookup - --single optional Start the node in single none clustered mode + --node-name optional Unique name for the node in the cluster (default: $HOSTNAME) + --data-dir optional The port to bind the https query server on (default: ./canhazdata) + + --repl optional Start a repl, allowing you to script in the terminal `.trim() + '\n'); } -console.log(`${chalk.green(chalk.bold(`📦 ${packageJson.name}`))} ${chalk.green(`- v${packageJson.version}`)}`); - -argv.driver = argv.driver || 'canhazdb-driver-ejdb'; +log.info(`${chalk.green(chalk.bold(`📦 ${packageJson.name}`))} ${chalk.green(`- v${packageJson.version}`)}`); if (argv.join) { argv.join = Array.isArray(argv.join) ? argv.join : [argv.join]; } -function installDriver () { - return new Promise((resolve, reject) => { - if (fs.existsSync('./node_modules/' + argv.driver)) { - return resolve(); - } - - npm.load(function (error) { - if (error) { - return reject(error); - } - - npm.commands.install([argv.driver], function (error, data) { - if (error) { - return reject(error); - } - resolve(); - }); - - npm.on('log', function (message) { - console.log(message); - }); - }); - }); -} - process.on('SIGINT', () => { - console.info('Interrupted'); + log.info('Interrupted'); process.exit(0); }); -if (argv.help) { - showHelp(); - process.exit(1); -} else { - installDriver() - .then(() => { - const nodeName = argv['node-name'] || process.env.CANHAZDB_NODE_NAME || os.hostname(); - return canhazdb({ - dataDirectory: argv['data-dir'] || path.resolve(process.cwd(), './canhazdata', nodeName), - nodeName: argv['node-name'], - driver: argv.driver, - host: argv.host || 'localhost', - port: argv.port || 7060, - queryPort: argv['query-port'] || 8060, - tlsCa: argv['tls-ca'], - tlsCert: argv['tls-cert'], - tlsKey: argv['tls-key'], - join: argv.join, - joinFromDns: argv['join-from-dns'], - single: argv.single - }); - }).then(node => { - console.log(''); - console.log(`${chalk.cyan('internal server')}: ${node.host}:${node.port}`); - console.log(`${chalk.cyan('query server')}: ${node.url}`); - }).catch(error => { - console.log(error); - process.exit(1); - }); +async function main () { + if (argv.help) { + showHelp(); + process.exit(1); + } + + if (!argv['tls-ca'] || !argv['tls-cert'] || !argv['tls-key']) { + throw new Error('all tls-ca, tls-cert and tls-key arguments must be provided'); + } + + const nodeName = argv['node-name'] || process.env.CANHAZDB_NODE_NAME || os.hostname(); + const node = await canhazdb({ + dataDirectory: argv['data-dir'] || path.resolve(process.cwd(), './canhazdata', nodeName), + nodeName: argv['node-name'], + host: argv.host || 'localhost', + port: argv.port || 7060, + tlsCa: argv['tls-ca'], + tlsCert: argv['tls-cert'], + tlsKey: argv['tls-key'], + join: argv.join, + joinFromDns: argv['join-from-dns'], + httpHost: argv['http-host'], + httpPort: argv['http-port'], + webHost: argv['web-host'], + webPort: argv['web-port'] + }).catch(error => { + log.error(error); + process.exit(1); + }); + + log.info(`${chalk.cyan('internal server')}: ${node.options.host}:${node.options.port}`); + + if (argv.repl) { + startRepl(node); + } } + +main(); diff --git a/lib/constants.js b/lib/constants.js index 8a11c99..332e13a 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,38 +1,70 @@ -let commandIndex = 0; - const constants = { - COMMAND: commandIndex++, - STATUS: commandIndex++, - DOCUMENT: commandIndex++, - DOCUMENTS: commandIndex++, - DATA: commandIndex++, - INFO: commandIndex++, - NOTIFY_ON: commandIndex++, - NOTIFY_OFF: commandIndex++, - LOCK: commandIndex++, - UNLOCK: commandIndex++, - COUNT: commandIndex++, - GET: commandIndex++, - POST: commandIndex++, - PUT: commandIndex++, - PATCH: commandIndex++, - DELETE: commandIndex++, - LOCK_ID: commandIndex++, - LOCK_STRATEGY: commandIndex++, - LOCK_STRATEGY_FAIL: commandIndex++, - LOCK_STRATEGY_WAIT: commandIndex++, - COLLECTION_ID: commandIndex++, - RESOURCE_ID: commandIndex++, - QUERY: commandIndex++, - FIELDS: commandIndex++, - LIMIT: commandIndex++, - ORDER: commandIndex++ + INTERNAL: 2, + SYSTEM: 3, + + COLLECTION_ID: 10, + RESOURCE_ID: 11, + + DATA: 20, + REPLICATED_NODES: 21, + + INFO: 30, + COUNT: 31, + GET: 32, + POST: 33, + PUT: 34, + PATCH: 35, + DELETE: 36, + + QUERY: 40, + FIELDS: 41, + LIMIT: 42, + ORDER: 43, + + NOTIFY: 50, + NOTIFY_ON: 51, + NOTIFY_OFF: 52, + NOTIFY_PATH: 53, + + LOCK: 60, + UNLOCK: 61, + LOCK_ID: 62, + LOCK_STRATEGY: 63, + LOCK_STRATEGY_FAIL: 64, + LOCK_STRATEGY_WAIT: 65, + LOCK_KEY: 66, + LOCK_ORIGIN: 67, + + COMMAND: 70, + STATUS: 71, + + RAFT_SYSTEM_PROTO: 80, + RAFT_APPEND: 81, + RAFT_BROADCAST: 82, + RAFT_SNAPSHOT: 83, + RAFT_ACTION_TYPE: 84, + + ERROR: 100, + + STATUS_OK: 120, + STATUS_BAD_REQUEST: 121, + STATUS_NOT_FOUND: 122, + STATUS_CREATED: 123, + STATUS_SERVER_ERROR: 124, + STATUS_SERVER_UNHEALTHY: 125, + STATUS_SERVER_CLOSED: 126, + STATUS_LOCKED: 127, + + CONFLICT_GET: 150, + CONFLICT_RAISE: 151, + CONFLICT_RESOLVE: 152, + CONFLICT_CLEANUP: 153, + + READY: 160 }; -if (process.env.NODE_ENV === 'development') { - Object.keys(constants).forEach(key => { - constants[key] = key; - }); -} +Object.keys(constants).forEach(key => { + constants[constants[key]] = key; +}); -module.exports = constants; +export default constants; diff --git a/lib/createCollectionMetadataUpdater.js b/lib/createCollectionMetadataUpdater.js deleted file mode 100644 index 88515e1..0000000 --- a/lib/createCollectionMetadataUpdater.js +++ /dev/null @@ -1,67 +0,0 @@ -const debarrel = require('debarrel'); - -async function upsertRecord (driver, collectionId, changes) { - const collection = (await driver.get('system.collections', { collectionId }))[0]; - if (collection) { - await driver.patch('system.collections', { - documentCount: collection.documentCount + changes.documentCountAdd - }, { - collectionId - }); - } else { - await driver.post('system.collections', { - collectionId, - documentCount: changes.documentCountAdd - }); - } -} - -function createCollectionMetadataUpdater (state) { - const cache = {}; - let processing = false; - - async function processCache (driver, cache) { - if (state.closed) { - return; - } - - if (processing) { - setTimeout(() => processCache(driver, cache), 25); - return; - } - - processing = true; - - const promises = Object.keys(cache).map(async collectionId => { - const promise = upsertRecord(driver, collectionId, cache[collectionId]).catch((error) => { - if (!state.closed) { - throw error; - } - }); - delete cache[collectionId]; - return promise; - }); - - await Promise.all(promises); - - processing = false; - } - - const watch = debarrel( - () => processCache(state.driver, cache), - { - minimumFlushTime: 25, - maximumFlushTime: 100 - } - ); - - return watch((collectionId, change) => { - const collectionMetadata = cache[collectionId] = cache[collectionId] || { - documentCountAdd: 0 - }; - - collectionMetadata.documentCountAdd = collectionMetadata.documentCountAdd + change.documentCountAdd; - }); -} - -module.exports = createCollectionMetadataUpdater; diff --git a/lib/createHandler.js b/lib/createHandler.js new file mode 100644 index 0000000..7b6afed --- /dev/null +++ b/lib/createHandler.js @@ -0,0 +1,107 @@ +import logslot from 'logslot'; +import tcpocket from 'tcpocket'; + +import c from './constants.js'; +import waitUntil from './utils/waitUntil.js'; + +const log = logslot('canhazdb.createHandler'); + +function handleError (request, response, error) { + log.error(error.message, error); + if (error.status) { + response.reply(error.status, { + [c.ERROR]: error?.error?.message || 'Unknown server error' + }); + return; + } + + response.reply(c.STATUS_SERVER_ERROR); +} + +function createHandler (context) { + const { port, tls } = context.options; + + const tcpServer = tcpocket.createServer({ port, ...tls }, async function (request, response) { + const socket = request.socket; + socket.activeRequests = socket.activeRequests + 1; + // const remoteString = request.socket.remoteAddress + ':' + request.socket.remotePort; + // logslot('canhazdb.comms').debug('received request ' + remoteString, { + // data: request.data + // }); + + const requestData = request.data ? request.json() : {}; + + const requestType = requestData[c.SYSTEM] + ? 'system' + : requestData[c.INTERNAL] ? 'internal' : 'external'; + + const controllers = await context.controllers[requestType].find(request); + + if (controllers.length === 0) { + socket.activeRequests = socket.activeRequests - 1; + response.reply(c.STATUS_NOT_FOUND); + return; + } + + const resultPromise = controllers[0].handler({ + context, + socket: request.socket, + request, + response + }); + + if (!resultPromise.catch) { + throw new Error('createHandler: controllers must return a promise'); + } + + const result = await resultPromise + .catch(error => { + handleError(request, response, error); + }) + .finally(() => { + socket.activeRequests = socket.activeRequests - 1; + }); + + return result; + }); + + tcpServer.on('connection', (socket) => { + socket.activeRequests = 0; + context.clients.push(socket); + socket.state = {}; + + context.emit('client.connected', socket); + + let waitPromise = waitUntil(() => { + return ( + context.thisNode && context.thisNode.status === 'healthy' + ); + }); + + waitPromise.then(() => { + waitPromise = false; + socket.send(c.READY); + }); + + socket.on('close', () => { + socket.activeRequests = 0; + waitPromise && waitPromise.cancel(); + + const clientIndex = context.clients.indexOf(socket); + if (clientIndex === -1) { + throw new Error('socket not found in client list'); + } + + context.clients.splice(clientIndex, 1); + context.emit('client.closed', socket); + }); + + socket.on('error', error => { + log.warn('a client disconnected from the server', { code: error.code }); + }); + }); + + return tcpServer; +} + +export default createHandler; diff --git a/lib/driver/index.js b/lib/driver/index.js new file mode 100644 index 0000000..c4752dc --- /dev/null +++ b/lib/driver/index.js @@ -0,0 +1,182 @@ +import path from 'path'; +import fs from 'fs/promises'; +import { EJDB2 } from 'node-ejdb-lite'; +import mqlToJql from 'mql-to-jql'; + +import waitUntil from '../utils/waitUntil.js'; + +const convert = mqlToJql.convert; +const createQuery = mqlToJql.createQuery; + +async function createEjdbDriver (state) { + let connections = {}; + let closed = false; + let activeQueries = 0; + + await fs.mkdir(state.options.dataDirectory, { recursive: true }); + + async function getDatabaseConnection (collectionId) { + if (connections[collectionId]) { + return connections[collectionId]; + } + const dbFile = path.join(state.options.dataDirectory, './' + collectionId + '.db'); + + connections[collectionId] = EJDB2.open(dbFile); + return connections[collectionId]; + } + + async function count (collectionId, query) { + const ejdbQuery = convert({ query }); + + const queryWithCount = { + mql: ejdbQuery.mql + ' | count', + values: ejdbQuery.values + }; + + const db = await getDatabaseConnection(collectionId); + const q = createQuery(db, collectionId, queryWithCount); + + const count = await q.scalarInt(); + + return count; + } + + async function get (collectionId, query, fields, order, limit) { + if (fields && !fields.includes('id')) { + fields.push('id'); + } + + const ejdbQuery = convert({ query, fields, order, limit }); + + const db = await getDatabaseConnection(collectionId); + const q = createQuery(db, collectionId, ejdbQuery); + const list = await q.list(); + + return list.map(item => item.json); + } + + async function post (collectionId, document) { + const db = await getDatabaseConnection(collectionId); + + const insertableRecord = { + ...document + }; + + await Promise.all(Object.keys(document).map(field => { + return db.ensureStringIndex(collectionId, '/' + field, false); + })); + + await db.put(collectionId, JSON.stringify(insertableRecord)); + + return insertableRecord; + } + + async function put (collectionId, document, query) { + const ejdbQuery = convert({ query }); + + const db = await getDatabaseConnection(collectionId); + const q = createQuery(db, collectionId, ejdbQuery); + const records = await q.list(); + + await Promise.all(Object.keys(document).map(field => { + return db.ensureStringIndex(collectionId, '/' + field, false); + })); + + const promises = records.map(async record => { + const insertableRecord = { + ...document, + id: record.json.id, + _replicatedNodes: record.json._replicatedNodes + }; + + return db.put(collectionId, JSON.stringify(insertableRecord), record.id); + }); + + await Promise.all(promises); + + return { changes: promises.length }; + } + + async function patch (collectionId, document, query) { + const ejdbQuery = convert({ query }); + + const db = await getDatabaseConnection(collectionId); + const q = createQuery(db, collectionId, ejdbQuery); + const records = await q.list(); + + await Promise.all(Object.keys(document).map(field => { + return db.ensureStringIndex(collectionId, '/' + field, false); + })); + + const promises = records.map(async record => { + const parsed = record.json; + + const insertableRecord = { + ...parsed, + ...document, + id: parsed.id + }; + + return db.patch(collectionId, JSON.stringify(insertableRecord), record.id); + }); + + await Promise.all(promises); + + return { changes: promises.length }; + } + + async function del (collectionId, query) { + const ejdbQuery = convert({ query }); + + const db = await getDatabaseConnection(collectionId); + const q = createQuery(db, collectionId, ejdbQuery); + const records = await q.list(); + const promises = records.map(async record => { + return db.del(collectionId, record.id); + }); + + await Promise.all(promises); + + return { changes: promises.length }; + } + + async function close () { + await waitUntil(() => activeQueries === 0); + + closed = true; + for (const connection in connections) { + if (connections[connection]) { + await (await connections[connection]).close(); + } + } + connections = {}; + } + + function wrapDataFunction (fn) { + return async (...args) => { + if (closed) { + throw new Error('canhazdb.driver: this instance is closed'); + } + + activeQueries = activeQueries + 1; + try { + return await fn(...args); + } finally { + activeQueries = activeQueries - 1; + } + }; + } + + return { + count: wrapDataFunction(count), + get: wrapDataFunction(get), + put: wrapDataFunction(put), + post: wrapDataFunction(post), + patch: wrapDataFunction(patch), + del: wrapDataFunction(del), + + close + }; +} + +export default createEjdbDriver; diff --git a/lib/handleInvalidRequestBody.js b/lib/handleInvalidRequestBody.js deleted file mode 100644 index 800799f..0000000 --- a/lib/handleInvalidRequestBody.js +++ /dev/null @@ -1,9 +0,0 @@ -function handleInvalidRequestBody (error) { - if (error.message.includes('Unexpected token')) { - throw Object.assign(new Error('request body not valid json'), { statusCode: 400 }); - } else { - throw Object.assign(new Error('empty request body not allowed'), { statusCode: 400 }); - } -} - -module.exports = handleInvalidRequestBody; diff --git a/lib/httpHandler.js b/lib/httpHandler.js deleted file mode 100644 index 672c547..0000000 --- a/lib/httpHandler.js +++ /dev/null @@ -1,402 +0,0 @@ -const writeResponse = require('write-response'); -const finalStream = require('final-stream'); -const uuid = require('uuid').v4; - -const packageJson = require('../package.json'); - -const validateAlphaNumericDashDot = require('../utils/validateAlphaNumericDashDot'); - -const handlePost = require('./actions/http/post'); -const handleGetAll = require('./actions/http/getAll'); -const handleGetOne = require('./actions/http/getOne'); - -function handleInvalidRequestBody (error) { - if (error.message.includes('Unexpected token')) { - throw Object.assign(new Error('request body not valid json'), { statusCode: 400 }); - } else { - throw Object.assign(new Error('empty request body not allowed'), { statusCode: 400 }); - } -} - -const { - COMMAND, - STATUS, - DATA, - DOCUMENT, - LOCK, - UNLOCK, - COUNT, - PUT, - PATCH, - DELETE, - COLLECTION_ID, - RESOURCE_ID, - QUERY -} = require('./constants'); - -function askOnAllNodes (state, data) { - return Promise.all( - state.nodes.map(node => node.connection.send(data)) - ); -} - -function accumulateChanges (responses) { - return responses.reduce((accumulator, response) => { - if (!response[DATA]) { - return accumulator; - } - - accumulator = accumulator + response[DATA].changes; - return accumulator; - }, 0); -} - -async function handleCount (state, request, response, { collectionId, url }) { - const responses = await askOnAllNodes(state, { - [COMMAND]: COUNT, - [DATA]: { - [COLLECTION_ID]: collectionId, - [QUERY]: url.searchParams.get('query') && JSON.parse(url.searchParams.get('query')) - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - if (!responses.find(response => response[STATUS] === 200)) { - writeResponse(200, { documentCount: 0 }, response); - return; - } - - const documentCount = responses - .reduce((total, response) => { - if (response[STATUS] !== 200) { - return total; - } - - return total + response[DATA].documentCount; - }, 0); - - writeResponse(200, { documentCount }, response); -} - -async function handlePutOne (state, request, response, { collectionId, resourceId }) { - const body = await finalStream(request).then(JSON.parse) - .catch(handleInvalidRequestBody); - - const responses = await askOnAllNodes(state, { - [COMMAND]: PUT, - [DATA]: { - [COLLECTION_ID]: collectionId, - [RESOURCE_ID]: resourceId, - [DOCUMENT]: body - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - const result = responses.find(response => response[STATUS] === 200); - - if (!result) { - writeResponse(404, {}, response); - return; - } - - writeResponse(200, result, response); -} - -async function handlePutAll (state, request, response, { collectionId, url }) { - const body = await finalStream(request).then(JSON.parse) - .catch(handleInvalidRequestBody); - - const responses = await askOnAllNodes(state, { - [COMMAND]: PUT, - [DATA]: { - [COLLECTION_ID]: collectionId, - [QUERY]: url.searchParams.get('query') && JSON.parse(url.searchParams.get('query')), - [DOCUMENT]: body - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - const changes = accumulateChanges(responses); - - writeResponse(200, { changes }, response); -} - -async function handlePatchOne (state, request, response, { collectionId, resourceId }) { - const body = await finalStream(request).then(JSON.parse) - .catch(handleInvalidRequestBody); - - const responses = await askOnAllNodes(state, { - [COMMAND]: PATCH, - [DATA]: { - [COLLECTION_ID]: collectionId, - [RESOURCE_ID]: resourceId, - [DOCUMENT]: body - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - const result = responses.find(response => response[STATUS] === 200); - - if (!result) { - writeResponse(404, {}, response); - return; - } - - writeResponse(200, result, response); -} - -async function handlePatchAll (state, request, response, { collectionId, url }) { - const body = await finalStream(request).then(JSON.parse) - .catch(handleInvalidRequestBody); - - const responses = await askOnAllNodes(state, { - [COMMAND]: PATCH, - [DATA]: { - [COLLECTION_ID]: collectionId, - [QUERY]: url.searchParams.get('query') && JSON.parse(url.searchParams.get('query')), - [DOCUMENT]: body - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - const changes = accumulateChanges(responses); - - writeResponse(200, { changes }, response); -} - -async function handleDeleteOne (state, request, response, { collectionId, resourceId }) { - const responses = await askOnAllNodes(state, { - [COMMAND]: DELETE, - [DATA]: { - [COLLECTION_ID]: collectionId, - [RESOURCE_ID]: resourceId - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - const changes = accumulateChanges(responses); - - if (changes === 0) { - writeResponse(404, {}, response); - return; - } - - writeResponse(200, {}, response); -} - -async function handleDeleteAll (state, request, response, { collectionId, url }) { - const responses = await askOnAllNodes(state, { - [COMMAND]: DELETE, - [DATA]: { - [COLLECTION_ID]: collectionId, - [QUERY]: url.searchParams.get('query') && JSON.parse(url.searchParams.get('query')) - } - }); - - if (responses.find(response => response[STATUS] >= 500)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - const changes = accumulateChanges(responses); - - writeResponse(200, { changes }, response); -} - -async function handleLock (state, request, response) { - const body = await finalStream(request).then(JSON.parse); - - const id = uuid(); - const responses = await askOnAllNodes(state, { - [COMMAND]: LOCK, - [DATA]: { - id, - keys: body - } - }); - - if (responses.find(response => response[STATUS] !== 200)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - writeResponse(200, { id }, response); -} - -async function handleUnlock (state, request, response, { resourceId }) { - const responses = await askOnAllNodes(state, { - [COMMAND]: UNLOCK, - [DATA]: { - id: resourceId - } - }); - - if (responses.find(response => response[STATUS] === 404)) { - writeResponse(404, {}, response); - return; - } - - if (responses.find(response => response[STATUS] !== 200)) { - writeResponse(500, responses[0][DATA], response); - return; - } - - writeResponse(200, {}, response); -} - -function handleError (request, response) { - return error => { - if (error.statusCode) { - writeResponse(error.statusCode, { error: error.message }, response); - return; - } - - console.log(error); - writeResponse(500, { error: 'unexpected server error' }, response); - }; -} - -function handleSystem (state, request, response, { url }) { - const [,, collectionId, resourceId] = url.pathname.split('/'); - - if (request.method === 'POST' && collectionId === 'locks') { - handleLock(state, request, response); - return; - } - - if (request.method === 'DELETE' && collectionId === 'locks') { - handleUnlock(state, request, response, { resourceId }); - return; - } - - response.writeHead(404); - response.end(); -} - -function handleExternal (state, request, response) { - const url = new URL(request.url, 'http://localhost'); - - if (request.url.startsWith('/_')) { - handleSystem(state, request, response, { url }); - return; - } - - const [, collectionId, resourceId] = url.pathname.split('/'); - - if (collectionId && !validateAlphaNumericDashDot(collectionId)) { - writeResponse(422, { - errors: ['collectionId can only contain a-z, A-Z, 0-9, dashs or dots'] - }, response); - return; - } - - const unhealthyNodes = state.nodes.filter(node => node.status !== 'healthy'); - if (unhealthyNodes.length > 0) { - writeResponse(503, { - errors: ['a node in the cluster is unhealthy, therefore the database is down'] - }, response); - return; - } - - if (request.method === 'GET' && url.pathname === '/') { - writeResponse(200, { - status: 200, - name: packageJson.name, - version: packageJson.version, - info: 'https://canhazdb.com' - }, response); - return; - } else if (url.pathname === '/') { - writeResponse(405, { error: 'method not allowed' }, response); - return; - } - - if (request.method === 'GET' && resourceId) { - handleGetOne(state, request, response, { collectionId, resourceId, url }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'GET' && url.searchParams.get('count') && !resourceId) { - handleCount(state, request, response, { collectionId, url }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'GET' && !resourceId) { - handleGetAll(state, request, response, { collectionId, url }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'POST') { - handlePost(state, request, response, { collectionId, resourceId }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'PUT' && resourceId) { - handlePutOne(state, request, response, { collectionId, resourceId }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'PUT' && !resourceId) { - handlePutAll(state, request, response, { collectionId, url }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'PATCH' && resourceId) { - handlePatchOne(state, request, response, { collectionId, resourceId }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'PATCH' && !resourceId) { - handlePatchAll(state, request, response, { collectionId, url }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'DELETE' && resourceId) { - handleDeleteOne(state, request, response, { collectionId, resourceId }) - .catch(handleError(request, response)); - return; - } - - if (request.method === 'DELETE' && !resourceId) { - handleDeleteAll(state, request, response, { collectionId, url }) - .catch(handleError(request, response)); - return; - } - - response.writeHead(404); - response.end(); -} - -module.exports = handleExternal; diff --git a/lib/index.js b/lib/index.js index e38b779..07bb998 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,267 +1,228 @@ -const path = require('path'); -const fs = require('fs'); -const os = require('os'); -const dns = require('dns').promises; - -const chalk = require('chalk'); -const tcpocket = require('tcpocket'); -const enableDestroy = require('server-destroy'); -const getPort = require('get-port'); - -const httpHandler = require('./httpHandler'); -const tcpHandler = require('./tcpHandler'); -const wsHandler = require('./wsHandler'); - -const { COMMAND, INFO, DATA } = require('./constants'); - -async function prepareOptions (rawOptions) { - const options = { - ...rawOptions, - log: (rawOptions.logger || console.log), - join: rawOptions.join || [], - single: rawOptions.single - }; - - options.port = options.port ? parseInt(options.port) : await getPort(); - options.queryPort = options.queryPort ? parseInt(options.queryPort) : await getPort(); - - if (rawOptions.joinFromDns) { - const dnsLookupResults = await dns.lookup(rawOptions.joinFromDns, { all: true }); - console.log('joining from dns:', dnsLookupResults); - options.join = dnsLookupResults.map(item => `${item.address}:${options.port}`); - } - - if (options.join.length > 0 && options.single) { - throw new Error('Can not start canhazdb in both single mode and attempt to join other nodes.'); - } - - if (!options.join || options.join.length === 0) { - if (options.single) { - options.join = [`${rawOptions.host}:${options.port}`]; - } else { - throw new Error('You must start canhazdb in --single mode or join it to another node and itself'); - } +import logslot from 'logslot'; +import EventEmitter from 'events'; + +import prepareOptions from './prepareOptions.js'; +import createHandler from './createHandler.js'; +import driver from './driver/index.js'; +import join from './utils/join.js'; +import waitUntil from './utils/waitUntil.js'; + +import controllersModule from './modules/controllers/index.js'; +import collectionsModule from './modules/collections/index.js'; +import conflictsModule from './modules/conflicts/index.js'; +import crudModule from './modules/crud/index.js'; +import httpModule from './modules/http/index.js'; +import lockModule from './modules/lock/index.js'; +import notifyModule from './modules/notify/index.js'; +import raftModule from './modules/raft/index.js'; +import webModule from './modules/web/index.js'; + +import c from './constants.js'; + +const log = logslot('canhazdb.server'); + +async function persistNode (context, node) { + if (context.closed) { + return; } - if (rawOptions.tlsCa || rawOptions.tlsCert || rawOptions.tlsKey) { - if (!rawOptions.tlsCa || !rawOptions.tlsCert || !rawOptions.tlsKey) { - console.log(chalk.red('You must specifiy either all [tls-key, tls-cert, tls-ca] or none of them')); - return; - } + const existingRecords = await context.driver.get('system.nodes', { + name: node.name + }); - options.tls = { - key: fs.readFileSync(rawOptions.tlsKey), - cert: fs.readFileSync(rawOptions.tlsCert), - ca: [fs.readFileSync(rawOptions.tlsCa)], - requestCert: true - }; + if (existingRecords.length === 0) { + process.context = context; + await context.driver.post('system.nodes', { + name: node.name, + host: node.host, + port: node.port + }); } - options.driver = process.env.CANHAZDB_DRIVER || rawOptions.driver || 'canhazdb-driver-ejdb'; - options.nodeName = options.nodeName || process.env.CANHAZDB_NODE_NAME || os.hostname(); - options.dataDirectory = rawOptions.dataDirectory - ? path.resolve(rawOptions.dataDirectory, options.nodeName) - : path.resolve(process.cwd(), './canhazdata', options.nodeName); - - return options; + node.persisted = true; } -async function makeConnection (scope, host, port, tls, node) { - if (scope.closed) { - return; - } - - if (node.connection) { - // console.log('Aborting connection to ', host, port, 'as already connected'); - return; - } - - node.status = 'unhealthy'; - - node.reconnect = () => { - if (scope.closed) { - return; +async function canhazdb (rawOptions) { + const options = await prepareOptions(rawOptions); + log.debug('parsed options', options); + + const context = Object.assign( + new EventEmitter(), + { + closed: false, + clients: [], + settings: Object.assign({ + infoInterval: 250, + conflictSyncInterval: 100, + conflictCleanupInterval: 30000, + replicas: 3 + }, rawOptions.settings), + info: { + generators: [] + }, + nodes: [], + join, + options } + ); + + const activeModules = await Promise.all([ + controllersModule(context), + notifyModule(context), + collectionsModule(context), + conflictsModule(context), + lockModule(context), + crudModule(context), + httpModule(context), + webModule(context), + raftModule(context) + ]); + + context.driver = await driver(context); + + const tcpServer = createHandler(context); + tcpServer.open(); - clearTimeout(node.reconnectionTimer); + context.options.join.forEach(item => { + const [host, port] = item.split(':'); + join(context, host, port); + }); - node.reconnectionTimer = setTimeout(() => { - delete node.reconnectionTimer; - makeConnection(scope, host, port, tls, node); - }, 1000); - }; + const persistedNodes = await context.driver.get('system.nodes'); + persistedNodes.forEach(node => { + join(context, node.host, node.port); + }); - function handleError (error) { - if (['CLOSED', 'ECONNREFUSED', 'EHOSTUNREACH', 'ECONNRESET'].includes(error.code)) { - node.status = 'unhealthy'; - delete node.connection; - node.reconnect(); + async function syncNodesInfo () { + if (context.closed) { return; } - throw error; - } + await Promise.all( + context.nodes.map(async node => { + if (!node.client) { + return; + } + const result = await node.client.send(c.INFO, { + [c.DATA]: { + nodes: context.nodes.map(node => ({ + host: node.host, + port: node.port + })) + }, + [c.SYSTEM]: true + }).catch(error => { + log.warn('syncNodesInfo: client disconnected', { error: error.code }); + return null; + }); - try { - const servername = scope.options.joinFromDns; + if (!result || result.command !== c.STATUS_OK) { + return; + } - const client = await tcpocket.createClient({ host, port, servername, ...tls }); - scope.clients.push(client); - node.status = 'healthy'; + const resultData = result.json(); - client.on('message', data => { - scope.handleMessage && scope.handleMessage(data); - }); + node.info = resultData[c.DATA]; + node.name = resultData[c.DATA].nodeName; + context.nodes[node.name] = node; + node.status = resultData[c.DATA].status; - client.on('close', () => { - handleError(Object.assign(new Error('client closed'), { code: 'CLOSED' })); - }); + if (node.name) { + node.online = true; + } - client.on('error', handleError); + persistNode(context, node); - node.connection = client; + context.thisNode = context.nodes.find(node => node.name === context.options.nodeName); + context.emit('node.infoReceived', node); + }) + ); - return client; - } catch (error) { - handleError(error); + context.syncNodesInfoTimer = setTimeout(syncNodesInfo, context.settings.infoInterval); } -} + syncNodesInfo(); -async function join (scope, { host, port }, alreadyRecursed) { - port = parseInt(port); - - if (scope.nodes.find(node => node.host === host && node.port === port)) { - return; - } - - if (!scope.options.single) { - scope.log(` joining ${host}:${port}`); - } - - const newNode = { - host, - port - }; - scope.nodes.push(newNode); - - await makeConnection(scope, host, port, scope.options.tls, newNode); - - try { - newNode.info = await newNode.connection.send({ - [COMMAND]: INFO, - [DATA]: { - nodes: scope.nodes.map(node => ({ host: node.host, port: node.port })) - } - }); - - if (!alreadyRecursed) { - const otherJoins = newNode.info[DATA].nodes.map(node => { - return join(scope, { ...node }, true); - }); - - await Promise.all(otherJoins); + context.sendToAllNodes = (context, command, data) => { + if (!context.nodes) { + return []; } - } catch (error) { - console.log('could not connect to new node', newNode.host, newNode.port); - console.log(' ', error.message); - } -} - -async function canhazdb (rawOptions) { - const options = await prepareOptions(rawOptions); - - const scope = { - options, - log: options.log, - - url: `${options.tls ? 'https' : 'http'}://` + options.host + ':' + options.queryPort, - wsUrl: `${options.tls ? 'wss' : 'ws'}://` + options.host + ':' + options.queryPort, - - host: options.host, - port: options.port, - queryPort: options.queryPort, - clients: [], - nodes: [], - - data: {} + return Promise.all( + context.nodes + .map(node => { + if (!node.connected) { + return { + command: c.STATUS_SERVER_ERROR, + error: new Error('client not connected'), + node + }; + } + + return node.client.send(command, data) + .then(result => { + return { + ...result, + node + }; + }) + .catch(error => { + log.warn(error); + return { + command: c.STATUS_SERVER_ERROR, + node + }; + }); + }) + ); }; - scope.driver = require(options.driver)(scope); + context.close = async function () { + context.emit('closed'); + context.closed = true; - const tcpServer = tcpHandler(scope, options.port, options.tls); - tcpServer.open(); + context.locks.cancel( + Object.assign(new Error('server was closed'), { status: c.STATUS_SERVER_CLOSED }) + ); - let server; - if (options.tls) { - server = require('https').createServer(options.tls, httpHandler.bind(null, scope)); - } else { - server = require('http').createServer(httpHandler.bind(null, scope)); - } - enableDestroy(server); + const activeRequestsWait = waitUntil(() => { + const activeRequests = context.clients.reduce((total, client) => { + return total + client.activeRequests; + }, 0); - const wss = wsHandler(server, scope, options); - - options.join.forEach(async item => { - const [host, port] = item.split(':'); - await join(scope, { host, port }); - }); - - if (options.joinFromDns) { - async function dnsLookups () { - if (scope.closed) { - return; - } - - const dnsLookupResults = await dns.lookup(rawOptions.joinFromDns, { all: true }); - dnsLookupResults.forEach(async item => { - join(scope, { host: item.address, port: options.port }); - }); - } - setInterval(dnsLookups, 5000); - } - - scope.join = join.bind(null, scope); - - const serverReturn = { - ...scope, - - open: async () => { - delete scope.closed; - const openPromise = new Promise((resolve) => { - server.once('listening', async () => { - scope.nodes.forEach(node => node.reconnect()); + return activeRequests === 0; + }); - resolve(serverReturn); - }); - }); - tcpServer.close(); - tcpServer.open(); - scope.driver.open && scope.driver.open(); - server.listen(options.queryPort); + // #72 activeRequests is sometimes wrong when closing server + // https://github.com/canhazdb/server/issues/72 + const workaroundTimer = setTimeout(() => { + console.log('Issue 72: Workaround was required as activeRequests did not reset in time!'); + activeRequestsWait.cancel(); + }, 500); + await activeRequestsWait; + clearTimeout(workaroundTimer); - return openPromise; - }, + await new Promise(resolve => tcpServer.close(resolve)); - close: async () => { - scope.closed = true; + clearTimeout(context.syncNodesInfoTimer); - scope.locks.cancel(); + await Promise.all(context.nodes.map(node => { + return node.close(); + })); - await Promise.all(scope.clients.map(node => { - return node.close(); - })); + await Promise.all( + activeModules.filter(item => !!item).map(item => item.cleanup && item.cleanup()) + ); - server.destroy(); - wss.close(); - tcpServer.close(); - scope.driver.close(); - } + await context.driver.close(); }; - await serverReturn.open(); + context.clientConfig = { + host: context.options.host, + port: context.options.port, + ...context.options.tls + }; - return serverReturn; + return context; } -module.exports = canhazdb; +export default canhazdb; diff --git a/lib/modules/collections/documentCountCollector.js b/lib/modules/collections/documentCountCollector.js new file mode 100644 index 0000000..d936aac --- /dev/null +++ b/lib/modules/collections/documentCountCollector.js @@ -0,0 +1,48 @@ +import logslot from 'logslot'; +import debarrel from 'debarrel'; + +const log = logslot('canhazdb.documentCountCollector'); + +function documentCountCollector (handler) { + const cache = {}; + let processing = false; + + async function processCache () { + if (processing) { + setTimeout(() => processCache(), 25); + return; + } + + processing = true; + + try { + await handler(cache); + } catch (error) { + log.error('could not update documentCount', error); + } finally { + processing = false; + } + } + + const watch = debarrel( + () => processCache(), + { + minimumFlushTime: 25, + maximumFlushTime: 100 + } + ); + + const add = watch((collectionId, count) => { + const collectionMetadata = cache[collectionId] = cache[collectionId] || { + documentCountAdd: 0 + }; + + collectionMetadata.documentCountAdd = collectionMetadata.documentCountAdd + count; + }); + + return { + add + }; +} + +export default documentCountCollector; diff --git a/lib/modules/collections/index.js b/lib/modules/collections/index.js new file mode 100644 index 0000000..93c35bc --- /dev/null +++ b/lib/modules/collections/index.js @@ -0,0 +1,96 @@ +import logslot from 'logslot'; +import documentCountCollector from './documentCountCollector.js'; +import systemNodesController from './systemNodesController.js'; +import insertDefaultDocument from '../../utils/insertDefaultDocument.js'; +import c from '../../constants.js'; + +const log = logslot('canhazdb.collections'); +async function updateCollectionByAmount (context, collectionId, cachedItem) { + const collectionsQuery = await context.thisNode.client.send(c.GET, { + [c.COLLECTION_ID]: 'system.collections', + [c.QUERY]: { collectionId: collectionId } + }); + + if (collectionsQuery.command !== c.STATUS_OK) { + log.warn('could not updateCollectionByAmount', { + command: collectionsQuery.command, + data: collectionsQuery.data && collectionsQuery.data.toString() + }); + return; + } + + const collection = collectionsQuery.json()[c.DATA][0]; + + if (collection) { + await context.thisNode.client.send(c.PATCH, { + [c.COLLECTION_ID]: 'system.collections', + [c.QUERY]: { collectionId: collectionId }, + [c.DATA]: { + documentCount: collection.documentCount + cachedItem.documentCountAdd + } + }); + } else { + await insertDefaultDocument(context, 'system.collections', { + id: collectionId, + collectionId: collectionId, + documentCount: cachedItem.documentCountAdd + }); + } +} + +function collectionsModule (context) { + context.controllers.external.add({ + command: c.GET, + priority: 10, + conditions: [ + (request) => { + const data = request.json(); + return data[c.COLLECTION_ID] === 'system.nodes'; + } + ], + handler: systemNodesController + }); + + insertDefaultDocument(context, 'system.collections', { + id: 'system.collections', + collectionId: 'system.collections', + documentCount: 0 + }); + + insertDefaultDocument(context, 'system.collections', { + id: 'system.nodes', + collectionId: 'system.nodes', + documentCount: 0 + }); + + const collector = documentCountCollector(async function (cache) { + if (context.closed) { + return; + } + + const promises = Object.keys(cache).map(async collectionId => { + const promise = updateCollectionByAmount(context, collectionId, cache[collectionId]) + .catch((error) => { + if (!context.closed) { + throw error; + } + }); + delete cache[collectionId]; + return promise; + }); + + await Promise.all(promises); + }); + + context.on('notify', (notifyPath, method, collectionId) => { + if (method === 'POST') { + collector.add(collectionId, 1); + } + + if (method === 'DELETE') { + collector.add(collectionId, -1); + } + }); +} + +export default collectionsModule; diff --git a/lib/modules/collections/systemNodesController.js b/lib/modules/collections/systemNodesController.js new file mode 100644 index 0000000..f4020ad --- /dev/null +++ b/lib/modules/collections/systemNodesController.js @@ -0,0 +1,14 @@ +import c from '../../constants.js'; + +async function systemNodesController ({ context, socket, request, response }) { + response.reply(c.STATUS_OK, { + [c.DATA]: context.nodes.map(node => { + return { + ...node, + client: undefined + }; + }) + }); +} + +export default systemNodesController; diff --git a/lib/modules/conflicts/index.js b/lib/modules/conflicts/index.js new file mode 100644 index 0000000..55ef672 --- /dev/null +++ b/lib/modules/conflicts/index.js @@ -0,0 +1,228 @@ +import logslot from 'logslot'; +import c from '../../constants.js'; +import onlyOnce from '../../utils/onlyOnce.js'; +const log = logslot('canhazdb.conflicts'); + +async function resolveConflict (context, conflict) { + try { + const result = await context.thisNode.client + .send(c[conflict.method], conflict.request); + + if (![c.STATUS_CREATED, c.STATUS_OK].includes(result.command)) { + throw Object.assign(new Error('conflict could not resolve'), { result }); + } + + return context.sendToAllNodes(context, c.CONFLICT_RESOLVE, { + [c.INTERNAL]: true, + [c.DATA]: conflict + }); + } catch (error) { + log.error('could not resolve conflict', error); + } +} + +const syncServerHealth = onlyOnce( + async function syncServerHealth (context) { + const ownConflicts = context.conflicts.items + .filter(conflict => !conflict.resolved && conflict.nodeName === context.thisNode.name); + + if (ownConflicts.length > 0) { + context.thisNode.status = 'unhealthy'; + + await Promise.all( + ownConflicts + .filter(conflict => !conflict.resolved) + .map(resolveConflict.bind(null, context)) + ); + + return; + } + + const totalNodes = context.nodes.length; + const onlineNodes = context.nodes.filter(node => node.online).length; + const percentageOnline = parseFloat((onlineNodes / totalNodes).toFixed(2)); + + if (percentageOnline > 0.5) { + context.thisNode.status = 'healthy'; + } else { + log.warn('less than 51% of the cluster is online', { onlineNodes, totalNodes, percentageOnline }); + context.thisNode.status = 'unhealthy'; + } + } +); + +async function isConflictResolvedOnAllNodes (context, conflict) { + const nodeResults = await context.sendToAllNodes(context, c.CONFLICT_GET, { + [c.INTERNAL]: true, + [c.RESOURCE_ID]: conflict.id + }); + + const allResolved = nodeResults.every(response => { + if (response.command !== c.STATUS_OK) { + return false; + } + + const result = response.json(); + return result[c.DATA].resolved; + }); + + return allResolved; +} + +const cleanupResolvedConflicts = onlyOnce( + async function cleanupResolvedConflicts (context) { + const resolvedConflicts = context.conflicts.items + .filter(conflict => conflict.resolved && conflict.nodeName === context.thisNode.name); + + await Promise.all( + resolvedConflicts.map(async conflict => { + const fullyResolved = await isConflictResolvedOnAllNodes(context, conflict); + if (fullyResolved) { + context.sendToAllNodes(context, c.CONFLICT_CLEANUP, { + [c.INTERNAL]: true, + [c.DATA]: conflict + }); + } + }) + ); + } +); + +function upsertConflict (context, data) { + const existing = context.conflicts.items + .find(item => item.id === data.id); + + if (existing) { + return; + } + + context.conflicts.items.push(data); +} + +async function conflictRaiseHandler ({ context, socket, request, response }) { + const requestData = request.json(); + const data = requestData[c.DATA]; + + upsertConflict(context, data); +} + +async function conflictResolveHandler ({ context, socket, request, response }) { + const requestData = request.json(); + const data = requestData[c.DATA]; + + const existing = context.conflicts.items + .find(item => item.id === data.id); + + if (!existing) { + return; + } + + existing.resolved = true; + response.reply(c.STATUS_OK); +} + +async function conflictCleanupHandler ({ context, socket, request, response }) { + const requestData = request.json(); + const data = requestData[c.DATA]; + + const existingIndex = context.conflicts.items + .findIndex(item => item.id === data.id); + + if (existingIndex === -1) { + return; + } + + context.conflicts.items.splice(existingIndex, 1); + + response.reply(c.STATUS_OK); +} + +async function conflictGetHandler ({ context, socket, request, response }) { + const requestData = request.json(); + const resourceId = requestData[c.RESOURCE_ID]; + + if (resourceId) { + const conflict = context.conflicts.items.find(item => item.id === resourceId); + + if (!conflict) { + response.reply(c.STATUS_NOT_FOUND); + return; + } + + response.reply(c.STATUS_OK, { + [c.DATA]: conflict + }); + + return; + } + + response.reply(c.STATUS_OK, { + [c.DATA]: context.conflicts.items + }); +} + +function conflictsModule (context) { + context.conflicts = { + items: [] + }; + + context.controllers.internal.add({ + command: c.CONFLICT_GET, + handler: conflictGetHandler + }); + + context.controllers.internal.add({ + command: c.CONFLICT_RAISE, + handler: conflictRaiseHandler + }); + + context.controllers.internal.add({ + command: c.CONFLICT_RESOLVE, + handler: conflictResolveHandler + }); + + context.controllers.internal.add({ + command: c.CONFLICT_CLEANUP, + handler: conflictCleanupHandler + }); + + context.on('node.connected', async function (node) { + const conflicts = await node.client.send(c.CONFLICT_GET, { + [c.INTERNAL]: true + }); + + conflicts.json()[c.DATA].forEach(conflictData => { + upsertConflict(context, conflictData); + }); + }); + + context.on('conflict', async function (data) { + return context.sendToAllNodes(context, c.CONFLICT_RAISE, { + [c.INTERNAL]: true, + [c.DATA]: data + }); + }); + + const syncTimer = setInterval(() => { + if (!context?.thisNode?.client) { + return; + } + syncServerHealth(context); + }, context.settings.conflictSyncInterval); + + const cleanupTimer = setInterval(() => { + if (!context?.thisNode?.client) { + return; + } + cleanupResolvedConflicts(context); + }, context.settings.conflictCleanupInterval); + + return { + cleanup: () => { + clearInterval(syncTimer); + clearInterval(cleanupTimer); + } + }; +} + +export default conflictsModule; diff --git a/lib/modules/controllers/createControllerStore.js b/lib/modules/controllers/createControllerStore.js new file mode 100644 index 0000000..d9b51db --- /dev/null +++ b/lib/modules/controllers/createControllerStore.js @@ -0,0 +1,42 @@ +function createControllerStore () { + const data = {}; + + function add ({ command, priority = 0, conditions, handler }) { + if (!data[command]) { + data[command] = []; + } + + data[command].push({ priority, conditions, handler }); + + data[command] = data[command].sort((a, b) => { + return a.priority < b.priority ? 1 : -1; + }); + } + + function find (request) { + if (!data[request.command]) { + return []; + } + + const results = data[request.command].filter(controller => { + if (!controller.conditions) { + return true; + } + + const conditionResults = controller.conditions + .map(condition => condition(request)); + + return conditionResults.every(result => result === true); + }); + + return results; + } + + return { + data, + find, + add + }; +} + +export default createControllerStore; diff --git a/lib/modules/controllers/index.js b/lib/modules/controllers/index.js new file mode 100644 index 0000000..f16ee34 --- /dev/null +++ b/lib/modules/controllers/index.js @@ -0,0 +1,34 @@ +import c from '../../constants.js'; + +import createControllerStore from './createControllerStore.js'; + +import internalInfo from './infoController.js'; + +function rejectWhenUnhealthy (fn) { + return async (options) => { + const { context, response } = options; + if (context.thisNode.status === 'unhealthy') { + response.reply(c.STATUS_SERVER_UNHEALTHY); + return; + } + + return fn(options); + }; +} + +function controllersModule (context) { + context.controllers = { + system: createControllerStore(), + internal: createControllerStore(), + external: createControllerStore(), + + rejectWhenUnhealthy + }; + + context.controllers.system.add({ + command: c.INFO, + handler: internalInfo + }); +} + +export default controllersModule; diff --git a/lib/modules/controllers/infoController.js b/lib/modules/controllers/infoController.js new file mode 100644 index 0000000..d7161ef --- /dev/null +++ b/lib/modules/controllers/infoController.js @@ -0,0 +1,31 @@ +import c from '../../constants.js'; + +async function infoController ({ context, socket, request, response }) { + const data = context.info.generators.reduce((data, generator) => { + return { + ...data, + ...generator() + }; + }, {}); + + response.reply(c.STATUS_OK, { + [c.DATA]: { + nodeName: context.options.nodeName, + status: context?.thisNode?.status || 'unhealthy', + nodes: context.nodes.map(node => ({ + host: node.host, + port: node.port + })), + ...data + } + }); + + const requestData = request.json(); + if (requestData[c.DATA] && requestData[c.DATA].nodes) { + requestData[c.DATA].nodes.forEach(node => { + context.join(context, node.host, node.port); + }); + } +} + +export default infoController; diff --git a/lib/modules/crud/controllers/external/count.js b/lib/modules/crud/controllers/external/count.js new file mode 100644 index 0000000..3b5a84d --- /dev/null +++ b/lib/modules/crud/controllers/external/count.js @@ -0,0 +1,34 @@ +import logslot from 'logslot'; + +import c from '../../../../constants.js'; + +const log = logslot('canhazdb.controllers.external.count'); + +async function countController ({ context, socket, request, response }) { + const requestData = request.json(); + + const results = await Promise.all( + context.nodes + .filter(node => node.connected) + .map(node => { + return node.client.send(c.COUNT, { + [c.COLLECTION_ID]: requestData[c.COLLECTION_ID], + [c.ORDER]: requestData[c.ORDER], + [c.LIMIT]: requestData[c.LIMIT], + [c.INTERNAL]: true + }, false) + .then(result => { + return result.json()[c.DATA]; + }) + .catch(error => { + log.warn('node send failed', error); + }); + }) + ); + + response.reply(c.STATUS_OK, { + [c.DATA]: results.reduce((a, b) => a + b) + }); +} + +export default countController; diff --git a/lib/modules/crud/controllers/external/delete.js b/lib/modules/crud/controllers/external/delete.js new file mode 100644 index 0000000..c5c2e37 --- /dev/null +++ b/lib/modules/crud/controllers/external/delete.js @@ -0,0 +1,56 @@ +import { v4 as uuid } from 'uuid'; + +import c from '../../../../constants.js'; +import validateRequestData from '../../../../utils/validateRequestData.js'; + +async function deleteController ({ context, socket, request, response }) { + const requestData = request.json(); + + await validateRequestData(context, requestData); + + const collectionId = requestData[c.COLLECTION_ID]; + + const internalRequestData = { + [c.COLLECTION_ID]: collectionId, + [c.QUERY]: requestData[c.QUERY], + [c.DATA]: requestData[c.DATA], + [c.INTERNAL]: true + }; + + const results = await context.sendToAllNodes(context, c.DELETE, internalRequestData); + + const errors = results.filter(result => { + return !result || result.command !== c.STATUS_OK || result.error; + }); + + errors.forEach(error => { + context.emit('conflict', { + id: uuid(), + nodeName: error.node.name, + method: 'DELETE', + request: internalRequestData, + collectionId, + documentId: document.id, + document, + timestamp: new Date() + }); + }); + + const effectedDocumentIds = results.reduce((ids, result) => { + if (result.command === c.STATUS_OK) { + return ids.concat(result.json()[c.DATA]); + } + + return ids; + }, []); + + effectedDocumentIds.forEach(documentId => { + context.emit('notify', `DELETE:/${collectionId}/${documentId}`, 'DELETE', collectionId, documentId, request); + }); + + response.reply(c.STATUS_OK, { + [c.DATA]: effectedDocumentIds + }); +} + +export default deleteController; diff --git a/lib/modules/crud/controllers/external/get.js b/lib/modules/crud/controllers/external/get.js new file mode 100644 index 0000000..4e35180 --- /dev/null +++ b/lib/modules/crud/controllers/external/get.js @@ -0,0 +1,71 @@ +import logslot from 'logslot'; + +import c from '../../../../constants.js'; +import orderByFields from '../../../../utils/orderByFields.js'; +import calculateAllowedErrorCount from '../../../../utils/calculateAllowedErrorCount.js'; +import validateRequestData from '../../../../utils/validateRequestData.js'; + +const log = logslot('canhazdb.controllers.external.get'); + +async function getController ({ context, socket, request, response }) { + const requestData = request.json(); + + await validateRequestData(context, requestData); + + const results = await Promise.all( + context.nodes + .filter(node => node.connected) + .map(node => { + return node.client.send(c.GET, { + [c.COLLECTION_ID]: requestData[c.COLLECTION_ID], + [c.QUERY]: requestData[c.QUERY], + [c.FIELDS]: requestData[c.FIELDS], + [c.ORDER]: requestData[c.ORDER], + [c.LIMIT]: requestData[c.LIMIT], + [c.INTERNAL]: true + }).catch(error => { + log.warn(error); + return { + command: c.STATUS_SERVER_ERROR + }; + }); + }) + ); + + const errors = results.filter(result => { + return result && result.command !== c.STATUS_OK; + }); + + const maximumErrorCount = calculateAllowedErrorCount(context.settings.replicas, context.nodes.length); + + if (errors.length > maximumErrorCount) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: 'Not enough nodes responded successfully' + }); + return; + } + + let documents = results + .filter(result => result.command === c.STATUS_OK) + .flatMap(result => result && result.json()[c.DATA]) + .map(item => { + delete item._replicatedNodes; + return item; + }); + + const orders = requestData[c.ORDER] || []; + orders.forEach(order => { + orderByFields(order, documents); + }); + + const limit = requestData[c.LIMIT]; + if (limit) { + documents = documents.slice(0, limit); + } + + response.reply(c.STATUS_OK, { + [c.DATA]: documents + }); +} + +export default getController; diff --git a/lib/modules/crud/controllers/external/patch.js b/lib/modules/crud/controllers/external/patch.js new file mode 100644 index 0000000..ffff913 --- /dev/null +++ b/lib/modules/crud/controllers/external/patch.js @@ -0,0 +1,58 @@ +import { v4 as uuid } from 'uuid'; + +import c from '../../../../constants.js'; +import validateRequestData from '../../../../utils/validateRequestData.js'; + +async function patchController ({ context, socket, request, response }) { + const requestData = request.json(); + + await validateRequestData(context, requestData); + + const collectionId = requestData[c.COLLECTION_ID]; + + const document = requestData[c.DATA]; + + const internalRequestData = { + [c.COLLECTION_ID]: collectionId, + [c.QUERY]: requestData[c.QUERY], + [c.DATA]: document, + [c.INTERNAL]: true + }; + + const results = await context.sendToAllNodes(context, c.PATCH, internalRequestData); + + const errors = results.filter(result => { + return !result || result.command !== c.STATUS_OK || result.error; + }); + + errors.forEach(error => { + context.emit('conflict', { + id: uuid(), + nodeName: error.node.name, + method: 'PATCH', + request: internalRequestData, + collectionId, + documentId: document.id, + document, + timestamp: new Date() + }); + }); + + const effectedDocumentIds = results.reduce((ids, result) => { + if (result.command === c.STATUS_OK) { + return ids.concat(result.json()[c.DATA]); + } + + return ids; + }, []); + + effectedDocumentIds.forEach(documentId => { + context.emit('notify', `PATCH:/${collectionId}/${documentId}`, 'PATCH', collectionId, documentId, request); + }); + + response.reply(c.STATUS_OK, { + [c.DATA]: effectedDocumentIds + }); +} + +export default patchController; diff --git a/lib/modules/crud/controllers/external/post.js b/lib/modules/crud/controllers/external/post.js new file mode 100644 index 0000000..631a1bc --- /dev/null +++ b/lib/modules/crud/controllers/external/post.js @@ -0,0 +1,63 @@ +import { v4 as uuid } from 'uuid'; + +import c from '../../../../constants.js'; +import selectRandomItemsFromArray from '../../../../utils/selectRandomItemsFromArray.js'; + +async function postController ({ context, socket, request, response }) { + const nodes = selectRandomItemsFromArray( + context.nodes, + Math.min(context.settings.replicas, context.nodes.length) + ); + + const requestData = request.json(); + + const document = { + id: uuid(), + ...requestData[c.DATA] + }; + + const collectionId = requestData[c.COLLECTION_ID]; + + const internalRequestData = { + [c.LOCK_ID]: requestData[c.LOCK_ID], + [c.LOCK_STRATEGY]: requestData[c.LOCK_STRATEGY], + [c.COLLECTION_ID]: collectionId, + [c.REPLICATED_NODES]: nodes.map(node => node.name), + [c.DATA]: document, + [c.INTERNAL]: true + }; + + const results = await context.sendToAllNodes(context, c.POST, internalRequestData); + + const errors = results.filter(result => { + return !result || result.command !== c.STATUS_CREATED || result.error; + }); + + errors.forEach(error => { + context.emit('conflict', { + id: uuid(), + nodeName: error.node.name, + method: 'POST', + request: internalRequestData, + collectionId, + documentId: document.id, + document, + timestamp: new Date() + }); + }); + + if (results.length - errors.length === 0) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: 'No node in the cluster responded successfully' + }); + return; + } + + context.emit('notify', `POST:/${collectionId}/${document.id}`, 'POST', collectionId, document.id, request); + + response.reply(c.STATUS_CREATED, { + [c.DATA]: document + }); +} + +export default postController; diff --git a/lib/modules/crud/controllers/external/put.js b/lib/modules/crud/controllers/external/put.js new file mode 100644 index 0000000..0916324 --- /dev/null +++ b/lib/modules/crud/controllers/external/put.js @@ -0,0 +1,65 @@ +import { v4 as uuid } from 'uuid'; + +import c from '../../../../constants.js'; +import validateRequestData from '../../../../utils/validateRequestData.js'; + +async function putController ({ context, socket, request, response }) { + const requestData = request.json(); + + await validateRequestData(context, requestData); + + const collectionId = requestData[c.COLLECTION_ID]; + + const document = requestData[c.DATA]; + + const internalRequestData = { + [c.COLLECTION_ID]: collectionId, + [c.QUERY]: requestData[c.QUERY], + [c.DATA]: document, + [c.INTERNAL]: true + }; + + const results = await context.sendToAllNodes(context, c.PUT, internalRequestData); + + const errors = results.filter(result => { + return !result || result.command !== c.STATUS_OK || result.error; + }); + + errors.forEach(error => { + context.emit('conflict', { + id: uuid(), + nodeName: error.node.name, + method: 'PUT', + request: internalRequestData, + collectionId, + documentId: document.id, + document, + timestamp: new Date() + }); + }); + + if (results.length - errors.length === 0) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: 'No node in the cluster responded successfully' + }); + return; + } + + const effectedDocumentIds = results.reduce((ids, result) => { + if (result.command === c.STATUS_OK) { + return ids.concat(result.json()[c.DATA]); + } + + return ids; + }, []); + + effectedDocumentIds.forEach(documentId => { + context.emit('notify', `PUT:/${collectionId}/${documentId}`, 'PUT', collectionId, documentId, request); + }); + + response.reply(c.STATUS_OK, { + [c.DATA]: effectedDocumentIds + }); +} + +export default putController; diff --git a/lib/modules/crud/controllers/internal/count.js b/lib/modules/crud/controllers/internal/count.js new file mode 100644 index 0000000..4b39e53 --- /dev/null +++ b/lib/modules/crud/controllers/internal/count.js @@ -0,0 +1,40 @@ +import c from '../../../../constants.js'; + +// Logic: Only return the document if we are +// the first replica that's available +function isFirstConnectedReplica (connectedNodes, nodeName) { + return document => { + const availableReplicatedNodes = document._replicatedNodes.filter(nodeName => { + return !!connectedNodes.find(cnode => cnode.name === nodeName); + }); + + if (availableReplicatedNodes[0] === nodeName) { + return true; + } + + return false; + }; +} + +async function internalCountController ({ context, socket, request, response }) { + const requestData = request.json(); + + const collectionId = requestData[c.COLLECTION_ID]; + const query = requestData[c.QUERY]; + const order = requestData[c.ORDER]; + const limit = requestData[c.LIMIT]; + + const documents = await context.driver.get(collectionId, query, order, limit); + + const connectedNodes = context.nodes.filter(node => node.connected); + + const filteredDocuments = documents.filter( + isFirstConnectedReplica(connectedNodes, context.thisNode.name) + ); + + response.reply(c.STATUS_OK, { + [c.DATA]: filteredDocuments.length + }); +} + +export default internalCountController; diff --git a/lib/modules/crud/controllers/internal/delete.js b/lib/modules/crud/controllers/internal/delete.js new file mode 100644 index 0000000..c734d89 --- /dev/null +++ b/lib/modules/crud/controllers/internal/delete.js @@ -0,0 +1,23 @@ +import c from '../../../../constants.js'; +import isLockedOrWait from '../../../../utils/isLockedOrWait.js'; + +async function deleteController ({ context, socket, request, response }) { + const requestData = request.json(); + + const query = requestData[c.QUERY]; + const collectionId = requestData[c.COLLECTION_ID]; + const lockId = requestData[c.LOCK_ID]; + const waitForUnlock = requestData[c.LOCK_STRATEGY] !== c.LOCK_STRATEGY_FAIL; + + await isLockedOrWait(context, socket, collectionId, lockId, waitForUnlock); + + const foundDocuments = await context.driver.get(collectionId, query); + + await context.driver.del(collectionId, query); + + response.reply(c.STATUS_OK, { + [c.DATA]: foundDocuments.map(document => document.id) + }); +} + +export default deleteController; diff --git a/lib/modules/crud/controllers/internal/get.js b/lib/modules/crud/controllers/internal/get.js new file mode 100644 index 0000000..9c3ec80 --- /dev/null +++ b/lib/modules/crud/controllers/internal/get.js @@ -0,0 +1,45 @@ +import c from '../../../../constants.js'; + +// Logic: Only return the document if we are +// the first replica that's available +function isFirstConnectedReplica (connectedNodes, nodeName) { + return document => { + const availableReplicatedNodes = document._replicatedNodes.filter(nodeName => { + return !!connectedNodes.find(cnode => cnode.name === nodeName); + }); + + if (availableReplicatedNodes[0] === nodeName) { + return true; + } + + return false; + }; +} + +async function internalGetController ({ context, socket, request, response }) { + const requestData = request.json(); + + const collectionId = requestData[c.COLLECTION_ID]; + const query = requestData[c.QUERY]; + const fields = requestData[c.FIELDS]; + const order = requestData[c.ORDER]; + const limit = requestData[c.LIMIT]; + + if (fields) { + fields.push('_replicatedNodes'); + } + + const documents = await context.driver.get(collectionId, query, fields, order, limit); + + const connectedNodes = context.nodes.filter(node => node.connected); + + const filteredDocuments = documents.filter( + isFirstConnectedReplica(connectedNodes, context.thisNode.name) + ); + + response.reply(c.STATUS_OK, { + [c.DATA]: filteredDocuments + }); +} + +export default internalGetController; diff --git a/lib/modules/crud/controllers/internal/patch.js b/lib/modules/crud/controllers/internal/patch.js new file mode 100644 index 0000000..12f468f --- /dev/null +++ b/lib/modules/crud/controllers/internal/patch.js @@ -0,0 +1,23 @@ +import c from '../../../../constants.js'; +import isLockedOrWait from '../../../../utils/isLockedOrWait.js'; + +async function patchController ({ context, socket, request, response }) { + const requestData = request.json(); + + const data = requestData[c.DATA]; + const query = requestData[c.QUERY]; + const collectionId = requestData[c.COLLECTION_ID]; + const lockId = requestData[c.LOCK_ID]; + const waitForUnlock = requestData[c.LOCK_STRATEGY] !== c.LOCK_STRATEGY_FAIL; + + await isLockedOrWait(context, socket, collectionId, lockId, waitForUnlock); + const foundDocuments = await context.driver.get(collectionId, query); + + await context.driver.patch(collectionId, data, query); + + response.reply(c.STATUS_OK, { + [c.DATA]: foundDocuments.map(document => document.id) + }); +} + +export default patchController; diff --git a/lib/modules/crud/controllers/internal/post.js b/lib/modules/crud/controllers/internal/post.js new file mode 100644 index 0000000..b82a649 --- /dev/null +++ b/lib/modules/crud/controllers/internal/post.js @@ -0,0 +1,23 @@ +import c from '../../../../constants.js'; +import isLockedOrWait from '../../../../utils/isLockedOrWait.js'; + +async function postController ({ context, socket, request, response }) { + const requestData = request.json(); + + const data = requestData[c.DATA]; + const collectionId = requestData[c.COLLECTION_ID]; + const replicatedNodes = requestData[c.REPLICATED_NODES]; + const lockId = requestData[c.LOCK_ID]; + const waitForUnlock = requestData[c.LOCK_STRATEGY] !== c.LOCK_STRATEGY_FAIL; + + await isLockedOrWait(context, socket, collectionId, lockId, waitForUnlock); + + data._replicatedNodes = replicatedNodes.sort(); + const document = await context.driver.post(collectionId, data); + + response.reply(c.STATUS_CREATED, { + [c.DATA]: document + }); +} + +export default postController; diff --git a/lib/modules/crud/controllers/internal/put.js b/lib/modules/crud/controllers/internal/put.js new file mode 100644 index 0000000..19a4bf1 --- /dev/null +++ b/lib/modules/crud/controllers/internal/put.js @@ -0,0 +1,27 @@ +import c from '../../../../constants.js'; +import isLockedOrWait from '../../../../utils/isLockedOrWait.js'; +import validateRequestData from '../../../../utils/validateRequestData.js'; + +async function putController ({ context, socket, request, response }) { + const requestData = request.json(); + + await validateRequestData(context, requestData); + + const data = requestData[c.DATA]; + const query = requestData[c.QUERY]; + const collectionId = requestData[c.COLLECTION_ID]; + const lockId = requestData[c.LOCK_ID]; + const waitForUnlock = requestData[c.LOCK_STRATEGY] !== c.LOCK_STRATEGY_FAIL; + + await isLockedOrWait(context, socket, collectionId, lockId, waitForUnlock); + + const foundDocuments = await context.driver.get(collectionId, query); + + await context.driver.put(collectionId, data, query); + + response.reply(c.STATUS_OK, { + [c.DATA]: foundDocuments.map(document => document.id) + }); +} + +export default putController; diff --git a/lib/modules/crud/index.js b/lib/modules/crud/index.js new file mode 100644 index 0000000..b8f96ae --- /dev/null +++ b/lib/modules/crud/index.js @@ -0,0 +1,83 @@ +import c from '../../constants.js'; + +import internalPost from './controllers/internal/post.js'; +import internalCount from './controllers/internal/count.js'; +import internalGet from './controllers/internal/get.js'; +import internalPut from './controllers/internal/put.js'; +import internalPatch from './controllers/internal/patch.js'; +import internalDelete from './controllers/internal/delete.js'; + +import externalPost from './controllers/external/post.js'; +import externalCount from './controllers/external/count.js'; +import externalGet from './controllers/external/get.js'; +import externalPut from './controllers/external/put.js'; +import externalPatch from './controllers/external/patch.js'; +import externalDelete from './controllers/external/delete.js'; + +function crudModule (context) { + // Internal + context.controllers.internal.add({ + command: c.POST, + conditions: [], + handler: internalPost + }); + context.controllers.internal.add({ + command: c.COUNT, + conditions: [], + handler: internalCount + }); + context.controllers.internal.add({ + command: c.GET, + conditions: [], + handler: internalGet + }); + context.controllers.internal.add({ + command: c.PUT, + conditions: [], + handler: internalPut + }); + context.controllers.internal.add({ + command: c.PATCH, + conditions: [], + handler: internalPatch + }); + context.controllers.internal.add({ + command: c.DELETE, + conditions: [], + handler: internalDelete + }); + + // External + context.controllers.external.add({ + command: c.POST, + conditions: [], + handler: context.controllers.rejectWhenUnhealthy(externalPost) + }); + context.controllers.external.add({ + command: c.COUNT, + conditions: [], + handler: context.controllers.rejectWhenUnhealthy(externalCount) + }); + context.controllers.external.add({ + command: c.GET, + conditions: [], + handler: context.controllers.rejectWhenUnhealthy(externalGet) + }); + context.controllers.external.add({ + command: c.PUT, + conditions: [], + handler: context.controllers.rejectWhenUnhealthy(externalPut) + }); + context.controllers.external.add({ + command: c.PATCH, + conditions: [], + handler: context.controllers.rejectWhenUnhealthy(externalPatch) + }); + context.controllers.external.add({ + command: c.DELETE, + conditions: [], + handler: context.controllers.rejectWhenUnhealthy(externalDelete) + }); +} + +export default crudModule; diff --git a/lib/modules/http/index.js b/lib/modules/http/index.js new file mode 100644 index 0000000..6941210 --- /dev/null +++ b/lib/modules/http/index.js @@ -0,0 +1,149 @@ +import fs from 'fs'; +import http2 from 'http2'; +import logslot from 'logslot'; +import writeResponse from 'write-response'; +import validateAlphaNumericDashDot from '../../utils/validateAlphaNumericDashDot.js'; +import c from '../../constants.js'; +import finalStream from 'final-stream'; + +async function parseRequestBody (request) { + const data = await finalStream(request); + + try { + if (!data || data.toString() === '') { + return [null, 'none']; + } + + return [JSON.parse(data), 'json']; + } catch (error) { + return [null, 'invalid']; + } +} + +const packageJson = JSON.parse( + fs.readFileSync('./package.json', 'utf8') +); + +const log = logslot('canhazdb.http'); + +async function handleGetDocument (context, request, response, { collectionId, documentId }) { + const getResult = await context.thisNode.client.send(c.GET, { + [c.COLLECTION_ID]: collectionId, + [c.QUERY]: { + id: documentId + } + }); + + const data = getResult.json()[c.DATA]; + + response.end(JSON.stringify(data[0], null, 2)); +} + +async function handleGetCollection (context, request, response, { collectionId, query, limit }) { + const getResult = await context.thisNode.client.send(c.GET, { + [c.COLLECTION_ID]: collectionId, + [c.QUERY]: query, + [c.LIMIT]: limit ? parseInt(limit) : undefined + }); + + const data = getResult.json()[c.DATA]; + + writeResponse(200, data, response); +} + +function httpModule (context) { + if (!context.options.httpPort || !context.options.httpHost) { + return; + } + + const server = http2.createSecureServer({ + ...context.options.tls, + allowHTTP1: true + }, async function (request, response) { + const [body, bodyType] = await parseRequestBody(request); + if (bodyType === 'invalid') { + writeResponse(400, { error: 'request body not valid json' }, response); + return; + } + + if (body instanceof Error) { + console.log(body); + process.exit(1); + } + + const path = request.url || request.headers[':path']; + const url = new URL(path, 'https://127.0.0.1/'); + const parts = url.pathname.split('/'); + + const [, collectionId, resourceId] = url.pathname.split('/'); + + log.info('request received', { pathname: url.pathname, method: request.method }); + + if (collectionId && !validateAlphaNumericDashDot(collectionId)) { + writeResponse(422, { + errors: ['collectionId can only contain a-z, A-Z, 0-9, dashs or dots'] + }, response); + return; + } + + const unhealthyNodes = context.nodes.filter(node => node.status !== 'healthy'); + if (unhealthyNodes.length > context.settings.replicas - 1) { + writeResponse(503, { + errors: ['too many nodes in the cluster are unhealthy, therefore the database is down'] + }, response); + return; + } + + if (request.method === 'GET' && url.pathname === '/') { + writeResponse(200, { + status: 200, + name: packageJson.name, + version: packageJson.version, + info: 'https://canhazdb.com' + }, response); + return; + } else if (url.pathname === '/') { + writeResponse(405, { error: 'method not allowed' }, response); + return; + } + + if (!body && ['POST', 'PUT', 'PATCH'].includes(request.method)) { + writeResponse(400, { error: 'empty request body not allowed' }, response); + return; + } + + if (parts.length === 2) { + handleGetCollection(context, request, response, { + collectionId: parts[1], + limit: url.searchParams.get('limit') + }); + return; + } + + if (parts.length === 3) { + handleGetDocument(context, request, response, { + collectionId: parts[1], + documentId: parts[2] + }); + return; + } + + response.end('api - not found'); + }); + server.on('error', (error) => console.error(error)); + + server.on('listening', () => { + log.info('http server listening on ' + server.address().port); + }); + + server.listen(context.options.httpPort, context.options.httpHost); + + return { + cleanup: () => { + log.info('http server closed'); + server.close(); + } + }; +} + +export default httpModule; diff --git a/lib/modules/lock/controllers/external/lock.js b/lib/modules/lock/controllers/external/lock.js new file mode 100644 index 0000000..f600a8b --- /dev/null +++ b/lib/modules/lock/controllers/external/lock.js @@ -0,0 +1,50 @@ +import { v4 as uuid } from 'uuid'; + +import c from '../../../../constants.js'; +import waitUntil from '../../../../utils/waitUntil.js'; + +async function lockController ({ context, socket, request, response }) { + const requestData = request.json(); + + if (typeof requestData[c.LOCK_KEY] !== 'string') { + response.reply(c.STATUS_BAD_REQUEST, { + [c.ERROR]: { + message: 'LOCK_KEY must be a string' + } + }); + return; + } + + const id = uuid(); + + await waitUntil(() => context.raft.leader?.client || context.closed); + + if (context.closed) { + return; + } + + const result = await context.raft.leader.client.send(c.LOCK, { + [c.INTERNAL]: true, + [c.LOCK_ID]: id, + [c.LOCK_KEY]: requestData[c.LOCK_KEY], + [c.LOCK_ORIGIN]: context.thisNode.name + }); + + if (result.command !== c.STATUS_OK) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: { + message: 'lock has not been acquired', + reason: result[c.ERROR] + } + }); + return; + } + + socket.state.locks.push(id); + + response.reply(c.STATUS_OK, { + [c.LOCK_ID]: id + }); +} + +export default lockController; diff --git a/lib/modules/lock/controllers/external/systemLocksController.js b/lib/modules/lock/controllers/external/systemLocksController.js new file mode 100644 index 0000000..969502e --- /dev/null +++ b/lib/modules/lock/controllers/external/systemLocksController.js @@ -0,0 +1,9 @@ +import c from '../../../../constants.js'; + +async function systemLocksController ({ context, socket, request, response }) { + response.reply(c.STATUS_OK, { + [c.DATA]: context.locks.queue + }); +} + +export default systemLocksController; diff --git a/lib/modules/lock/controllers/external/unlock.js b/lib/modules/lock/controllers/external/unlock.js new file mode 100644 index 0000000..2289eee --- /dev/null +++ b/lib/modules/lock/controllers/external/unlock.js @@ -0,0 +1,41 @@ +import c from '../../../../constants.js'; +import waitUntil from '../../../../utils/waitUntil.js'; + +async function unlockController ({ context, socket, request, response }) { + const requestData = request.json(); + + const matchingLock = socket.state.locks + .find(id => id === requestData[c.LOCK_ID]); + + if (!matchingLock) { + response.reply(c.STATUS_NOT_FOUND); + return; + } + + await waitUntil(() => context.raft.leader?.client || context.closed); + + if (context.closed) { + return; + } + + const result = await context.raft.leader.client.send(c.UNLOCK, { + [c.INTERNAL]: true, + [c.LOCK_ID]: requestData[c.LOCK_ID] + }); + + if (result.command !== c.STATUS_OK) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: { + message: 'lock has not been released', + reason: result[c.ERROR] + } + }); + return; + } + + response.reply(c.STATUS_OK, { + [c.LOCK_ID]: requestData[c.LOCK_ID] + }); +} + +export default unlockController; diff --git a/lib/modules/lock/controllers/internal/lock.js b/lib/modules/lock/controllers/internal/lock.js new file mode 100644 index 0000000..4016e58 --- /dev/null +++ b/lib/modules/lock/controllers/internal/lock.js @@ -0,0 +1,50 @@ +import c from '../../../../constants.js'; + +async function lockController ({ context, socket, request, response }) { + const requestData = request.json(); + + const isLeader = context.raft.leader === context.thisNode; + + if (!isLeader) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: 'internal lock request sent to none leader' + }); + return; + } + + const key = requestData[c.LOCK_KEY]; + const id = requestData[c.LOCK_ID]; + const lockOrigin = requestData[c.LOCK_ORIGIN]; + context.locks.byNode[lockOrigin] = context.locks.byNode[lockOrigin] || []; + context.locks.byNode[lockOrigin].push(id); + + /* Horrible, needs a refactor, but it works. Make sure both the + lock is resolved AND the dispatch has resolved. If not, then + there is a chance the external lock will resolve, before all + nodes have synced the actual lock. + */ + let calls = 0; + const finish = () => { + calls = calls + 1; + if (calls === 2) { + response.reply(c.STATUS_OK, { + [c.LOCK_ID]: id + }); + } + }; + + context.locks.once('resolved.' + id, () => { + finish(); + }); + + await context.dispatchToRaft(context, { + [c.RAFT_ACTION_TYPE]: c.LOCK, + [c.LOCK_KEY]: key, + [c.LOCK_ID]: id, + [c.LOCK_ORIGIN]: lockOrigin + }); + + finish(); +} + +export default lockController; diff --git a/lib/modules/lock/controllers/internal/unlock.js b/lib/modules/lock/controllers/internal/unlock.js new file mode 100644 index 0000000..02ae886 --- /dev/null +++ b/lib/modules/lock/controllers/internal/unlock.js @@ -0,0 +1,36 @@ +import c from '../../../../constants.js'; + +async function unlockController ({ context, socket, request, response }) { + const requestData = request.json(); + + const isLeader = context.raft.leader === context.thisNode; + + if (!isLeader) { + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: 'internal lock request sent to none leader' + }); + return; + } + + const id = requestData[c.LOCK_ID]; + + const foundLocks = await context.locks.queue.find(lock => lock.id === id); + + if (!foundLocks) { + response.reply(c.STATUS_NOT_FOUND, { + [c.LOCK_ID]: id + }); + return; + } + + await context.dispatchToRaft(context, { + [c.RAFT_ACTION_TYPE]: c.UNLOCK, + [c.LOCK_ID]: id + }); + + response.reply(c.STATUS_OK, { + [c.LOCK_ID]: id + }); +} + +export default unlockController; diff --git a/lib/modules/lock/index.js b/lib/modules/lock/index.js new file mode 100644 index 0000000..baa3935 --- /dev/null +++ b/lib/modules/lock/index.js @@ -0,0 +1,163 @@ +import logslot from 'logslot'; +import lockbase from 'lockbase'; +import failmenot from 'failmenot/curried.js'; +import systemLocksController from './controllers/external/systemLocksController.js'; +import externalLockController from './controllers/external/lock.js'; +import externalUnlockController from './controllers/external/unlock.js'; +import internalLockController from './controllers/internal/lock.js'; +import internalUnlockController from './controllers/internal/unlock.js'; +import insertDefaultDocument from '../../utils/insertDefaultDocument.js'; +import waitUntil from '../../utils/waitUntil.js'; + +import c from '../../constants.js'; + +const log = logslot('canhazdb.lock'); + +const dispatchToRaftWithRetry = failmenot({ + maximumTime: 5000 +})((context, ...args) => { + if (context.closed) { + return; + } + + return context.dispatchToRaft(context, ...args); +}); + +function lockReducer (state, action) { + if (!state.locks) { + state.locks = { + incremental: 0, + queue: [] + }; + } + if (action[c.RAFT_ACTION_TYPE] === c.LOCK) { + state.locks.queue.push({ + id: action[c.LOCK_ID], + path: action[c.LOCK_KEY], + origin: action[c.LOCK_ORIGIN] + }); + state.locks.incremental = state.locks.incremental + 1; + return state; + } + + if (action[c.RAFT_ACTION_TYPE] === c.UNLOCK) { + state.locks.queue = state.locks.queue.filter(item => item.id !== action[c.LOCK_ID]); + + return state; + } + + return state; +} + +async function cleanupDisconnectedNodes (context) { + const disconnectedNodes = context.nodes.filter(node => !node.connected) + + const orphanedLocks = context.locks.queue + .filter(item => { + return disconnectedNodes.find(node => node.name === item.origin); + }); + + if (orphanedLocks.length > 0) { + log.info(`cleaning up ${orphanedLocks.length} orphaned locks`); + } + + for (let lock of orphanedLocks) { + log.info('unlocking orphaned lock [' + lock.id + ']'); + await dispatchToRaftWithRetry(context, { + [c.RAFT_ACTION_TYPE]: c.UNLOCK, + [c.LOCK_ID]: lock.id + }); + } +} + +async function lockModule (context) { + context.locks = lockbase(); + context.locks.byNode = {}; + + context.controllers.external.add({ + command: c.LOCK, + handler: externalLockController + }); + context.controllers.external.add({ + command: c.UNLOCK, + handler: externalUnlockController + }); + + context.controllers.internal.add({ + command: c.LOCK, + handler: internalLockController + }); + context.controllers.internal.add({ + command: c.UNLOCK, + handler: internalUnlockController + }); + + context.controllers.external.add({ + command: c.GET, + priority: 10, + conditions: [ + (request) => { + const data = request.json(); + return data[c.COLLECTION_ID] === 'system.locks'; + } + ], + handler: systemLocksController + }); + + context.on('client.closed', socket => { + const isLeader = context.raft.leader === context.thisNode; + + if (!isLeader) { + return; + } + + socket.state.locks.forEach(lockId => { + dispatchToRaftWithRetry(context, { + [c.RAFT_ACTION_TYPE]: c.UNLOCK, + [c.LOCK_ID]: lockId + }); + }); + }); + + context.on('raft:thisNodeIsLeader', () => { + cleanupDisconnectedNodes(context); + }); + + context.on('node.disconnected', async node => { + const isLeader = context.raft.leader === context.thisNode; + if (!isLeader || context.closed) { + return; + } + + cleanupDisconnectedNodes(context); + }); + + context.on('client.connected', socket => { + socket.state.locks = []; + }); + + context.on('raft:stateChanged', () => { + context.locks.importState(context.raft.state.locks); + context.locks.byNode = {}; + + context.raft.state.queue?.forEach(lock => { + const lockId = lock.id; + const nodeName = lock.nodeName; + + context.locks.byNode[nodeName] = context.locks.byNode[nodeName] || []; + context.locks.byNode[nodeName].push(lockId); + }); + }); + + insertDefaultDocument(context, 'system.collections', { + id: 'system.locks', + collectionId: 'system.locks', + documentCount: 0 + }); + + await waitUntil(() => context.raft?.reducers && context.raft?.state); + + context.raft.reducers.push(lockReducer); +} + +export default lockModule; diff --git a/lib/modules/notify/controllers/external/notifyOff.js b/lib/modules/notify/controllers/external/notifyOff.js new file mode 100644 index 0000000..5a4a63e --- /dev/null +++ b/lib/modules/notify/controllers/external/notifyOff.js @@ -0,0 +1,21 @@ +// import logslot from 'logslot'; + +import c from '../../../../constants.js'; + +async function externalNotifyOffController ({ context, socket, request, response }) { + const requestData = request.json(); + const notifyPath = requestData[c.NOTIFY_PATH]; + + const existingNotifierIndex = socket.state.notifiers + .findIndex(notifier => notifier.path === notifyPath); + + if (existingNotifierIndex > -1) { + socket.state.notifiers.splice(existingNotifierIndex, 1); + } + + await context.notify.unwatch(notifyPath); + + response.reply(c.STATUS_OK); +} + +export default externalNotifyOffController; diff --git a/lib/modules/notify/controllers/external/notifyOn.js b/lib/modules/notify/controllers/external/notifyOn.js new file mode 100644 index 0000000..a1c30f3 --- /dev/null +++ b/lib/modules/notify/controllers/external/notifyOn.js @@ -0,0 +1,22 @@ +// import logslot from 'logslot'; + +import c from '../../../../constants.js'; + +async function externalNotifyOnController ({ context, socket, request, response }) { + const requestData = request.json(); + const notifyPath = requestData[c.NOTIFY_PATH]; + + socket.state.notifiers.push({ + path: notifyPath, + regex: new RegExp(notifyPath), + handler: path => { + response.send(c.NOTIFY, { [c.DATA]: path }); + } + }); + + await context.notify.watch(notifyPath); + + response.reply(c.STATUS_OK); +} + +export default externalNotifyOnController; diff --git a/lib/modules/notify/controllers/internal/notify.js b/lib/modules/notify/controllers/internal/notify.js new file mode 100644 index 0000000..1ae9cba --- /dev/null +++ b/lib/modules/notify/controllers/internal/notify.js @@ -0,0 +1,14 @@ +// import logslot from 'logslot'; + +import c from '../../../../constants.js'; + +async function internalNotifyController ({ context, socket, request, response }) { + const requestData = request.json(); + const notifyPath = requestData[c.DATA]; + + context.emit('notify.received', notifyPath); + + response.reply(c.STATUS_OK); +} + +export default internalNotifyController; diff --git a/lib/modules/notify/controllers/internal/notifyOff.js b/lib/modules/notify/controllers/internal/notifyOff.js new file mode 100644 index 0000000..ff9d5ed --- /dev/null +++ b/lib/modules/notify/controllers/internal/notifyOff.js @@ -0,0 +1,20 @@ +// import logslot from 'logslot'; + +import c from '../../../../constants.js'; + +async function internalNotifyOffController ({ context, socket, request, response }) { + const requestData = request.json(); + const notifyPath = requestData[c.NOTIFY_PATH]; + + const notifiers = context.notify.internalNotifiers; + + const existingNotifierIndex = notifiers.findIndex(notifier => notifier.path === notifyPath); + + if (existingNotifierIndex > -1) { + notifiers.splice(existingNotifierIndex, 1); + } + + response.reply(c.STATUS_OK); +} + +export default internalNotifyOffController; diff --git a/lib/modules/notify/controllers/internal/notifyOn.js b/lib/modules/notify/controllers/internal/notifyOn.js new file mode 100644 index 0000000..af23e45 --- /dev/null +++ b/lib/modules/notify/controllers/internal/notifyOn.js @@ -0,0 +1,27 @@ +// import logslot from 'logslot'; + +import c from '../../../../constants.js'; + +async function internalNotifyOnController ({ context, socket, request, response }) { + const requestData = request.json(); + const nodeName = requestData[c.INTERNAL]; + const notifyPath = requestData[c.NOTIFY_PATH]; + + const notifiers = context.notify.internalNotifiers; + + const existingNotifier = context.notify.internalNotifiers.find( + notifier => notifier.nodeName === nodeName && notifier.path === notifyPath + ); + + if (!existingNotifier) { + notifiers.push({ + path: notifyPath, + regex: new RegExp(notifyPath), + nodeName: requestData[c.INTERNAL] + }); + } + + response.reply(c.STATUS_OK); +} + +export default internalNotifyOnController; diff --git a/lib/modules/notify/index.js b/lib/modules/notify/index.js new file mode 100644 index 0000000..1bb3213 --- /dev/null +++ b/lib/modules/notify/index.js @@ -0,0 +1,161 @@ +import logslot from 'logslot'; + +import c from '../../constants.js'; +import systemNotifysController from './systemNotifysController.js'; +import insertDefaultDocument from '../../utils/insertDefaultDocument.js'; + +const log = logslot('canhazdb.notify'); + +function askOnAllNodes (context, command, data) { + return Promise.all( + context.nodes.map(node => { + return node.client && node.client.send(command, data).catch(error => { + if (error.message.includes('client disconnected')) { + log.warn(`could not send ${c[command]} to node('${node.name}') because it was not connected`); + } else { + throw error; + } + }); + }) + ); +} + +async function notifyModule (context) { + context.notify = { + internalNotifiers: [], + watching: {}, + + watch: notifyPath => { + log.info('sending NOTIFY_ON to all nodes', { notifyPath }); + context.notify.watching[notifyPath] = (context.notify.watching[notifyPath] || 0) + 1; + return askOnAllNodes(context, c.NOTIFY_ON, { + [c.INTERNAL]: context.thisNode.name, + [c.NOTIFY_PATH]: notifyPath + }); + }, + + unwatch: notifyPath => { + log.info('sending NOTIFY_OFF to all nodes', { notifyPath }); + context.notify.watching[notifyPath] = (context.notify.watching[notifyPath] || 0) - 1; + if (context.notify.watching[notifyPath] < 0) { + context.notify.watching[notifyPath] = 0; + } + + return askOnAllNodes(context, c.NOTIFY_OFF, { + [c.INTERNAL]: context.thisNode.name, + [c.NOTIFY_PATH]: notifyPath + }); + } + }; + + context.controllers.external.add({ + command: c.GET, + priority: 10, + conditions: [ + (request) => { + const data = request.json(); + return data[c.COLLECTION_ID] === 'system.notifys'; + } + ], + handler: systemNotifysController + }); + + context.controllers.external.add({ + command: c.NOTIFY_OFF, + handler: context.controllers.rejectWhenUnhealthy( + (await import('./controllers/external/notifyOff.js')).default + ) + }); + + context.controllers.external.add({ + command: c.NOTIFY_ON, + handler: context.controllers.rejectWhenUnhealthy( + (await import('./controllers/external/notifyOn.js')).default + ) + }); + + context.controllers.internal.add({ + command: c.NOTIFY_OFF, + handler: (await import('./controllers/internal/notifyOff.js')).default + }); + + context.controllers.internal.add({ + command: c.NOTIFY_ON, + handler: (await import('./controllers/internal/notifyOn.js')).default + }); + + context.controllers.internal.add({ + command: c.NOTIFY, + handler: (await import('./controllers/internal/notify.js')).default + }); + + context.info.generators.push(() => { + return { + internalNotifiers: context.notify.internalNotifiers + }; + }); + + context.on('node.infoReceived', node => { + node.info.internalNotifiers?.forEach(newNotifier => { + const existingNotifier = context.notify.internalNotifiers.find( + notifier => notifier.nodeName === newNotifier.nodeName && notifier.path === newNotifier.path + ); + + if (!existingNotifier) { + context.notify.internalNotifiers.push(newNotifier); + } + }); + }); + + context.on('client.closed', socket => { + if (!socket.state.notifiers) { + return; + } + + socket.state.notifiers.forEach(notifier => { + context.notify.unwatch(notifier.path); + }); + }); + + context.on('client.connected', socket => { + socket.state.notifiers = []; + + context.on('notify.received', notifyPath => { + const notifiers = socket.state.notifiers.filter( + notifier => notifyPath.match(notifier.regex) + ); + + notifiers.forEach(notifier => { + notifier.handler(notifyPath); + }); + }); + }); + + context.on('notify', notifyPath => { + const notifiers = context.notify.internalNotifiers.filter( + notifier => notifyPath.match(notifier.regex) + ); + + notifiers.forEach(notifier => { + const node = context.nodes.find(node => node.name === notifier.nodeName); + node.client.send(c.NOTIFY, { + [c.INTERNAL]: context.thisNode.name, + [c.DATA]: notifyPath + }).catch(error => { + if (error.message.includes('client disconnected')) { + log.warn('could not send notify because client was not connected'); + } else { + throw error; + } + }); + }); + }); + + insertDefaultDocument(context, 'system.collections', { + id: 'system.notifys', + collectionId: 'system.notifys', + documentCount: 0 + }); +} + +export default notifyModule; diff --git a/lib/modules/notify/systemNotifysController.js b/lib/modules/notify/systemNotifysController.js new file mode 100644 index 0000000..017f05b --- /dev/null +++ b/lib/modules/notify/systemNotifysController.js @@ -0,0 +1,14 @@ +import c from '../../constants.js'; + +async function systemCollectionController ({ context, socket, request, response }) { + response.reply(c.STATUS_OK, { + [c.DATA]: Object.keys(context.notify.watching).reduce((result, notifyPath) => { + result.push({ + notifyPath: notifyPath + }); + return result; + }, []) + }); +} + +export default systemCollectionController; diff --git a/lib/modules/raft/index.js b/lib/modules/raft/index.js new file mode 100644 index 0000000..74d2c02 --- /dev/null +++ b/lib/modules/raft/index.js @@ -0,0 +1,170 @@ +import LifeRaft from '@markwylde/liferaft'; +import logslot from 'logslot'; + +import c from '../../constants.js'; +import waitUntil from '../../utils/waitUntil.js'; + +const log = logslot('canhazdb.raft'); + +async function systemRaftAppendController ({ context, socket, request, response }) { + const requestData = request.json(); + + const isLeader = context.raft.leader === context.thisNode; + + if (!isLeader) { + log.error('can not append to none leader'); + response.reply(c.STATUS_SERVER_ERROR, { + [c.ERROR]: 'internal lock request sent to none leader' + }); + return; + // return context.appendToRaft(context, requestData[c.COMMAND], requestData[c.DATA]); + } + + await context.sendToAllNodes(context, c.RAFT_BROADCAST, { + [c.SYSTEM]: true, + [c.COMMAND]: requestData[c.COMMAND], + [c.RESOURCE_ID]: context.raft.log.length, + [c.DATA]: requestData[c.DATA] + }); + + response.reply(c.STATUS_OK); +} + +async function systemRaftBroadcastController ({ context, socket, request, response }) { + const requestData = request.json(); + + const resourceId = requestData[c.RESOURCE_ID]; + + const action = requestData[c.DATA]; + context.raft.log[resourceId] = action; + + context.raft.state = context.raft.reducers.reduce((state, fn) => { + return fn(state, action); + }, context.raft.state || {}); + + context.emit('raft:stateChanged', context.raft.state); + + response.reply(c.STATUS_OK); +} + +async function raftModule (context) { + let controller; + class CanHazRaft extends LifeRaft { + initialize () { + log.debug(`initializing reply socket on port ${this.address}`); + + controller = async ({ request, response }) => { + const requestData = request.json(); + const data = requestData[c.DATA]; + + this.emit('data', data, (responseData) => { + response.reply(c.RAFT_SYSTEM_PROTO, { + [c.DATA]: responseData + }); + }); + }; + } + + async write (packet, callback) { + if (!this.socket) { + this.socket = context.nodes.find(node => node.address === this.address); + } + + try { + log.debug(`writing packet to socket on port ${this.address}`); + const request = await this.socket?.client?.send(c.RAFT_SYSTEM_PROTO, { + [c.SYSTEM]: true, + [c.DATA]: packet + }); + + if (!request) { + return; + } + + const requestData = request.json(); + const data = requestData[c.DATA]; + + callback(undefined, data); + } catch (error) { + if (context.closed) { + return; + } + log.warn(`raft failed to write to socket on port ${this.address}`, error); + } + } + } + + context.raft = { + leader: null, + log: [], + reducers: [], + state: {} + }; + + if (Array.from(new Set(context.options.join)).length === 1) { + waitUntil(() => { + return context.thisNode; + }).then(() => { + context.raft.leader = context.thisNode; + }); + } + + context.dispatchToRaft = function (context, data) { + return context.raft.leader.client.send(c.RAFT_APPEND, { + [c.SYSTEM]: true, + [c.DATA]: data + }); + }; + + context.controllers.system.add({ + command: c.RAFT_SYSTEM_PROTO, + handler: (...args) => controller(...args) + }); + + context.controllers.system.add({ + command: c.RAFT_APPEND, + handler: (...args) => systemRaftAppendController(...args) + }); + + context.controllers.system.add({ + command: c.RAFT_BROADCAST, + handler: (...args) => systemRaftBroadcastController(...args) + }); + + const raft = new CanHazRaft(`tls://${context.options.host}:${context.options.port}`, { + context, + 'election min': 200, + 'election max': 1000, + heartbeat: 150 + }); + + raft.on('heartbeat timeout', function () { + log.info('heart beat timeout, starting election'); + }); + + raft.on('leader change', function (to, from) { + context.raft.leader = context.nodes.find(node => node.address === to); + context.emit('raft:leaderChanged', to, from); + log.info('we have a new leader', { to, from }); + }); + + raft.on('leader', function () { + context.emit('raft:thisNodeIsLeader'); + log.info('this node has been elected as the leader', { nodeName: context.thisNode?.name }); + }); + + async function join (node) { + raft.join(node.address); + } + + context.nodes.forEach(join); + context.on('node.connected', join); + + return { + cleanup: () => { + raft.end(); + } + }; +} + +export default raftModule; diff --git a/lib/modules/web/build.js b/lib/modules/web/build.js new file mode 100644 index 0000000..966a8c7 --- /dev/null +++ b/lib/modules/web/build.js @@ -0,0 +1,58 @@ +import fs from 'fs'; +import esbuild from 'esbuild'; + +async function build () { + const watch = process.env.NODE_ENV === 'development'; + + async function buildJs () { + const result = await esbuild.build({ + entryPoints: ['./web/js/index.js'], + bundle: true, + sourcemap: true, + metafile: true, + outfile: './web/public/index.min.js', + watch, + minify: true, + loader: { + '.svg': 'file', + '.gif': 'file', + '.png': 'file', + '.js': 'jsx' + }, + define: { + 'process.env.NODE_ENV': '"' + process.env.NODE_ENV + '"' + } + }); + fs.writeFileSync('./web/meta.json', JSON.stringify(result.metafile, null, 2)); + } + + async function buildCss () { + await esbuild.build({ + entryPoints: ['./web/css/index.css'], + bundle: true, + sourcemap: true, + outfile: './web/public/index.min.css', + watch, + loader: { + '.svg': 'file', + '.png': 'file' + } + }); + } + + async function buildHtml () { + let html = await fs.promises.readFile('./web/html/index.html', 'utf8'); + + html = html.replace('{BASE_URL}', process.env.BASE_URL || '/'); + + await fs.promises.writeFile('./web/public/index.html', html); + } + + await Promise.all([ + buildCss(), + buildJs(), + buildHtml() + ]); +} + +export default build; diff --git a/lib/modules/web/index.js b/lib/modules/web/index.js new file mode 100644 index 0000000..8f0abe9 --- /dev/null +++ b/lib/modules/web/index.js @@ -0,0 +1,151 @@ +import path from 'path'; +import http2 from 'http2'; +import axios from 'axios'; +import https from 'https'; +import servatron from 'servatron/http.js'; +import logslot from 'logslot'; +import build from './build.js'; +import finalStream from 'final-stream'; +import cryptoRandomString from 'crypto-random-string'; + +const log = logslot('canhazdb.web'); + +const staticHandler = servatron({ + directory: './web/public', + spa: true, + spaIndex: 'index.html' +}); + +function webModule (context) { + if (!context.options.webPort || !context.options.webHost) { + return; + } + + const authentications = {}; + + build(); + + const server = http2.createSecureServer({ + ...context.options.tls, + allowHTTP1: true, + requestCert: false + }, async function (request, response) { + const body = await finalStream(request).then(JSON.parse).catch(() => null); + const urlPath = request.url || request.headers[':path']; + + if (urlPath.startsWith('/api/')) { + log.info('request received to ' + urlPath); + if (urlPath === '/api/settings') { + response.end( + JSON.stringify({ + ca: { + name: path.basename(context.options.tlsCa), + data: context.options.tls.ca.toString() + } + }) + ); + return; + } + + if (urlPath === '/api/authenticate') { + const httpsAgent = new https.Agent({ + key: body.privateKey.data, + cert: body.cert.data, + ca: [body.ca.data] + }); + + try { + await axios(`https://localhost:${context.options.httpPort}/api/system.collections`, { + httpsAgent + }); + + const token = cryptoRandomString({ length: 36 }); + authentications[token] = { + body, + httpsAgent + }; + response.end( + JSON.stringify({ + token + }) + ); + } catch (error) { + log.warn('failed to authenticate', { error: error.message }); + response.end( + JSON.stringify({ + error: error.message + }) + ); + } + return; + } + + if (urlPath.startsWith('/api/authenticate/')) { + const token = urlPath.substr('/api/authenticate/'.length); + + try { + await axios(`https://localhost:${context.options.httpPort}/api/system.collections`, { + httpsAgent: authentications[token]?.httpsAgent + }); + + response.end( + JSON.stringify(authentications[request.headers.authorisation].body) + ); + } catch (error) { + log.warn('failed to authenticate', { error }); + response.writeHead(401); + response.end( + JSON.stringify({ + error: error.message + }) + ); + } + return; + } + + if (request.headers.authorisation) { + try { + const proxyUrl = `https://localhost:${context.options.httpPort}${urlPath.replace('/api', '')}`; + const proxiedResponse = await axios(proxyUrl, { + method: request.method, + httpsAgent: authentications[request.headers.authorisation]?.httpsAgent + }); + response.end( + JSON.stringify(proxiedResponse.data) + ); + return; + } catch (error) { + log.warn('failed to authenticate', { error }); + response.writeHead(401); + response.end( + JSON.stringify({ + error: error.message + }) + ); + } + } + + response.end('api - not found'); + + return; + } + + staticHandler(request, response); + }); + server.on('error', (error) => console.error(error)); + + server.on('listening', () => { + log.info('web ui server listening on ' + server.address().port); + }); + + server.listen(context.options.webPort, context.options.webHost); + + return { + cleanup: () => { + log.info('web server closed'); + server.close(); + } + }; +} + +export default webModule; diff --git a/lib/prepareOptions.js b/lib/prepareOptions.js new file mode 100644 index 0000000..65b6707 --- /dev/null +++ b/lib/prepareOptions.js @@ -0,0 +1,46 @@ +import dns from 'dns'; +import os from 'os'; +import fs from 'fs'; +import path from 'path'; + +import logslot from 'logslot'; +const log = logslot('canhazdb.prepareOptions'); + +async function prepareOptions (rawOptions) { + const options = { + ...rawOptions, + port: rawOptions.port || 8060, + join: rawOptions.join || [] + }; + + options.nodeName = rawOptions.nodeName || process.env.CANHAZDB_NODE_NAME || os.hostname(); + options.port = parseInt(options.port); + + if (rawOptions.joinFromDns) { + const dnsLookupResults = await dns.promises.lookup(rawOptions.joinFromDns, { all: true }); + log.info('joining from dns:', { dnsLookupResults }); + options.join = dnsLookupResults.map(item => `${item.address}:${options.port}`); + } else { + options.join.push(`${rawOptions.host}:${options.port}`); + } + + if (rawOptions.tlsCa || rawOptions.tlsCert || rawOptions.tlsKey) { + if (!rawOptions.tlsCa || !rawOptions.tlsCert || !rawOptions.tlsKey) { + throw new Error('You must specifiy either all [tls-key, tls-cert, tls-ca] or none of them'); + } + + options.tls = { + key: fs.readFileSync(rawOptions.tlsKey), + cert: fs.readFileSync(rawOptions.tlsCert), + ca: [fs.readFileSync(rawOptions.tlsCa)], + requestCert: true + }; + } + + options.dataDirectory = rawOptions.dataDirectory || + path.resolve(process.cwd(), './canhazdata', options.nodeName); + + return options; +} + +export default prepareOptions; diff --git a/lib/startRepl.js b/lib/startRepl.js new file mode 100644 index 0000000..13ded90 --- /dev/null +++ b/lib/startRepl.js @@ -0,0 +1,22 @@ +import repl from 'repl'; +import c from './constants.js'; + +async function startRepl (context) { + console.log('\nInteractive REPL:'); + process.on('unhandledRejection', (error) => { + console.log(error); + const r = repl.start('> '); + + Object.assign(r.context, { context }); + Object.assign(r.context, c); + Object.assign(r.context, { c }); + }); + + const r = repl.start('> '); + + Object.assign(r.context, { context }); + Object.assign(r.context, c); + Object.assign(r.context, { c }); +} + +export default startRepl; diff --git a/lib/tcpHandler.js b/lib/tcpHandler.js deleted file mode 100644 index 4d767d4..0000000 --- a/lib/tcpHandler.js +++ /dev/null @@ -1,332 +0,0 @@ -const tcpocket = require('tcpocket'); -const lockbase = require('lockbase'); - -const createCollectionMetadataUpdater = require('./createCollectionMetadataUpdater'); - -const { - COMMAND, - STATUS, - DATA, - DOCUMENT, - DOCUMENTS, - INFO, - NOTIFY_ON, - NOTIFY_OFF, - LOCK, - LOCK_STRATEGY, - LOCK_STRATEGY_FAIL, - UNLOCK, - COUNT, - GET, - POST, - PUT, - PATCH, - DELETE, - LOCK_ID, - COLLECTION_ID, - RESOURCE_ID, - QUERY, - FIELDS, - LIMIT, - ORDER -} = require('./constants'); - -function getKeyByValue (object, value) { - return Object.keys(object).find(key => object[key] === value); -} - -function handleError (type, request, response, error) { - const data = (request.data && request.data[DATA]) || {}; - const collectionId = data[COLLECTION_ID]; - const resourceId = data[RESOURCE_ID]; - const query = data[QUERY]; - const fields = data[FIELDS]; - const order = data[ORDER]; - const limit = data[LIMIT]; - - response.reply({ - [STATUS]: error.status || 500, - [DATA]: { - error: error.message, - type: getKeyByValue(require('./constants'), type), - collectionId, - resourceId, - query, - fields, - order, - limit - } - }); -} - -async function isLockedOrWait (locks, keys, lockId, waitForUnlock) { - const locked = locks.check(keys); - - if (!locked) { - return false; - } - - if (locked && locked[0] === lockId) { - return false; - } - - if (waitForUnlock) { - try { - await locks.wait(keys); - } catch (error) { - throw Object.assign(new Error('canhazdb cancelled all locks'), { status: 409 }); - } - return false; - } - - return true; -} - -async function get (state, request, response) { - const data = request.data[DATA]; - const collectionId = data[COLLECTION_ID]; - const resourceId = data[RESOURCE_ID]; - let query = data[QUERY]; - const fields = data[FIELDS]; - const order = data[ORDER]; - const limit = data[LIMIT]; - - if (resourceId) { - query = { id: resourceId }; - } - - const documents = await state.driver.get(collectionId, query, fields, order, limit); - - response.reply({ [STATUS]: 200, [DOCUMENTS]: documents }); -} - -async function count (state, request, response) { - const data = request.data[DATA]; - const collectionId = data[COLLECTION_ID]; - const query = data[QUERY]; - const fields = data[FIELDS]; - const order = data[ORDER]; - const limit = data[LIMIT]; - - const documentCount = await state.driver.count(collectionId, query, fields, order, limit); - - response.reply({ [STATUS]: 200, [DATA]: { documentCount } }); -} - -function notify (notifyPath, collectionId, resourceId, request) { - request.state.notifiers - .filter(notifier => { - return notifier[1].test(notifyPath); - }) - .forEach(notifier => { - request.state.send([notifyPath, collectionId, resourceId, notifier[0]]); - }); -} - -async function post (state, request, response) { - const data = request.data[DATA]; - const collectionId = data[COLLECTION_ID]; - const lockId = data[LOCK_ID]; - const waitForUnlock = data[LOCK_STRATEGY] !== LOCK_STRATEGY_FAIL; - - if (await isLockedOrWait(state.locks, [collectionId], lockId, waitForUnlock)) { - throw Object.assign(new Error('lock prevented change'), { status: 409 }); - } - - const document = await state.driver.post(collectionId, data[DOCUMENT]); - - state.updateCollectionMetadata(collectionId, { documentCountAdd: 1 }); - - notify(`POST:/${collectionId}/${document.id}`, collectionId, document.id, request); - - response.reply({ - [STATUS]: 201, - [DOCUMENT]: document - }); -} - -async function put (state, request, response) { - const data = request.data[DATA]; - const collectionId = data[COLLECTION_ID]; - const resourceId = data[RESOURCE_ID]; - let query = data[QUERY]; - - if (resourceId) { - query = { id: resourceId }; - } - - const lockId = data[LOCK_ID]; - const waitForUnlock = data[LOCK_STRATEGY] !== LOCK_STRATEGY_FAIL; - - if (await isLockedOrWait(state.locks, [collectionId], lockId, waitForUnlock)) { - throw Object.assign(new Error('lock prevented change'), { status: 409 }); - } - - const result = await state.driver.put(collectionId, data[DOCUMENT], query); - - notify(`PUT:/${collectionId}/${resourceId}`, collectionId, resourceId, request); - - response.reply({ [STATUS]: 200, [DATA]: { changes: result.changes } }); -} - -async function patch (state, request, response) { - const data = request.data[DATA]; - const collectionId = data[COLLECTION_ID]; - const resourceId = data[RESOURCE_ID]; - let query = data[QUERY]; - - if (resourceId) { - query = { id: resourceId }; - } - - const lockId = data[LOCK_ID]; - const waitForUnlock = data[LOCK_STRATEGY] !== LOCK_STRATEGY_FAIL; - - if (await isLockedOrWait(state.locks, [collectionId], lockId, waitForUnlock)) { - throw Object.assign(new Error('lock prevented change'), { status: 409 }); - } - - const result = await state.driver.patch(collectionId, data[DOCUMENT], query); - - notify(`PATCH:/${collectionId}/${resourceId}`, collectionId, resourceId, request); - - response.reply({ [STATUS]: 200, [DATA]: { changes: result.changes } }); -} - -async function del (state, request, response) { - const data = request.data[DATA]; - const collectionId = data[COLLECTION_ID]; - const resourceId = data[RESOURCE_ID]; - let query = data[QUERY]; - - if (resourceId) { - query = { id: resourceId }; - } - - const lockId = data[LOCK_ID]; - const waitForUnlock = data[LOCK_STRATEGY] !== LOCK_STRATEGY_FAIL; - - if (await isLockedOrWait(state.locks, [collectionId], lockId, waitForUnlock)) { - throw Object.assign(new Error('lock prevented change'), { status: 409 }); - } - - const result = await state.driver.del(collectionId, query); - - if (result.changes > 0) { - state.updateCollectionMetadata(collectionId, { documentCountAdd: -result.changes }); - } - - notify(`DELETE:/${collectionId}/${resourceId}`, collectionId, resourceId, request); - - response.reply({ [STATUS]: 200, [DATA]: { changes: result.changes } }); -} - -async function info (state, request, response) { - const data = request.data[DATA]; - - await Promise.all(data.nodes.map(node => state.join(node, true))); - - response.reply({ - [STATUS]: 200, - [DATA]: { - nodes: state.nodes.map(node => ({ host: node.host, port: node.port })) - } - }); -} - -async function lock (state, request, response) { - const { id, keys } = request.data[DATA]; - - await state.locks.add(keys, id); - - response.reply({ - [STATUS]: 200, - [DATA]: { - id - } - }); -} - -async function unlock (state, request, response) { - const { id } = request.data[DATA]; - - if (state.locks.remove(id)) { - response.reply({ - [STATUS]: 200 - }); - - return; - } - - response.reply({ - [STATUS]: 404 - }); -} - -async function notifyOn (state, request, response) { - const path = request.data[DATA]; - - request.state.notifiers.push([path, new RegExp(path)]); - response.reply({ - [STATUS]: 200 - }); -} -async function notifyOff (state, request, response) { - const path = request.data[DATA]; - - const existingIndex = request.state.notifiers.findIndex(notifer => notifer[0] === path); - request.state.notifiers.splice(existingIndex, 1); - - response.reply({ - [STATUS]: 200 - }); -} - -const mappings = { - [INFO]: info, - [LOCK]: lock, - [UNLOCK]: unlock, - [COUNT]: count, - [GET]: get, - [POST]: post, - [PUT]: put, - [PATCH]: patch, - [DELETE]: del, - [NOTIFY_ON]: notifyOn, - [NOTIFY_OFF]: notifyOff -}; - -function createInternalServer (state, port, tls) { - state.locks = lockbase(); - - state.updateCollectionMetadata = createCollectionMetadataUpdater(state); - - return tcpocket.createServer({ port, ...tls }, function (request, response) { - request.socket.state = request.socket.state || { - send: response.send, - notifiers: [] - }; - - request.state = request.socket.state; - - const mapping = mappings[request.data[COMMAND]]; - - if (!mapping) { - response.reply({ - [STATUS]: 404 - }); - return; - } - - return mapping(state, request, response) - .catch(error => { - console.log(error); - if (error[STATUS] && error[STATUS] >= 500) { - console.log(error); - } - handleError(request.data[COMMAND], request, response, error); - }); - }); -} - -module.exports = createInternalServer; diff --git a/lib/utils/calculateAllowedErrorCount.js b/lib/utils/calculateAllowedErrorCount.js new file mode 100644 index 0000000..abbce44 --- /dev/null +++ b/lib/utils/calculateAllowedErrorCount.js @@ -0,0 +1,12 @@ +function calculateAllowedErrorCount (replicas, nodeCount) { + if (nodeCount < 1) { + throw new Error('calculateAllowedErrorCount: nodeCount can not be less than 1'); + } + if (nodeCount <= replicas) { + return Math.max(0, nodeCount - 1); + } + + return Math.min(replicas - 1, nodeCount - replicas); +} + +export default calculateAllowedErrorCount; diff --git a/lib/utils/insertDefaultDocument.js b/lib/utils/insertDefaultDocument.js new file mode 100644 index 0000000..6c89a29 --- /dev/null +++ b/lib/utils/insertDefaultDocument.js @@ -0,0 +1,65 @@ +import logslot from 'logslot'; +import waitUntil from './waitUntil.js'; +import c from '../constants.js'; + +const log = logslot('canhazdb.utils.insertDefaultDocument'); + +async function insertDefaultDocument (context, collectionId, document) { + await waitUntil(() => { + return context?.thisNode?.status === 'healthy' || context.closed; + }); + + if (!context?.thisNode?.client) { + throw new Error('no thisNode.connection'); + } + + if (context.closed) { + return; + } + + try { + const client = context.thisNode.client; + + const lockResponse = await client.send(c.LOCK, { + [c.LOCK_KEY]: collectionId, + [c.LOCK_ORIGIN]: context.thisNode.name + }); + const lock = lockResponse.json(); + + const unlock = async () => { + const unlockResponse = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lock[c.LOCK_ID] + }); + + return unlockResponse; + }; + + const existingDocument = await client.send(c.GET, { + [c.COLLECTION_ID]: collectionId, + [c.QUERY]: { + id: document.id + } + }); + + if (existingDocument.json()[c.DATA].length > 0) { + // document already exists + await unlock(); + return; + } + + const insertedDocument = await client.send(c.POST, { + [c.COLLECTION_ID]: collectionId, + [c.DATA]: document, + [c.LOCK_ID]: lock[c.LOCK_ID] + }); + + await unlock(); + } catch (error) { + if (context.closed) { + return; + } + log.warn(`could not insertDefaultDocument "${document.id}" to "${collectionId}`, { error }); + } +} + +export default insertDefaultDocument; diff --git a/lib/utils/isDocumentPrimaryReplica.js b/lib/utils/isDocumentPrimaryReplica.js new file mode 100644 index 0000000..d02deb7 --- /dev/null +++ b/lib/utils/isDocumentPrimaryReplica.js @@ -0,0 +1,15 @@ +function isDocumentPrimaryReplica (context, document) { + const connectedNodes = context.nodes.filter(node => node.status === 'healthy'); + + const availableReplicatedNodes = document._replicatedNodes + .sort() + .filter(nodeName => { + return !!connectedNodes.find(cnode => cnode.name === nodeName); + }); + + if (availableReplicatedNodes[0] === context.thisNode.name) { + return true; + } +} + +export default isDocumentPrimaryReplica; diff --git a/lib/utils/isLockedOrWait.js b/lib/utils/isLockedOrWait.js new file mode 100644 index 0000000..e27dbbb --- /dev/null +++ b/lib/utils/isLockedOrWait.js @@ -0,0 +1,32 @@ +import c from '../constants.js'; + +async function isLockedOrWait (context, socket, key, lockId, waitForUnlock) { + const locked = await context.locks.find(key); + + if (locked.length === 0) { + return false; + } + + if (locked[0].id === lockId) { + return false; + } + + if (waitForUnlock && !lockId) { + await context.locks.wait(key); + return false; + } + + if (waitForUnlock) { + return new Promise(resolve => { + context.locks.on('resolved.' + lockId, () => { + resolve(false); + }); + }); + } + + throw Object.assign( + new Error('canhazdb: locked ' + key.toString()), { status: c.STATUS_LOCKED } + ); +} + +export default isLockedOrWait; diff --git a/lib/utils/join.js b/lib/utils/join.js new file mode 100644 index 0000000..f0974f2 --- /dev/null +++ b/lib/utils/join.js @@ -0,0 +1,86 @@ +import tcpocket from 'tcpocket'; +import logslot from 'logslot'; + +const log = logslot('canhazdb.server'); + +function join (context, host, port) { + port = parseInt(port); + + const servername = context.options.joinFromDns; + + const existingNode = context.nodes.find(node => node.host === host && node.port === port); + if (existingNode) { + return; + } + + log.info('joining node', { host, port }); + + const client = tcpocket.createClient({ + host, + port, + servername, + ...context.options.tls + }); + + const node = { + connected: false, + online: false, + address: `tls://${host}:${port}`, + host, + port, + client + }; + + node.client.on('message', (message) => { + context.emit('node.message', message); + }); + + function handleError (error) { + node.connected = false; + node.online = false; + + if (node.closing || context.closed) { + return; + } + + log.warn('node closed without cause, will reconnect'); + log.debug('node closed', error); + join(context, host, port); + } + + // node.client.on('message', data => { + // logslot('canhazdb.comms').debug('node message received', { data }); + // }); + + node.client.on('connect', () => { + node.connected = true; + context.emit('node.connected', node); + }); + + node.client.on('close', () => { + node.connected = false; + node.online = false; + context.emit('node.disconnected', node); + handleError(Object.assign(new Error('client closed'), { code: 'CLOSED' })); + delete node.client; + }); + + node.client.on('error', handleError); + + context.nodes = context.nodes.filter(i => { + return !(i.host === host && i.port === port); + }); + + node.status = 'unhealthy'; + + node.close = () => { + node.online = false; + node.closing = true; + return node.client && node.client.close(); + }; + + context.nodes.push(node); + context.nodes.sort(); +} + +export default join; diff --git a/lib/utils/onlyOnce.js b/lib/utils/onlyOnce.js new file mode 100644 index 0000000..ff5c4d8 --- /dev/null +++ b/lib/utils/onlyOnce.js @@ -0,0 +1,14 @@ +function onlyOnce (fn) { + let isRunning = false; + + return async (...args) => { + if (isRunning) { + return; + } + isRunning = true; + await fn(...args); + isRunning = false; + }; +} + +export default onlyOnce; diff --git a/utils/orderByFields.js b/lib/utils/orderByFields.js similarity index 78% rename from utils/orderByFields.js rename to lib/utils/orderByFields.js index a879084..883551f 100644 --- a/utils/orderByFields.js +++ b/lib/utils/orderByFields.js @@ -1,3 +1,5 @@ +const matcher = /(desc|asc)\((.*?)\)/g; + function dynamicSort (property, direction = 1) { return function (a, b) { const result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; @@ -5,8 +7,7 @@ function dynamicSort (property, direction = 1) { }; } -function orderByFields (results, order) { - const matcher = /(desc|asc)\((.*?)\)/g; +function orderByFields (order, results) { [...order.matchAll(matcher)] .forEach(field => { const fieldName = field[2]; @@ -15,4 +16,4 @@ function orderByFields (results, order) { }); } -module.exports = orderByFields; +export default orderByFields; diff --git a/lib/utils/selectRandomItemsFromArray.js b/lib/utils/selectRandomItemsFromArray.js new file mode 100644 index 0000000..215b6fc --- /dev/null +++ b/lib/utils/selectRandomItemsFromArray.js @@ -0,0 +1,6 @@ +function selectRandomItemFromArray (array, count) { + const randomArray = [...array].sort(() => 0.5 - Math.random()); + return randomArray.slice(0, count); +} + +export default selectRandomItemFromArray; diff --git a/utils/validateAlphaNumericDashDot.js b/lib/utils/validateAlphaNumericDashDot.js similarity index 77% rename from utils/validateAlphaNumericDashDot.js rename to lib/utils/validateAlphaNumericDashDot.js index 708fea3..be66678 100644 --- a/utils/validateAlphaNumericDashDot.js +++ b/lib/utils/validateAlphaNumericDashDot.js @@ -7,4 +7,4 @@ const validateAlphaNumericDashDot = (value) => { return true; }; -module.exports = validateAlphaNumericDashDot; +export default validateAlphaNumericDashDot; diff --git a/lib/utils/validateRequestData.js b/lib/utils/validateRequestData.js new file mode 100644 index 0000000..839177d --- /dev/null +++ b/lib/utils/validateRequestData.js @@ -0,0 +1,22 @@ +import c from '../constants.js'; + +async function validateRequestData (context, requestData) { + const collectionId = requestData[c.COLLECTION_ID]; + const query = requestData[c.QUERY]; + const fields = requestData[c.FIELDS]; + const order = requestData[c.ORDER]; + const limit = requestData[c.LIMIT]; + + try { + await context.driver.get(collectionId, query, fields, order, limit); + } catch (error) { + throw Object.assign( + new Error('validation failed'), + { + status: c.STATUS_BAD_REQUEST, + error + }); + } +} + +export default validateRequestData; diff --git a/lib/utils/waitUntil.js b/lib/utils/waitUntil.js new file mode 100644 index 0000000..de4235b --- /dev/null +++ b/lib/utils/waitUntil.js @@ -0,0 +1,33 @@ +function waitUntil (fn) { + const initialValue = fn(); + if (initialValue) { + return Promise.resolve(initialValue); + } + + let timer; + let storedResolve; + function attempt (resolve) { + const value = fn(); + + if (value) { + resolve(value); + return; + } + + timer = setTimeout(() => attempt(resolve), 1); + } + + const promise = new Promise((resolve, reject) => { + storedResolve = resolve; + attempt(resolve); + }); + + promise.cancel = () => { + storedResolve(); + clearTimeout(timer); + }; + + return promise; +} + +export default waitUntil; diff --git a/lib/wsHandler.js b/lib/wsHandler.js deleted file mode 100644 index 5dd90fa..0000000 --- a/lib/wsHandler.js +++ /dev/null @@ -1,118 +0,0 @@ -const WebSocket = require('ws'); - -const handlePost = require('./actions/ws/post'); -const handleGetAll = require('./actions/ws/getAll'); - -const { - COMMAND, - DATA, - NOTIFY_ON, - NOTIFY_OFF -} = require('./constants'); - -function askOnAllNodes (state, data) { - return Promise.all( - state.nodes.map(node => node.connection.send(data)) - ); -} - -function wsHandler (server, state, options) { - const wss = new WebSocket.Server({ - server, - verifyClient: options.tls && options.tls.verifyClient - }); - - const listeners = {}; - - state.handleMessage = function (message) { - const triggeredPath = message[3]; - listeners[triggeredPath].forEach(socket => socket.send(JSON.stringify(['T', message]))); - }; - - async function addListener (acceptId, socket, path) { - listeners[path] = listeners[path] || []; - - if (listeners[path].length === 0) { - askOnAllNodes(state, { - [COMMAND]: NOTIFY_ON, - [DATA]: path - }); - } - - const listenerIndex = listeners[path].indexOf(socket); - if (listenerIndex > -1) { - return; - } - - listeners[path].push(socket); - - socket.send(JSON.stringify(['A', acceptId])); - } - - async function removeListener (acceptId, socket, path) { - if (!listeners[path]) { - return; - } - - const listenerIndex = listeners[path].indexOf(socket); - if (listenerIndex > -1) { - listeners[path].splice(listenerIndex, 1); - } - - if (listeners[path].length === 0) { - await askOnAllNodes(state, { - [COMMAND]: NOTIFY_OFF, - [DATA]: path - }); - - delete listeners[path]; - } - - socket.send(JSON.stringify(['A', acceptId])); - } - - wss.on('connection', function connection (socket) { - socket.on('message', function incoming (rawMessage) { - const message = JSON.parse(rawMessage); - const [acceptId, command, data] = message; - - if (command === 'NOTIFY') { - addListener(acceptId, socket, data); - return; - } - - if (command === 'UNNOTIFY') { - removeListener(acceptId, socket, data); - return; - } - - if (command === 'POST') { - handlePost(acceptId, state, data, socket); - - return; - } - - if (command === 'GET') { - handleGetAll(acceptId, state, data, socket); - - return; - } - - socket.send(JSON.stringify(['R', acceptId, 'COMMAND_NOT_FOUND'])); - }); - - socket.on('close', function incoming () { - Object.keys(listeners).forEach(key => { - listeners[key].forEach(listener => { - if (listener[0] === socket) { - removeListener(socket, key); - } - }); - }); - }); - }); - - return wss; -} - -module.exports = wsHandler; diff --git a/package-lock.json b/package-lock.json index b2343ff..7c6b67d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,68 +1,89 @@ { "name": "canhazdb-server", - "version": "7.1.1", + "version": "8.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "canhazdb-server", - "version": "7.1.1", + "version": "8.0.0", "license": "AGPL-3.0", "dependencies": { - "axios": "^0.27.2", - "chalk": "^4.1.1", - "debarrel": "^1.0.1", - "final-stream": "^2.0.3", - "get-port": "^5.1.1", - "hinton": "^1.0.0", - "lockbase": "^1.0.9", - "minimist": "^1.2.5", - "ndjson-fe": "^1.2.7", - "node-ejdb-lite": "^2.73.8", - "qs": "^6.10.1", - "reconnecting-websocket": "^4.4.0", + "@markwylde/liferaft": "^1.2.0", + "chalk": "^5.0.1", + "crypto-random-string": "^5.0.0", + "debarrel": "^1.0.2", + "failmenot": "^3.0.1", + "final-stream": "^2.0.4", + "lockbase": "^5.0.1", + "logslot": "^2.1.1", + "minimist": "^1.2.6", + "mql-to-jql": "^1.4.1", + "node-ejdb-lite": "^2.73.9", + "servatron": "^2.3.1", "server-destroy": "^1.0.1", - "tcpocket": "^5.0.6", - "uuid": "^8.3.2", - "write-response": "^1.2.3", - "ws": "^7.4.6", - "wtfnode": "^0.8.4" - }, - "bin": { - "canhazdb-server": "lib/cli.js" + "tcpocket": "^7.5.2", + "use-http": "^1.0.26", + "uuid": "^8.3.2" }, "devDependencies": { - "basictap": "^1.1.13", - "c8": "^7.7.2", - "canhazdb-driver-ejdb": "^1.1.5", + "@emotion/styled": "^10.3.0", + "axios": "^0.27.2", + "basictap": "^3.4.3", + "c8": "^7.12.0", + "classnames": "^2.3.1", + "esbuild": "^0.15.5", "eslint": "^8.22.0", - "npm": "^8.18.0", - "semistandard": "^16.0.1" + "eslint-plugin-react-hooks": "^4.6.0", + "semistandard": "^16.0.1", + "write-response": "^1.2.3" } }, "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -74,9 +95,8 @@ }, "node_modules/@babel/highlight/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" }, @@ -86,9 +106,8 @@ }, "node_modules/@babel/highlight/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", @@ -100,42 +119,37 @@ }, "node_modules/@babel/highlight/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/@babel/highlight/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 + "dev": true, + "license": "MIT" }, "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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" }, @@ -143,17 +157,197 @@ "node": ">=4" } }, + "node_modules/@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "node_modules/@emotion/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.3.1.tgz", + "integrity": "sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", + "dev": true, + "peer": true, + "dependencies": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "dev": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "dev": true + }, + "node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "dev": true, + "dependencies": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "node_modules/@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", + "dev": true, + "peer": true + }, + "node_modules/@emotion/styled": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", + "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "dev": true, + "dependencies": { + "@emotion/styled-base": "^10.3.0", + "babel-plugin-emotion": "^10.0.27" + }, + "peerDependencies": { + "@emotion/core": "^10.0.27", + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/styled-base": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz", + "integrity": "sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/is-prop-valid": "0.8.8", + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3" + }, + "peerDependencies": { + "@emotion/core": "^10.0.28", + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", + "dev": true, + "peer": true + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "dev": true + }, + "node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", "dev": true }, + "node_modules/@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", + "dev": true, + "peer": true + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -169,11 +363,35 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.17.0", + "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/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -185,9 +403,8 @@ }, "node_modules/@humanwhocodes/gitignore-to-minimatch": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", "dev": true, + "license": "Apache-2.0", "funding": { "type": "github", "url": "https://github.com/sponsors/nzakas" @@ -195,24 +412,62 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "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/resolve-uri": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@markwylde/liferaft": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@markwylde/liferaft/-/liferaft-1.2.0.tgz", + "integrity": "sha512-uPYbOEJgdsqrn7KimmQA9x8ihOQpnzbDQ1foOwMos3s1f4OTCTOFFKeEoREJ9aqA0mC+JFe1DkTc7pRcgURH9w==", + "dependencies": { + "emits": "^3.0.0", + "encoding-down": "^7.1.0", + "eventemitter3": "^4.0.7", + "extendible": "^0.1.1", + "immediate": "^3.3.0", + "leveldown": "^6.1.1", + "levelup": "^5.1.1", + "millisecond": "^0.1.2", + "modification": "^1.0.0", + "one-time": "^1.0.0", + "promise-queue": "^2.2.5", + "tick-tock": "^1.0.0" + } + }, "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" @@ -223,18 +478,16 @@ }, "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" @@ -244,28 +497,40 @@ } }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "version": "2.0.4", + "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 + "dev": true, + "license": "MIT" }, - "node_modules/abbott": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/abbott/-/abbott-1.1.3.tgz", - "integrity": "sha1-JvOtm7vb/+LFa1sDdU5ZgasOXlw=", + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "node_modules/abstract-leveldown": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/acorn": { "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -275,18 +540,16 @@ }, "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/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", @@ -300,26 +563,24 @@ }, "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-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/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" }, @@ -332,15 +593,13 @@ }, "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 + "dev": true, + "license": "Python-2.0" }, "node_modules/array-includes": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -357,23 +616,20 @@ }, "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.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.2.5", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" + "es-abstract": "^1.19.0" }, "engines": { "node": ">= 0.4" @@ -384,9 +640,8 @@ }, "node_modules/array.prototype.flatmap": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", - "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -402,49 +657,109 @@ }, "node_modules/astral-regex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "dev": true, + "license": "MIT" }, "node_modules/axios": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, "dependencies": { "follow-redirects": "^1.14.9", "form-data": "^4.0.0" } }, + "node_modules/babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/serialize": "^0.11.16", + "babel-plugin-macros": "^2.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^1.0.5", + "find-root": "^1.1.0", + "source-map": "^0.5.7" + } + }, + "node_modules/babel-plugin-emotion/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, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "node_modules/babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==", + "dev": true + }, "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 + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "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/basictap": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/basictap/-/basictap-1.1.13.tgz", - "integrity": "sha512-74mw9kmAdmdkHqtP70YFqHMYzO3my92kZA4axHbKI7V7sOUCniiVP1R+0wR7Y5BO4v5wnrt4sMU3nLjlvzTuWw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/basictap/-/basictap-3.4.3.tgz", + "integrity": "sha512-GKSlKn5F4BNUfkuuIQQYNz6/jdqb6teGbRddtIw66MIcyg/9d/oCsRuHSZE4+xfuPtEHnY9ngvysVyNcmtHPuA==", "dev": true, "dependencies": { - "colorette": "^1.2.2", - "concurrun": "^1.1.0", - "righto": "^6.1.3" + "colorette": "^2.0.16", + "events": "^3.3.0", + "promise-limit": "^2.7.0" } }, "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" @@ -452,9 +767,8 @@ }, "node_modules/braces": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -462,26 +776,48 @@ "node": ">=8" } }, - "node_modules/c8": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.7.2.tgz", - "integrity": "sha512-8AqNnUMxB3hsgYCYso2GJjlwnaNPlrEEbYbCQb7N76V1nrOgCKXiTcE3gXU18rIj0FeduPywROrIBMC7XAKApg==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.2", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.0.2", - "rimraf": "^3.0.0", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^7.1.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.7" - }, - "bin": { + "node_modules/buffer": { + "version": "6.0.3", + "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/c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "bin": { "c8": "bin/c8.js" }, "engines": { @@ -490,8 +826,8 @@ }, "node_modules/call-bind": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -502,44 +838,43 @@ }, "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/canhazdb-driver-ejdb": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/canhazdb-driver-ejdb/-/canhazdb-driver-ejdb-1.1.5.tgz", - "integrity": "sha512-NR+cJcPBq8+hUuJyYSRAOKn3MaDeByXCh7cXuRD1Z2SiQ+aOosFoKXXGA3QRDT6W9UgMrd1uEqdC2yu1ri/UtQ==", - "dev": true, + "node_modules/catering": { + "version": "2.1.0", + "license": "MIT", "dependencies": { - "mql-to-jql": "^1.4.1", - "node-ejdb-lite": "^2.73.8", - "uuid": "^8.3.2" + "queue-tick": "^1.0.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==", + "dev": true + }, "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", @@ -548,8 +883,8 @@ }, "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" }, @@ -559,24 +894,19 @@ }, "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/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, - "node_modules/colornames": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" - }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -586,30 +916,37 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/concurrun": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/concurrun/-/concurrun-1.1.0.tgz", - "integrity": "sha512-d6TtuUVtc+zxR/mXiXQLcotv/o5KjKHVADpkz2WAexkGe1nFnv2PP5aAKD+4LP4PLPaZP4wgqdja2yfsCA5YcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.1" } }, + "node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -619,16 +956,35 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-5.0.0.tgz", + "integrity": "sha512-KWjTXWwxFd6a94m5CdRGW/t82Tr8DoBc9dNnPCAbFI1EBweN6v1tv8y4Y1m7ndkp/nkIBRxUxAzpaBnR2k3bcQ==", + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==", + "dev": true + }, "node_modules/debarrel": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debarrel/-/debarrel-1.0.1.tgz", - "integrity": "sha512-0eOJdzuCDb8an9dv/98m3IMicTI5aFlVLz/9ENHADBMea68GFI9grscTOCnvxvKAT1JZtrBPiDahjp91sWOLkw==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/debarrel/-/debarrel-1.0.2.tgz", + "integrity": "sha512-dOGk3xqe786BZg3iZMvs5PCNjMKEDXgfMl9Jpm86rbovkH9ExMWPO4gRL42yLCJ9UTGuO4sKAkEg8T1qiIXX6g==" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.2", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -642,16 +998,25 @@ } }, "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deferred-leveldown": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3" + }, + "engines": { + "node": ">=10" + } }, "node_modules/define-properties": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, + "license": "MIT", "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -665,17 +1030,16 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "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" }, @@ -685,9 +1049,8 @@ }, "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" }, @@ -695,17 +1058,32 @@ "node": ">=6.0.0" } }, + "node_modules/emits": { + "version": "3.0.0", + "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 + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-down": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3", + "level-codec": "^10.0.0", + "level-errors": "^3.0.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/enquirer": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1" }, @@ -715,23 +1093,21 @@ }, "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/error-with-object": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/error-with-object/-/error-with-object-1.1.0.tgz", - "integrity": "sha512-ctthqZF3x2gG1CxAGB+irtAOXGYj7S9r+0flbRGe01qCOU/yJJAyvzOKuR/Locu/8pA1+v9jGDiEKS5ZX6OKDw==" + "dev": true, + "license": "MIT" }, "node_modules/es-abstract": { "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -766,18 +1142,16 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, + "license": "MIT", "dependencies": { "has": "^1.0.3" } }, "node_modules/es-to-primitive": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -790,1203 +1164,1048 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, "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==", + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "node_modules/esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "ajv": "^6.10.0", - "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.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "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.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "node_modules/esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "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==", + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "ms": "^2.1.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "node_modules/esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "node": ">=12" } }, - "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, - "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==", + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" + "node": ">=12" } }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "node_modules/esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "node": ">=12" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/esbuild-linux-64": { + "version": "0.15.5", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "ms": "2.0.0" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "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==", + "node_modules/esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "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==", + "node_modules/esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "cpu": [ + "arm64" + ], "dev": true, - "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" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" + "node": ">=12" } }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" } }, - "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==", + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=12" } }, - "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==", + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "cpu": [ + "riscv64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "node_modules/esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "cpu": [ + "s390x" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "node": ">=12" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "node_modules/esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "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==", + "node_modules/esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "cpu": [ + "ia32" + ], "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.10" + "node": ">=12" } }, - "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==", + "node_modules/esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/escalade": { + "version": "3.1.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">=6" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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 - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "node_modules/eslint": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", + "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", "dev": true, "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.4" - }, - "engines": { - "node": ">=8.6.0" + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "ajv": "^6.10.0", + "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.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.3", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "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.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "debug": "^3.2.7", + "resolve": "^1.20.0" } }, - "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 - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", "dev": true, + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "ms": "^2.1.1" } }, - "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==", + "node_modules/eslint-module-utils": { + "version": "2.7.1", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "debug": "^3.2.7", + "find-up": "^2.1.0", + "pkg-dir": "^2.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=4" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", "dev": true, + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" + "ms": "^2.1.1" } }, - "node_modules/final-stream": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/final-stream/-/final-stream-2.0.3.tgz", - "integrity": "sha512-THH/DnlYuhWQZBm7vPpavIlLV2hKh3HFMiLORz7kr+CxrbgbG33BP22RWtAn4EmN8OGfGttWcued3xluCA6p9g==" - }, - "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==", + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "locate-path": "^2.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=4" } }, - "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "engines": { + "node": ">=4" } }, - "node_modules/foreground-child": { + "node_modules/eslint-module-utils/node_modules/p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "p-limit": "^1.1.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=4" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=4" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "node_modules/eslint-plugin-es": { + "version": "3.0.1", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8.10.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "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, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "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==", + "node_modules/eslint-plugin-import": { + "version": "2.25.2", "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.0", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "is-core-module": "^2.7.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", "engines": { - "node": ">=8" + "node": ">=4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", "dev": true, + "license": "Apache-2.0", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "esutils": "^2.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", + "license": "MIT" + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "engines": { - "node": "*" + "node": ">=8.10.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "eslint": ">=5.16.0" } }, - "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==", + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, "engines": { - "node": ">=10.13.0" + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "node_modules/eslint-scope": { + "version": "7.1.1", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "type-fest": "^0.20.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/eslint-utils": { + "version": "2.1.0", "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" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4.0" + "node": ">=4" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "node_modules/eslint/node_modules/eslint-utils": { + "version": "3.0.0", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hex-rgb": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz", - "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==", - "engines": { - "node": ">=6" + "url": "https://github.com/sponsors/mysticatea" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hinton": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hinton/-/hinton-1.0.0.tgz", - "integrity": "sha512-92PiCRxSvcHLB+5f4w29Ex7EWC7/AVok3Zg84X8K+NCtrMmACh0UR7ZgQfos0/xGdc+vPcY4ak7ijaWhluUj8A==", - "dependencies": { - "chalk": "^4.1.0", - "string-to-color": "^2.2.2" + "peerDependencies": { + "eslint": ">=5" } }, - "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 - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 4" + "node": ">=10" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/eslint/node_modules/globals": { + "version": "13.17.0", "dev": true, + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "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 - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/espree": { + "version": "9.3.3", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "node_modules/esprima": { + "version": "4.0.1", "dev": true, - "engines": { - "node": ">= 0.4" + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "node_modules/esquery": { + "version": "1.4.0", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "has": "^1.0.3" + "estraverse": "^5.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/esrecurse": { + "version": "4.3.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "has-tostringtag": "^1.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/estraverse": { + "version": "5.3.0", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=4.0" } }, - "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==", + "node_modules/esutils": { + "version": "2.0.3", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "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==", + "node_modules/eventemitter3": { + "version": "4.0.7", + "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, - "dependencies": { - "is-extglob": "^2.1.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.8.x" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "node_modules/extendible": { + "version": "0.1.1", + "license": "MIT" + }, + "node_modules/failmenot": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/failmenot/-/failmenot-3.0.1.tgz", + "integrity": "sha512-nFgVwPKWp76fLN8HQwJ0g9HnNXnmgx+jC1LGaRzoTaP4JwMcWhQHmDr8EPQJSu+E7gPEcQIqcet2ANNuZhzuNw==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "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==", + "node_modules/fast-glob": { + "version": "3.2.11", "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.4" + }, "engines": { - "node": ">=0.12.0" + "node": ">=8.6.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", "dev": true, + "license": "ISC", "dependencies": { - "has-tostringtag": "^1.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.13.0", "dev": true, + "license": "ISC", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "reusify": "^1.0.4" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "node_modules/file-entry-cache": { + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "flat-cache": "^3.0.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/fill-range": { + "version": "7.0.1", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/final-stream": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/final-stream/-/final-stream-2.0.4.tgz", + "integrity": "sha512-kBaHWwbW2oRFp1WZeY28QrCwv5yJVJTO/tPHYIWLs3ezd2DvCXrBayqgG096tJPqZhUaCM/y1439LkAjnr7xaA==" + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "node_modules/find-up": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/flat-cache": { + "version": "3.0.4", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "node_modules/flatted": { + "version": "3.2.2", + "dev": true, + "license": "ISC" }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "node_modules/fn.name": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.1", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "node_modules/foreground-child": { + "version": "2.0.0", "dev": true, + "license": "ISC", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=8.0.0" } }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "node_modules/form-data": { + "version": "4.0.0", "dev": true, + "license": "MIT", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "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 + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" }, - "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==", + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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 - }, - "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 - }, - "node_modules/json-stable-stringify-without-jsonify": { + "node_modules/functional-red-black-tree": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "node_modules/functions-have-names": { + "version": "1.2.3", "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "node_modules/get-caller-file": { + "version": "2.0.5", "dev": true, - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, + "license": "ISC", "engines": { - "node": ">=4.0" + "node": "6.* || 8.* || >= 10.*" } }, - "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==", + "node_modules/get-intrinsic": { + "version": "1.1.1", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/get-stdin": { + "version": "8.0.0", "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1994,2372 +2213,1837 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lockbase": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/lockbase/-/lockbase-1.0.9.tgz", - "integrity": "sha512-6UYmTjzPSZcoAj2DNlmz6J8uXYD5UcIlu3JXcx6FJoFCZbjQ5n78WfQ4CVQebRpL704MXCIOV00Kn1QzuS2zyQ==", + "node_modules/get-symbol-description": { + "version": "1.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "uuid": "^8.3.1" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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 - }, - "node_modules/lodash.padend": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", - "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=" - }, - "node_modules/lodash.trimstart": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/lodash.trimstart/-/lodash.trimstart-4.5.1.tgz", - "integrity": "sha1-j/TexTLYJIavWVc8OURZFOlEp/E=" - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "node_modules/lodash.words": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.words/-/lodash.words-4.2.0.tgz", - "integrity": "sha1-Xs/q+Oz4rKqODIOGKV8Zk8nPQDY=" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/glob": { + "version": "7.2.0", "dev": true, + "license": "ISC", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "bin": { - "loose-envify": "cli.js" + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "node_modules/glob-parent": { + "version": "6.0.2", "dev": true, + "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=10" + "node": ">=10.13.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==", + "node_modules/globby": { + "version": "11.1.0", "dev": true, + "license": "MIT", "dependencies": { - "semver": "^6.0.0" + "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": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/graceful-fs": { + "version": "4.2.8", "dev": true, - "engines": { - "node": ">= 8" - } + "license": "ISC" }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/has": { + "version": "1.0.3", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "function-bind": "^1.1.1" }, "engines": { - "node": ">=8.6" + "node": ">= 0.4.0" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/has-bigints": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "get-intrinsic": "^1.1.1" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/has-tostringtag": { + "version": "1.0.0", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "has-symbols": "^1.0.2" }, "engines": { - "node": "*" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "node_modules/mql-to-jql": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mql-to-jql/-/mql-to-jql-1.4.1.tgz", - "integrity": "sha512-FBACw40CNcOn2eoR2E3NJolu8J4zsp592D1/xpgU7yufxd/5219Bk02S7Hfo4jfT0pFxcT4EuRFbmmnmRXg+YA==", - "dev": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "node_modules/ieee754": { + "version": "1.2.1", + "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/ndjson-fe": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/ndjson-fe/-/ndjson-fe-1.2.10.tgz", - "integrity": "sha512-KUnVQdm+kWJt/2HhiBmZ4EhzliHWXH6GglJDVZrrF8vr8ps2sBVFzijcz/jsXm7P9ji4lWWU3X1D1RZp0F6lWA==", + "node_modules/ignore": { + "version": "5.2.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 4" } }, - "node_modules/node-ejdb-lite": { - "version": "2.73.8", - "resolved": "https://registry.npmjs.org/node-ejdb-lite/-/node-ejdb-lite-2.73.8.tgz", - "integrity": "sha512-6YptAKZlkVB7ks3zWqagrZyDSEyDgwWIdwiBuAVzbbRyA1a9E8moDFt5EBOvGKo3VGflrYGjDrJNnj4ut+5H5Q==", - "cpu": [ - "x64", - "x32", - "arm", - "arm64" - ], - "hasInstallScript": true, - "os": [ - "darwin", - "linux", - "alpine", - "!win32" - ], - "engines": { - "node": ">=10.0.0", - "npm": ">=6.0.0" - } + "node_modules/immediate": { + "version": "3.3.0", + "license": "MIT" }, - "node_modules/npm": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-8.18.0.tgz", - "integrity": "sha512-G07/yKvNUwhwxYhk8BxcuDPB/4s+y755i6CnH3lf9LQBHP5siUx66WbuNGWEnN3xaBER4+IR3OWApKX7eBO5Dw==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/ci-detect", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/run-script", - "abbrev", - "archy", - "cacache", - "chalk", - "chownr", - "cli-columns", - "cli-table3", - "columnify", - "fastest-levenshtein", - "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", - "minipass", - "minipass-pipeline", - "mkdirp", - "mkdirp-infer-owner", - "ms", - "node-gyp", - "nopt", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "npmlog", - "opener", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "read-package-json", - "read-package-json-fast", - "readdir-scoped-modules", - "rimraf", - "semver", - "ssri", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which", - "write-file-atomic" - ], + "node_modules/import-fresh": { + "version": "3.3.0", "dev": true, + "license": "MIT", "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^5.0.4", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/config": "^4.2.1", - "@npmcli/fs": "^2.1.0", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/package-json": "^2.0.0", - "@npmcli/run-script": "^4.2.1", - "abbrev": "~1.1.1", - "archy": "~1.0.0", - "cacache": "^16.1.1", - "chalk": "^4.1.2", - "chownr": "^2.0.0", - "cli-columns": "^4.0.0", - "cli-table3": "^0.6.2", - "columnify": "^1.6.0", - "fastest-levenshtein": "^1.0.12", - "glob": "^8.0.1", - "graceful-fs": "^4.2.10", - "hosted-git-info": "^5.0.0", - "ini": "^3.0.0", - "init-package-json": "^3.0.2", - "is-cidr": "^4.0.2", - "json-parse-even-better-errors": "^2.3.1", - "libnpmaccess": "^6.0.2", - "libnpmdiff": "^4.0.2", - "libnpmexec": "^4.0.2", - "libnpmfund": "^3.0.1", - "libnpmhook": "^8.0.2", - "libnpmorg": "^4.0.2", - "libnpmpack": "^4.0.2", - "libnpmpublish": "^6.0.2", - "libnpmsearch": "^5.0.2", - "libnpmteam": "^4.0.2", - "libnpmversion": "^3.0.1", - "make-fetch-happen": "^10.2.0", - "minipass": "^3.1.6", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "ms": "^2.1.2", - "node-gyp": "^9.1.0", - "nopt": "^6.0.0", - "npm-audit-report": "^3.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.1.0", - "npm-pick-manifest": "^7.0.1", - "npm-profile": "^6.2.0", - "npm-registry-fetch": "^13.3.1", - "npm-user-validate": "^1.0.1", - "npmlog": "^6.0.2", - "opener": "^1.5.2", - "p-map": "^4.0.0", - "pacote": "^13.6.2", - "parse-conflict-json": "^2.0.2", - "proc-log": "^2.0.1", - "qrcode-terminal": "^0.12.0", - "read": "~1.0.7", - "read-package-json": "^5.0.1", - "read-package-json-fast": "^2.0.3", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.1", - "tar": "^6.1.11", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^2.0.0", - "validate-npm-package-name": "^4.0.0", - "which": "^2.0.2", - "write-file-atomic": "^4.0.1" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/@colors/colors": { - "version": "1.5.0", + "node_modules/imurmurhash": { + "version": "0.1.4", "dev": true, - "inBundle": true, "license": "MIT", - "optional": true, "engines": { - "node": ">=0.1.90" + "node": ">=0.8.19" } }, - "node_modules/npm/node_modules/@gar/promisify": { - "version": "1.1.3", - "dev": true, - "inBundle": true, + "node_modules/increlation": { + "version": "2.0.1", "license": "MIT" }, - "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/arborist": { - "version": "5.6.0", + "node_modules/inflight": { + "version": "1.0.6", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", - "@npmcli/move-file": "^2.0.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.1.1", - "@npmcli/run-script": "^4.1.3", - "bin-links": "^3.0.0", - "cacache": "^16.0.6", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "minimatch": "^5.1.0", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.0.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.0", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.1", - "proc-log": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.0", - "treeverse": "^2.0.0", - "walk-up-path": "^1.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/npm/node_modules/@npmcli/ci-detect": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "4.2.1", + "node_modules/internal-slot": { + "version": "1.0.3", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/map-workspaces": "^2.0.2", - "ini": "^3.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "proc-log": "^2.0.0", - "read-package-json-fast": "^2.0.3", - "semver": "^7.3.5", - "walk-up-path": "^1.0.0" + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" } }, - "node_modules/npm/node_modules/@npmcli/disparity-colors": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "ansi-styles": "^4.3.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "2.1.2", + "node_modules/is-bigint": { + "version": "1.0.4", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" + "has-bigints": "^1.0.1" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "3.0.2", + "node_modules/is-boolean-object": { + "version": "1.1.2", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/promise-spawn": "^3.0.0", - "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^7.0.0", - "proc-log": "^2.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" - }, + "node_modules/is-buffer": { + "version": "2.0.5", + "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": ">= 10" + "node": ">=4" } }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "2.0.4", + "node_modules/is-callable": { + "version": "1.2.4", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^8.0.1", - "minimatch": "^5.0.1", - "read-package-json-fast": "^2.0.3" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "3.1.1", + "node_modules/is-core-module": { + "version": "2.8.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "cacache": "^16.0.0", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", - "semver": "^7.3.5" + "has": "^1.0.3" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/move-file": { - "version": "2.0.1", + "node_modules/is-date-object": { + "version": "1.0.5", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", + "node_modules/is-extglob": { + "version": "2.1.1", "dev": true, - "inBundle": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "2.0.0", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "2.0.0", + "node_modules/is-glob": { + "version": "4.0.3", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "json-parse-even-better-errors": "^2.3.1" + "is-extglob": "^2.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "3.0.0", + "node_modules/is-negative-zero": { + "version": "2.0.2", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "infer-owner": "^1.0.4" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/query": { - "version": "1.1.1", + "node_modules/is-number": { + "version": "7.0.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^9.1.0", - "postcss-selector-parser": "^6.0.10", - "semver": "^7.3.7" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.12.0" } }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "4.2.1", + "node_modules/is-number-object": { + "version": "1.0.7", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/promise-spawn": "^3.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^2.0.3", - "which": "^2.0.2" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@tootallnate/once": { - "version": "2.0.0", + "node_modules/is-regex": { + "version": "1.1.4", "dev": true, - "inBundle": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, "engines": { - "node": ">= 10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/abbrev": { - "version": "1.1.1", + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", "dev": true, - "inBundle": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/npm/node_modules/agent-base": { - "version": "6.0.2", + "node_modules/is-string": { + "version": "1.0.7", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "debug": "4" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/agentkeepalive": { - "version": "4.2.1", + "node_modules/is-symbol": { + "version": "1.0.4", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" + "has-symbols": "^1.0.2" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/aggregate-error": { - "version": "3.1.0", + "node_modules/is-weakref": { + "version": "1.0.2", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/isexe": { + "version": "2.0.0", "dev": true, - "inBundle": true, - "license": "MIT", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/istanbul-lib-report": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "color-convert": "^2.0.1" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm/node_modules/aproba": { - "version": "2.0.0", + "node_modules/istanbul-reports": { + "version": "3.1.5", "dev": true, - "inBundle": true, - "license": "ISC" + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "dev": true, - "inBundle": true, + "node_modules/js-tokens": { + "version": "4.0.0", "license": "MIT" }, - "node_modules/npm/node_modules/are-we-there-yet": { - "version": "3.0.1", + "node_modules/js-yaml": { + "version": "4.1.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "argparse": "^2.0.1" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/npm/node_modules/asap": { - "version": "2.0.6", + "node_modules/json-parse-better-errors": { + "version": "1.0.2", "dev": true, - "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", + "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 + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", "dev": true, - "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/bin-links": { - "version": "3.0.2", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.2", + "dev": true, + "license": "MIT", "dependencies": { - "cmd-shim": "^5.0.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^3.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" + "array-includes": "^3.1.5", + "object.assign": "^4.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4.0" } }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "2.2.0", - "dev": true, - "inBundle": true, + "node_modules/level-codec": { + "version": "10.0.0", "license": "MIT", + "dependencies": { + "buffer": "^6.0.3" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "inBundle": true, + "node_modules/level-concat-iterator": { + "version": "3.0.0", "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": ">=10" } }, - "node_modules/npm/node_modules/builtins": { - "version": "5.0.1", - "dev": true, - "inBundle": true, + "node_modules/level-errors": { + "version": "3.0.1", "license": "MIT", - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "16.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^1.1.1" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" } }, - "node_modules/npm/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "inBundle": true, + "node_modules/level-iterator-stream": { + "version": "5.0.0", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" }, "engines": { "node": ">=10" - }, - "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", + "node_modules/level-supports": { + "version": "2.0.2", + "license": "MIT", "engines": { "node": ">=10" } }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", + "node_modules/leveldown": { + "version": "6.1.1", + "hasInstallScript": true, + "license": "MIT", "dependencies": { - "ip-regex": "^4.1.0" + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" }, "engines": { - "node": ">=10" + "node": ">=10.12.0" } }, - "node_modules/npm/node_modules/clean-stack": { - "version": "2.2.0", - "dev": true, - "inBundle": true, + "node_modules/levelup": { + "version": "5.1.1", "license": "MIT", + "dependencies": { + "catering": "^2.0.0", + "deferred-leveldown": "^7.0.0", + "level-errors": "^3.0.1", + "level-iterator-stream": "^5.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", + "node_modules/levn": { + "version": "0.4.1", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">= 10" + "node": ">= 0.8.0" } }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.2", + "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 + }, + "node_modules/load-json-file": { + "version": "5.3.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "string-width": "^4.2.0" + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" }, "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/clone": { - "version": "1.0.4", + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", "dev": true, - "inBundle": true, "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, "engines": { - "node": ">=0.8" + "node": ">=4" } }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "5.0.0", + "node_modules/load-json-file/node_modules/type-fest": { + "version": "0.3.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "mkdirp-infer-owner": "^2.0.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", + "node_modules/locate-path": { + "version": "6.0.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", + "node_modules/lockbase": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/lockbase/-/lockbase-5.0.1.tgz", + "integrity": "sha512-JbQF2eJFAEJPo341Et6sIyTxflop8q/h7gHE7px1OcI6B5ctdwgYpGSiNbdciFkCNKHXNK+b8zHJU5hXsL87eA==", + "dependencies": { + "uuid": "^8.3.2" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", "dev": true, - "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/color-support": { - "version": "1.1.3", + "node_modules/lodash.truncate": { + "version": "4.4.2", "dev": true, - "inBundle": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" + "license": "MIT" + }, + "node_modules/logslot": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/logslot/-/logslot-2.1.1.tgz", + "integrity": "sha512-IvnKXlw+tXBnguDdmpyHRdiUzoG86s8EXsAYP6TkSICEwiFTcT0VwiGV7eT20TCHTf7XsYzRXdWlkyge29j7bQ==", + "dependencies": { + "chalk": "^5.0.1" } }, - "node_modules/npm/node_modules/columnify": { - "version": "1.6.0", - "dev": true, - "inBundle": true, + "node_modules/loose-envify": { + "version": "1.4.0", "license": "MIT", "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" }, - "engines": { - "node": ">=8.0.0" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/console-control-strings": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", + "node_modules/lru-cache": { + "version": "6.0.0", "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/npm/node_modules/debug": { - "version": "4.3.4", + "node_modules/make-dir": { + "version": "3.1.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "semver": "^6.0.0" }, "engines": { - "node": ">=6.0" + "node": ">=8" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/debuglog": { - "version": "1.0.1", + "node_modules/merge2": { + "version": "1.4.1", "dev": true, - "inBundle": true, "license": "MIT", "engines": { - "node": "*" + "node": ">= 8" } }, - "node_modules/npm/node_modules/defaults": { - "version": "1.0.3", + "node_modules/micromatch": { + "version": "4.0.5", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "clone": "^1.0.2" + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "node_modules/npm/node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "inBundle": true, + "node_modules/millisecond": { + "version": "0.1.2", "license": "MIT" }, - "node_modules/npm/node_modules/depd": { - "version": "1.1.2", - "dev": true, - "inBundle": true, + "node_modules/mime": { + "version": "3.0.0", "license": "MIT", + "bin": { + "mime": "cli.js" + }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/dezalgo": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" + "node": ">=10.0.0" } }, - "node_modules/npm/node_modules/diff": { - "version": "5.0.0", + "node_modules/mime-db": { + "version": "1.52.0", "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.3.1" + "node": ">= 0.6" } }, - "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", + "node_modules/mime-types": { + "version": "2.1.35", "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", + "mime-db": "1.52.0" + }, "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.12", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/minimatch": { + "version": "3.1.2", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 8" + "node": "*" } }, - "node_modules/npm/node_modules/fs.realpath": { + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/modification": { "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.1", + "node_modules/mql-to-jql": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mql-to-jql/-/mql-to-jql-1.4.1.tgz", + "integrity": "sha512-FBACw40CNcOn2eoR2E3NJolu8J4zsp592D1/xpgU7yufxd/5219Bk02S7Hfo4jfT0pFxcT4EuRFbmmnmRXg+YA==" + }, + "node_modules/ms": { + "version": "2.1.2", "dev": true, - "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/gauge": { - "version": "4.0.4", + "node_modules/napi-macros": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, + "license": "MIT" + }, + "node_modules/node-ejdb-lite": { + "version": "2.73.9", + "resolved": "https://registry.npmjs.org/node-ejdb-lite/-/node-ejdb-lite-2.73.9.tgz", + "integrity": "sha512-ND5a12zfR+Wq1mBWQe/uy48UbyJpFMzI9t+eAuGqPr4JQ/bLrbUdk2b/pUkLGt5lMWfXXS1sELka5z+7ZYGWzw==", + "cpu": [ + "x64", + "x32", + "arm", + "arm64" + ], + "hasInstallScript": true, + "os": [ + "darwin", + "linux", + "alpine", + "!win32" + ], "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10.0.0", + "npm": ">=6.0.0" } }, - "node_modules/npm/node_modules/glob": { - "version": "8.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node_modules/node-gyp-build": { + "version": "4.5.0", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.10", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/has": { - "version": "1.0.3", - "dev": true, - "inBundle": true, + "node_modules/object-assign": { + "version": "4.1.1", "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, "engines": { - "node": ">= 0.4.0" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/has-flag": { - "version": "4.0.0", + "node_modules/object-inspect": { + "version": "1.12.2", "dev": true, - "inBundle": true, "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/has-unicode": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "5.0.0", + "node_modules/object-keys": { + "version": "1.1.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^7.5.1" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">= 0.4" } }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "5.0.0", + "node_modules/object.assign": { + "version": "4.1.2", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "5.0.1", + "node_modules/object.entries": { + "version": "1.1.5", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "agent-base": "6", - "debug": "4" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" } }, - "node_modules/npm/node_modules/humanize-ms": { - "version": "1.2.1", + "node_modules/object.fromentries": { + "version": "2.0.5", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "ms": "^2.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", + "node_modules/object.values": { + "version": "1.1.5", "dev": true, - "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "5.0.1", + "node_modules/once": { + "version": "1.4.0", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { - "minimatch": "^5.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "wrappy": "1" } }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "inBundle": true, + "node_modules/one-time": { + "version": "1.0.0", "license": "MIT", - "engines": { - "node": ">=0.8.19" + "dependencies": { + "fn.name": "1.x.x" } }, - "node_modules/npm/node_modules/indent-string": { - "version": "4.0.0", + "node_modules/optionator": { + "version": "0.9.1", "dev": true, - "inBundle": 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.3" + }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/npm/node_modules/infer-owner": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/inflight": { - "version": "1.0.6", + "node_modules/p-limit": { + "version": "3.1.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/ini": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", + "yocto-queue": "^0.1.0" + }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/init-package-json": { - "version": "3.0.2", + "node_modules/p-locate": { + "version": "5.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "npm-package-arg": "^9.0.1", - "promzard": "^0.3.0", - "read": "^1.0.7", - "read-package-json": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^4.0.0" + "p-limit": "^3.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/ip": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "4.3.0", + "node_modules/p-try": { + "version": "1.0.0", "dev": true, - "inBundle": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/npm/node_modules/is-cidr": { - "version": "4.0.2", + "node_modules/parent-module": { + "version": "1.0.1", "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "cidr-regex": "^3.1.1" + "callsites": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/npm/node_modules/is-core-module": { - "version": "2.10.0", + "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, - "inBundle": true, - "license": "MIT", "dependencies": { - "has": "^1.0.3" + "@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/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/path-exists": { + "version": "4.0.0", "dev": true, - "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/npm/node_modules/is-lambda": { + "node_modules/path-is-absolute": { "version": "1.0.1", "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "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" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", + "node_modules/path-key": { + "version": "3.1.1", "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/npm/node_modules/just-diff": { - "version": "5.1.1", + "node_modules/path-parse": { + "version": "1.0.7", "dev": true, - "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "5.4.1", + "node_modules/path-type": { + "version": "4.0.0", "dev": true, - "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "6.0.3", + "node_modules/picomatch": { + "version": "2.3.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "4.0.4", + "node_modules/pify": { + "version": "4.0.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/disparity-colors": "^2.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^5.0.1", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1", - "tar": "^6.1.0" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "4.0.11", + "node_modules/pkg-conf": { + "version": "3.1.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/arborist": "^5.0.0", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/fs": "^2.1.1", - "@npmcli/run-script": "^4.2.0", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^9.0.1", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "proc-log": "^2.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "semver": "^7.3.7", - "walk-up-path": "^1.0.0" + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "3.0.2", + "node_modules/pkg-conf/node_modules/find-up": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/arborist": "^5.0.0" + "locate-path": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "8.0.3", + "node_modules/pkg-conf/node_modules/locate-path": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "4.0.3", + "node_modules/pkg-conf/node_modules/p-limit": { + "version": "2.3.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "4.1.2", + "node_modules/pkg-conf/node_modules/p-locate": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/run-script": "^4.1.3", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1" + "p-limit": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "6.0.4", + "node_modules/pkg-conf/node_modules/p-try": { + "version": "2.2.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "normalize-package-data": "^4.0.0", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0", - "semver": "^7.3.7", - "ssri": "^9.0.0" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=6" } }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "5.0.3", + "node_modules/pkg-conf/node_modules/path-exists": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^13.0.0" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "4.0.3", + "node_modules/pkg-dir": { + "version": "2.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" + "find-up": "^2.1.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "3.0.6", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "2.1.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/git": "^3.0.0", - "@npmcli/run-script": "^4.1.3", - "json-parse-even-better-errors": "^2.3.1", - "proc-log": "^2.0.0", - "semver": "^7.3.7" + "locate-path": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "7.13.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "10.2.1", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "2.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/npm/node_modules/minimatch": { - "version": "5.1.0", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "1.3.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "p-try": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/npm/node_modules/minipass": { - "version": "3.3.4", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "2.0.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "p-limit": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "1.0.2", + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=4" } }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "2.1.1", + "node_modules/prelude-ls": { + "version": "1.2.1", "dev": true, - "inBundle": true, "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" + "node": ">= 0.8.0" } }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", + "node_modules/progress": { + "version": "2.0.3", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=0.4.0" } }, - "node_modules/npm/node_modules/minipass-json-stream": { - "version": "1.0.1", - "dev": true, - "inBundle": true, + "node_modules/promise-limit": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", + "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==", + "dev": true + }, + "node_modules/promise-queue": { + "version": "2.2.5", "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", + "node_modules/prop-types": { + "version": "15.8.1", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", + "node_modules/punycode": { + "version": "2.1.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/npm/node_modules/minizlib": { - "version": "2.1.2", - "dev": true, - "inBundle": true, + "node_modules/queue-microtask": { + "version": "1.2.3", + "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/queue-tick": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/react": { + "version": "17.0.2", "license": "MIT", + "peer": true, "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "inBundle": true, + "node_modules/react-dom": { + "version": "17.0.2", "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "react": "17.0.2" } }, - "node_modules/npm/node_modules/mkdirp-infer-owner": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.20.2", + "license": "MIT", + "peer": true, "dependencies": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - }, - "engines": { - "node": ">=10" + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" } }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", + "node_modules/react-is": { + "version": "16.13.1", "dev": true, - "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/mute-stream": { - "version": "0.0.8", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/negotiator": { - "version": "0.6.3", - "dev": true, - "inBundle": true, + "node_modules/readable-stream": { + "version": "3.6.0", "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, "engines": { - "node": ">= 0.6" + "node": ">= 6" } }, - "node_modules/npm/node_modules/node-gyp": { - "version": "9.1.0", + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { - "node": "^12.22 || ^14.13 || >=16" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/regexpp": { + "version": "3.2.0", "dev": true, - "inBundle": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "inBundle": 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": "*" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/require-directory": { + "version": "2.1.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { - "version": "5.0.0", + "node_modules/require-from-string": { + "version": "2.0.2", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/nopt": { - "version": "6.0.0", + "node_modules/resolve": { + "version": "1.20.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "4.0.1", + "node_modules/resolve-from": { + "version": "4.0.0", "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "3.0.0", + "node_modules/reusify": { + "version": "1.0.4", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chalk": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "1.1.2", + "node_modules/rimraf": { + "version": "3.0.2", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" + "glob": "^7.1.3" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "9.1.0", + "node_modules/run-parallel": { + "version": "1.2.0", "dev": true, - "inBundle": true, - "license": "ISC", + "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": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "5.1.1", + "node_modules/safe-buffer": { + "version": "5.1.2", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/semistandard": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/semistandard/-/semistandard-16.0.1.tgz", + "integrity": "sha512-ApAJ9fMAIwYuk5xI2HWSCd8s5o5L95abxU4dYl6ovUX6Rcww/7oxtaSuu9wLFL/Gfj/EXx1h6S4itXy5vyL60Q==", + "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" + } + ], "dependencies": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^1.1.2", - "npm-normalize-package-bin": "^1.0.1" + "eslint": "^7.27.0", + "eslint-config-semistandard": "16.0.0", + "eslint-config-standard": "16.0.3", + "eslint-config-standard-jsx": "10.0.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^5.1.0", + "eslint-plugin-react": "~7.21.5", + "standard-engine": "^14.0.0" }, "bin": { - "npm-packlist": "bin/index.js" + "semistandard": "bin/cmd.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10.12.0" } }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "7.0.1", + "node_modules/semistandard/node_modules/@babel/code-frame": { + "version": "7.12.11", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^9.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@babel/highlight": "^7.10.4" } }, - "node_modules/npm/node_modules/npm-profile": { - "version": "6.2.1", + "node_modules/semistandard/node_modules/@eslint/eslintrc": { + "version": "0.4.3", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0" + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "13.3.1", + "node_modules/semistandard/node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "make-fetch-happen": "^10.0.6", - "minipass": "^3.1.6", - "minipass-fetch": "^2.0.3", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.1", - "proc-log": "^2.0.0" + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10.10.0" } }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/npmlog": { - "version": "6.0.2", + "node_modules/semistandard/node_modules/acorn": { + "version": "7.4.1", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.4.0" } }, - "node_modules/npm/node_modules/once": { - "version": "1.4.0", + "node_modules/semistandard/node_modules/argparse": { + "version": "1.0.10", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/opener": { - "version": "1.5.2", - "dev": true, - "inBundle": true, - "license": "(WTFPL OR MIT)", - "bin": { - "opener": "bin/opener-bin.js" + "sprintf-js": "~1.0.2" } }, - "node_modules/npm/node_modules/p-map": { - "version": "4.0.0", + "node_modules/semistandard/node_modules/chalk": { + "version": "4.1.2", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "aggregate-error": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/npm/node_modules/pacote": { - "version": "13.6.2", + "node_modules/semistandard/node_modules/eslint": { + "version": "7.32.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/git": "^3.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/run-script": "^4.1.0", - "cacache": "^16.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.6", - "mkdirp": "^1.0.4", - "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^5.0.0", - "read-package-json-fast": "^2.0.3", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11" + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "bin": { - "pacote": "lib/bin.js" + "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "2.0.2", + "node_modules/semistandard/node_modules/eslint-config-semistandard": { + "version": "16.0.0", "dev": true, - "inBundle": true, "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "peerDependencies": { + "eslint": ">=7.12.1", + "eslint-config-standard": ">=16.0.3", + "eslint-plugin-import": ">=2.22.1", + "eslint-plugin-node": ">=11.1.0", + "eslint-plugin-promise": ">=4.2.1" } }, - "node_modules/npm/node_modules/path-is-absolute": { - "version": "1.0.1", + "node_modules/semistandard/node_modules/eslint-config-standard": { + "version": "16.0.3", "dev": true, - "inBundle": 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": ">=0.10.0" + "peerDependencies": { + "eslint": "^7.12.1", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1 || ^5.0.0" } }, - "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.0.10", + "node_modules/semistandard/node_modules/eslint-config-standard-jsx": { + "version": "10.0.0", "dev": true, - "inBundle": 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": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "peerDependencies": { + "eslint": "^7.12.1", + "eslint-plugin-react": "^7.21.5" } }, - "node_modules/npm/node_modules/proc-log": { - "version": "2.0.1", + "node_modules/semistandard/node_modules/eslint-plugin-promise": { + "version": "5.2.0", "dev": true, - "inBundle": true, "license": "ISC", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.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": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0" } }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.1", + "node_modules/semistandard/node_modules/eslint-plugin-react": { + "version": "7.21.5", "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" + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" }, "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "0.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "1" - } - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" } }, - "node_modules/npm/node_modules/read": { - "version": "1.0.7", + "node_modules/semistandard/node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "mute-stream": "~0.0.4" + "esutils": "^2.0.2" }, "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/read-package-json": { - "version": "5.0.1", + "node_modules/semistandard/node_modules/eslint-scope": { + "version": "5.1.1", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "BSD-2-Clause", "dependencies": { - "glob": "^8.0.1", - "json-parse-even-better-errors": "^2.3.1", - "normalize-package-data": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8.0.0" } }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "2.0.3", + "node_modules/semistandard/node_modules/eslint-visitor-keys": { + "version": "2.1.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, + "license": "Apache-2.0", "engines": { "node": ">=10" } }, - "node_modules/npm/node_modules/readable-stream": { - "version": "3.6.0", + "node_modules/semistandard/node_modules/espree": { + "version": "7.3.1", "dev": true, - "inBundle": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/npm/node_modules/readdir-scoped-modules": { - "version": "1.1.0", + "node_modules/semistandard/node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" + "license": "Apache-2.0", + "engines": { + "node": ">=4" } }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", + "node_modules/semistandard/node_modules/estraverse": { + "version": "4.3.0", "dev": true, - "inBundle": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">= 4" + "node": ">=4.0" } }, - "node_modules/npm/node_modules/rimraf": { - "version": "3.0.2", + "node_modules/semistandard/node_modules/glob-parent": { + "version": "5.1.2", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "is-glob": "^4.0.1" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">= 6" } }, - "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/semistandard/node_modules/globals": { + "version": "13.17.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm/node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "inBundle": 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" + "type-fest": "^0.20.2" }, "engines": { - "node": "*" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/semistandard/node_modules/ignore": { + "version": "4.0.6", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 4" } }, - "node_modules/npm/node_modules/safe-buffer": { - "version": "5.2.1", - "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" - } - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", + "node_modules/semistandard/node_modules/js-yaml": { + "version": "3.14.1", "dev": true, - "inBundle": true, "license": "MIT", - "optional": true + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } }, - "node_modules/npm/node_modules/semver": { + "node_modules/semistandard/node_modules/semver": { "version": "7.3.7", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -4371,5210 +4055,2559 @@ "node": ">=10" } }, - "node_modules/npm/node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", + "node_modules/semistandard/node_modules/type-fest": { + "version": "0.20.2", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/set-blocking": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", + "node_modules/semver": { + "version": "6.3.0", "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/npm/node_modules/socks": { - "version": "2.7.0", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/servatron": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/servatron/-/servatron-2.3.1.tgz", + "integrity": "sha512-PZz/KPi1vVwXRN57CJtJIUS1qfNrcRDXbsu/lAxU5B/d08ugXlQ3w3e1vIPWN8/30GkEdoml98/qKduGwhYtmw==", "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" + "mime": "^3.0.0", + "minimist": "^1.2.6" }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" + "bin": { + "servatron": "bin/cli.js" } }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "7.0.0", + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "CC-BY-3.0" - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.1", + "node_modules/shebang-regex": { + "version": "3.0.0", "dev": true, - "inBundle": true, "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.11", - "dev": true, - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/ssri": { - "version": "9.0.1", + "node_modules/side-channel": { + "version": "1.0.4", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.1.1" + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/string_decoder": { - "version": "1.3.0", + "node_modules/signal-exit": { + "version": "3.0.5", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } + "license": "ISC" }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", + "node_modules/slash": { + "version": "3.0.0", "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", + "node_modules/slice-ansi": { + "version": "4.0.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/npm/node_modules/supports-color": { - "version": "7.2.0", + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/tar": { - "version": "6.1.11", + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/standard-engine": { + "version": "14.0.1", "dev": true, - "inBundle": true, - "license": "ISC", + "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": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "get-stdin": "^8.0.0", + "minimist": "^1.2.5", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" }, "engines": { - "node": ">= 10" + "node": ">=8.10" } }, - "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": { + "node_modules/string_decoder": { "version": "1.3.0", - "dev": true, - "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "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/npm/node_modules/treeverse": { - "version": "2.0.0", + "node_modules/string-width": { + "version": "4.2.3", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/unique-filename": { - "version": "1.1.1", + "node_modules/string.prototype.matchall": { + "version": "4.0.7", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "unique-slug": "^2.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/unique-slug": { - "version": "2.0.2", + "node_modules/string.prototype.trimend": { + "version": "1.0.5", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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", + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", "dev": true, - "inBundle": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "4.0.0", + "node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "builtins": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "1.0.0", + "node_modules/strip-bom": { + "version": "3.0.0", "dev": true, - "inBundle": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/npm/node_modules/wcwidth": { - "version": "1.0.1", + "node_modules/strip-json-comments": { + "version": "3.1.1", "dev": true, - "inBundle": true, "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/which": { - "version": "2.0.2", + "node_modules/supports-color": { + "version": "7.2.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" + "has-flag": "^4.0.0" }, - "bin": { - "node-which": "bin/node-which" + "engines": { + "node": ">=8" + } + }, + "node_modules/table": { + "version": "6.8.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 8" + "node": ">=10.0.0" } }, - "node_modules/npm/node_modules/wide-align": { - "version": "1.1.5", + "node_modules/table/node_modules/ajv": { + "version": "8.11.0", "dev": true, - "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/npm/node_modules/wrappy": { - "version": "1.0.2", + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", "dev": true, - "inBundle": true, - "license": "ISC" + "license": "MIT" + }, + "node_modules/tcpocket": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tcpocket/-/tcpocket-7.5.2.tgz", + "integrity": "sha512-3U8Jw8MI0q8se1f6gk2vCNjzEiSyFifB/A2TH4xauptwEaGCalCNAboaO8U2fMn3mexzLh5vcq7prPU0KhYQfg==", + "dependencies": { + "increlation": "^2.0.1" + } }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "4.0.2", + "node_modules/test-exclude": { + "version": "6.0.0", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "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==", + "node_modules/text-table": { + "version": "0.2.0", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/tick-tock": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "millisecond": "0.1.x" } }, - "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==", + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, "engines": { - "node": ">= 0.4" + "node": ">=4" } }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "node_modules/to-regex-range": { + "version": "5.0.1", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "is-number": "^7.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.0" } }, - "node_modules/object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "node_modules/tsconfig-paths": { + "version": "3.11.0", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" } }, - "node_modules/object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" + "minimist": "^1.2.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/type-check": { + "version": "0.4.0", "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.3" + "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" } }, - "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, - "dependencies": { - "yocto-queue": "^0.1.0" - }, + "node_modules/type-fest": { + "version": "2.18.0", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=10" + "node": ">=12.20" }, "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==", + "node_modules/unbox-primitive": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/uri-js": { + "version": "4.4.1", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" + "punycode": "^2.1.0" } }, - "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, - "engines": { - "node": ">=8" + "node_modules/use-http": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/use-http/-/use-http-1.0.26.tgz", + "integrity": "sha512-yB0dXX2S0Doyiti/kHqMsvlShL3tlI8YkoEARao1OVFKrGvyXejmWvrYkEI+oVTPvUqGzOsHbNROY0qKDC88Pg==", + "dependencies": { + "urs": "^0.0.8", + "use-ssr": "^1.0.24", + "utility-types": "^3.10.0" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.0" } }, - "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/use-http/node_modules/urs": { + "version": "0.0.8", + "license": "MIT", + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.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, - "engines": { - "node": ">=8" + "node_modules/use-http/node_modules/use-ssr": { + "version": "1.0.24", + "license": "MIT", + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.0" } }, - "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 + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" }, - "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, + "node_modules/utility-types": { + "version": "3.10.0", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "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==", + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", "dev": true, + "license": "ISC", "dependencies": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" }, "engines": { - "node": ">=6" + "node": ">=10.12.0" } }, - "node_modules/pkg-conf/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==", + "node_modules/which": { + "version": "2.0.2", "dev": true, + "license": "ISC", "dependencies": { - "locate-path": "^3.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/pkg-conf/node_modules/load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "node_modules/which-boxed-primitive": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/pkg-conf/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==", + "node_modules/word-wrap": { + "version": "1.2.3", "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/pkg-conf/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==", + "node_modules/wrap-ansi": { + "version": "7.0.0", "dev": true, + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/pkg-conf/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==", + "node_modules/wrappy": { + "version": "1.0.2", "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "ISC" }, - "node_modules/pkg-conf/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==", + "node_modules/write-response": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/write-response/-/write-response-1.2.3.tgz", + "integrity": "sha512-Na6IPeWSJJsu3sqGmvVVsEAhgCSjbycZOQJJc8mm8Ek3zX4u2kkoFXDHouWw6Wd0VdAJLfuoWEnHVsGqKv0/LQ==", "dev": true, - "engines": { - "node": ">=6" + "dependencies": { + "error-with-object": "^1.1.0" } }, - "node_modules/pkg-conf/node_modules/parse-json": { + "node_modules/xdg-basedir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "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": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "node_modules/y18n": { + "version": "5.0.8", "dev": true, + "license": "ISC", "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/pkg-conf/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "node_modules/yallist": { + "version": "4.0.0", "dev": true, - "engines": { - "node": ">=6" - } + "license": "ISC" }, - "node_modules/pkg-conf/node_modules/type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "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, "engines": { - "node": ">=6" + "node": ">= 6" } }, - "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==", + "node_modules/yargs": { + "version": "16.2.0", "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": ">= 0.8.0" + "node": ">=10" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/yargs-parser": { + "version": "20.2.9", "dev": true, + "license": "ISC", "engines": { - "node": ">=0.4.0" + "node": ">=10" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "node_modules/yocto-queue": { + "version": "0.1.0", "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", - "dependencies": { - "side-channel": "^1.0.4" - }, + "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.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==", + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", "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" - } - ] + "requires": { + "@babel/types": "^7.18.6" + } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", "dev": true }, - "node_modules/reconnecting-websocket": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz", - "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==" + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "dev": true }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "@babel/highlight": { + "version": "7.18.6", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "requires": { + "regenerator-runtime": "^0.13.4" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "@bcoe/v8-coverage": { + "version": "0.2.3", + "dev": true + }, + "@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "peer": true, + "requires": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" } }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "@emotion/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.3.1.tgz", + "integrity": "sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==", "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peer": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" } }, - "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==", + "@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", "dev": true, - "engines": { - "node": ">=4" + "peer": true, + "requires": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "requires": { + "@emotion/memoize": "0.7.4" } }, - "node_modules/rgb-hex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rgb-hex/-/rgb-hex-3.0.0.tgz", - "integrity": "sha512-8h7ZcwxCBDKvchSWbWngJuSCqJGQ6nDuLLg+QcRyQDbX9jMWt+PpPeXAhSla0GOooEomk3lCprUpGkMdsLjKyg==", - "engines": { - "node": ">=8" - } + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "dev": true }, - "node_modules/righto": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/righto/-/righto-6.1.3.tgz", - "integrity": "sha512-tfnK3e10FjBCKSfVI69vJCzSCsHNaxCK7pdEhnxGM89KxHm4ykxT5B1jq6Xoj12+vK1atUvcKwAIFG84IBrPLw==", + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", "dev": true, - "dependencies": { - "abbott": "^1.1.3", - "setimmediate": "^1.0.5" + "requires": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peer": true + }, + "@emotion/styled": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", + "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "dev": true, + "requires": { + "@emotion/styled-base": "^10.3.0", + "babel-plugin-emotion": "^10.0.27" } }, - "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==", + "@emotion/styled-base": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz", + "integrity": "sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==", "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" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/is-prop-valid": "0.8.8", + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3" } }, - "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==", + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", + "dev": true, + "peer": true + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "dev": true }, - "node_modules/semistandard": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/semistandard/-/semistandard-16.0.1.tgz", - "integrity": "sha512-ApAJ9fMAIwYuk5xI2HWSCd8s5o5L95abxU4dYl6ovUX6Rcww/7oxtaSuu9wLFL/Gfj/EXx1h6S4itXy5vyL60Q==", + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", + "dev": true + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", "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" - } - ], - "dependencies": { - "eslint": "^7.27.0", - "eslint-config-semistandard": "16.0.0", - "eslint-config-standard": "16.0.3", - "eslint-config-standard-jsx": "10.0.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^5.1.0", - "eslint-plugin-react": "~7.21.5", - "standard-engine": "^14.0.0" - }, - "bin": { - "semistandard": "bin/cmd.js" - }, - "engines": { - "node": ">=10.12.0" - } + "peer": true }, - "node_modules/semistandard/node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", "dev": true, - "dependencies": { + "optional": true + }, + "@eslint/eslintrc": { + "version": "1.3.0", + "dev": true, + "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "dependencies": { + "globals": { + "version": "13.17.0", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "dev": true + } } }, - "node_modules/semistandard/node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "@humanwhocodes/config-array": { + "version": "0.10.4", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" } }, - "node_modules/semistandard/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } + "@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "dev": true }, - "node_modules/semistandard/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, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true }, - "node_modules/semistandard/node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "@istanbuljs/schema": { + "version": "0.1.3", + "dev": true }, - "node_modules/semistandard/node_modules/eslint-config-semistandard": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-16.0.0.tgz", - "integrity": "sha512-oD8QOo4mSInRJhQb3Zi6L8HebwZaB6SI3A+NNrPdVN0nN1K45L5pXK3joY+ksWDlT3ew/M+fJk2tuMCjIpjRzQ==", + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", "dev": true, - "peerDependencies": { - "eslint": ">=7.12.1", - "eslint-config-standard": ">=16.0.3", - "eslint-plugin-import": ">=2.22.1", - "eslint-plugin-node": ">=11.1.0", - "eslint-plugin-promise": ">=4.2.1" + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/semistandard/node_modules/eslint-config-standard": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", - "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", - "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" - } - ], - "peerDependencies": { - "eslint": "^7.12.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1 || ^5.0.0" + "@markwylde/liferaft": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@markwylde/liferaft/-/liferaft-1.2.0.tgz", + "integrity": "sha512-uPYbOEJgdsqrn7KimmQA9x8ihOQpnzbDQ1foOwMos3s1f4OTCTOFFKeEoREJ9aqA0mC+JFe1DkTc7pRcgURH9w==", + "requires": { + "emits": "^3.0.0", + "encoding-down": "^7.1.0", + "eventemitter3": "^4.0.7", + "extendible": "^0.1.1", + "immediate": "^3.3.0", + "leveldown": "^6.1.1", + "levelup": "^5.1.1", + "millisecond": "^0.1.2", + "modification": "^1.0.0", + "one-time": "^1.0.0", + "promise-queue": "^2.2.5", + "tick-tock": "^1.0.0" } }, - "node_modules/semistandard/node_modules/eslint-config-standard-jsx": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", - "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", + "@nodelib/fs.scandir": { + "version": "2.1.5", "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" - } - ], - "peerDependencies": { - "eslint": "^7.12.1", - "eslint-plugin-react": "^7.21.5" + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" } }, - "node_modules/semistandard/node_modules/eslint-plugin-promise": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", - "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", + "@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0" + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" } }, - "node_modules/semistandard/node_modules/eslint-plugin-react": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", - "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.1", - "array.prototype.flatmap": "^1.2.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "object.entries": "^1.1.2", - "object.fromentries": "^2.0.2", - "object.values": "^1.1.1", - "prop-types": "^15.7.2", - "resolve": "^1.18.1", - "string.prototype.matchall": "^4.0.2" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "abstract-leveldown": { + "version": "7.2.0", + "requires": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" } }, - "node_modules/semistandard/node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "acorn": { + "version": "8.8.0", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } + "requires": {} }, - "node_modules/semistandard/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==", + "ajv": { + "version": "6.12.6", "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "node_modules/semistandard/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "ansi-colors": { + "version": "4.1.3", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", "dev": true, - "engines": { - "node": ">=10" + "requires": { + "color-convert": "^2.0.1" } }, - "node_modules/semistandard/node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "argparse": { + "version": "2.0.1", + "dev": true + }, + "array-includes": { + "version": "3.1.5", "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" } }, - "node_modules/semistandard/node_modules/espree/node_modules/eslint-visitor-keys": { + "array-union": { + "version": "2.1.0", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, + "array.prototype.flatmap": { "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, - "engines": { - "node": ">=4" + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, - "node_modules/semistandard/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "astral-regex": { + "version": "2.0.0", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "dev": true + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dev": true, - "engines": { - "node": ">=4.0" + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" } }, - "node_modules/semistandard/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==", + "babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", "dev": true, - "dependencies": { - "is-glob": "^4.0.1" + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/serialize": "^0.11.16", + "babel-plugin-macros": "^2.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^1.0.5", + "find-root": "^1.1.0", + "source-map": "^0.5.7" }, - "engines": { - "node": ">= 6" + "dependencies": { + "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 + } } }, - "node_modules/semistandard/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", "dev": true, - "engines": { - "node": ">= 4" + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" } }, - "node_modules/semistandard/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==", + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "dev": true + }, + "base64-js": { + "version": "1.5.1" + }, + "basictap": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/basictap/-/basictap-3.4.3.tgz", + "integrity": "sha512-GKSlKn5F4BNUfkuuIQQYNz6/jdqb6teGbRddtIw66MIcyg/9d/oCsRuHSZE4+xfuPtEHnY9ngvysVyNcmtHPuA==", "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "requires": { + "colorette": "^2.0.16", + "events": "^3.3.0", + "promise-limit": "^2.7.0" } }, - "node_modules/semistandard/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "brace-expansion": { + "version": "1.1.11", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "braces": { + "version": "3.0.2", "dev": true, - "bin": { - "semver": "bin/semver.js" + "requires": { + "fill-range": "^7.0.1" } }, - "node_modules/server-destroy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", - "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=" - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true + "buffer": { + "version": "6.0.3", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } }, - "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==", + "c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" } }, - "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==", + "call-bind": { + "version": "1.0.2", "dev": true, - "engines": { - "node": ">=8" + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "callsites": { + "version": "3.1.0", + "dev": true + }, + "catering": { + "version": "2.1.0", + "requires": { + "queue-tick": "^1.0.0" } }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==" + }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==", "dev": true }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "cliui": { + "version": "7.0.4", "dev": true, - "engines": { - "node": ">=8" + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "color-convert": { + "version": "2.0.1", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "requires": { + "color-name": "~1.1.4" } }, - "node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "color-name": { + "version": "1.1.4", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", "dev": true, - "engines": { - "node": ">= 8" + "requires": { + "delayed-stream": "~1.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==", + "concat-map": { + "version": "0.0.1", "dev": true }, - "node_modules/standard-engine": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-14.0.1.tgz", - "integrity": "sha512-7FEzDwmHDOGva7r9ifOzD3BGdTbA7ujJ50afLVdW/tK14zQEptJjbFuUfn50irqdHDcTbNh0DTIoMPynMCXb0Q==", + "convert-source-map": { + "version": "1.8.0", "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" - } - ], - "dependencies": { - "get-stdin": "^8.0.0", - "minimist": "^1.2.5", - "pkg-conf": "^3.1.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8.10" + "requires": { + "safe-buffer": "~5.1.1" } }, - "node_modules/string-to-color": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/string-to-color/-/string-to-color-2.2.2.tgz", - "integrity": "sha512-XeA2goP7PNsSlz8RRn6KhYswnMf5Tl+38ajfy8n4oZJyMGC4qqKgHNHsZ/3qwvr42NRIjf9eSr721SyetDeMkA==", - "dependencies": { - "colornames": "^1.1.1", - "hex-rgb": "^4.1.0", - "lodash.padend": "^4.6.1", - "lodash.trimstart": "^4.5.1", - "lodash.words": "^4.2.0", - "rgb-hex": "^3.0.0" + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" } }, - "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==", + "cross-spawn": { + "version": "7.0.3", "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "node_modules/string.prototype.matchall": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", - "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.1", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "crypto-random-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-5.0.0.tgz", + "integrity": "sha512-KWjTXWwxFd6a94m5CdRGW/t82Tr8DoBc9dNnPCAbFI1EBweN6v1tv8y4Y1m7ndkp/nkIBRxUxAzpaBnR2k3bcQ==", + "requires": { + "type-fest": "^2.12.2" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==", + "dev": true + }, + "debarrel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/debarrel/-/debarrel-1.0.2.tgz", + "integrity": "sha512-dOGk3xqe786BZg3iZMvs5PCNjMKEDXgfMl9Jpm86rbovkH9ExMWPO4gRL42yLCJ9UTGuO4sKAkEg8T1qiIXX6g==" + }, + "debug": { + "version": "4.3.2", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "requires": { + "ms": "2.1.2" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "deep-is": { + "version": "0.1.4", + "dev": true + }, + "deferred-leveldown": { + "version": "7.0.0", + "requires": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3" } }, - "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==", + "define-properties": { + "version": "1.1.4", "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "delayed-stream": { + "version": "1.0.0", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "path-type": "^4.0.0" } }, - "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==", + "doctrine": { + "version": "3.0.0", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "esutils": "^2.0.2" } }, - "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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "emits": { + "version": "3.0.0" + }, + "emoji-regex": { + "version": "8.0.0", + "dev": true + }, + "encoding-down": { + "version": "7.1.0", + "requires": { + "abstract-leveldown": "^7.2.0", + "inherits": "^2.0.3", + "level-codec": "^10.0.0", + "level-errors": "^3.0.0" } }, - "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==", + "enquirer": { + "version": "2.3.6", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "requires": { + "ansi-colors": "^4.1.1" } }, - "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "error-ex": { + "version": "1.3.2", "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" + "requires": { + "is-arrayish": "^0.2.1" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "error-with-object": { + "version": "1.1.0", + "dev": true + }, + "es-abstract": { + "version": "1.20.1", "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" } }, - "node_modules/table/node_modules/json-schema-traverse": { + "es-shim-unscopables": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/tcpocket": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/tcpocket/-/tcpocket-5.0.6.tgz", - "integrity": "sha512-9VeOfMGJd0x0vPdz6b2PUT0O5R5l+xWaDLxfpHJJPYpB3INE7ZEfeGo+3GrUjKZ9U1sjJNCvN7WjW6x44HFJ0Q==", - "dependencies": { - "ndjson-fe": "^1.2.7" + "dev": true, + "requires": { + "has": "^1.0.3" } }, - "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==", + "es-to-primitive": { + "version": "1.2.1", "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "requires": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "dev": true, + "optional": true }, - "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==", + "esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } + "optional": true }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } + "optional": true }, - "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==", + "esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } + "optional": true }, - "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==", + "esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "optional": true }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } + "optional": true }, - "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==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", + "esbuild-linux-64": { + "version": "0.15.5", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.0" - } + "optional": true }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } + "optional": true }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "optional": true }, - "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==", + "esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", "dev": true, - "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/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-response": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/write-response/-/write-response-1.2.3.tgz", - "integrity": "sha512-Na6IPeWSJJsu3sqGmvVVsEAhgCSjbycZOQJJc8mm8Ek3zX4u2kkoFXDHouWw6Wd0VdAJLfuoWEnHVsGqKv0/LQ==", - "dependencies": { - "error-with-object": "^1.1.0" - } - }, - "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } + "optional": true }, - "node_modules/wtfnode": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.8.4.tgz", - "integrity": "sha512-64GEKtMt/MUBuAm+8kHqP74ojjafzu00aT0JKsmkIwYmjRQ/odO0yhbzKLm+Z9v1gMla+8dwITRKzTAlHsB+Og==", - "bin": { - "wtfnode": "proxy.js" - } + "esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "dev": true, + "optional": true }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", "dev": true, - "engines": { - "node": ">=8" - } + "optional": true }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", "dev": true, - "engines": { - "node": ">=10" - } + "optional": true }, - "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 + "esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "dev": true, + "optional": true }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", "dev": true, - "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" - } + "optional": true }, - "node_modules/yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", "dev": true, - "engines": { - "node": ">=10" - } + "optional": true }, - "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==", + "esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } + "optional": true }, - "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "escalade": { + "version": "3.1.1", "dev": true }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "escape-string-regexp": { + "version": "4.0.0", + "dev": true + }, + "eslint": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", + "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "ajv": "^6.10.0", + "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.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.3", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "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.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "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==", + "chalk": { + "version": "4.1.2", "dev": true, "requires": { - "color-convert": "^1.9.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "eslint-utils": { + "version": "3.0.0", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "dev": true + } } }, - "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==", + "globals": { + "version": "13.17.0", "dev": true, "requires": { - "color-name": "1.1.3" + "type-fest": "^0.20.2" } }, - "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 - }, - "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 - }, - "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==", + "type-fest": { + "version": "0.20.2", "dev": true - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } } } }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "eslint-import-resolver-node": { + "version": "0.3.6", "dev": true, "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.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" + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, - "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "eslint-module-utils": { + "version": "2.7.1", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "debug": "^3.2.7", + "find-up": "^2.1.0", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "dev": true + } } }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@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 - }, - "@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==", + "eslint-plugin-es": { + "version": "3.0.1", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" } }, - "@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 - }, - "@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==", + "eslint-plugin-import": { + "version": "2.25.2", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.0", + "has": "^1.0.3", + "is-core-module": "^2.7.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "dev": true + } } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "@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 - }, - "abbott": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/abbott/-/abbott-1.1.3.tgz", - "integrity": "sha1-JvOtm7vb/+LFa1sDdU5ZgasOXlw=", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true + "eslint-plugin-node": { + "version": "11.1.0", + "dev": true, + "requires": { + "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" + } }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "dev": true, "requires": {} }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "eslint-scope": { + "version": "7.1.1", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, - "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 - }, - "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 - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "eslint-utils": { + "version": "2.1.0", + "dev": true, "requires": { - "color-convert": "^2.0.1" + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "dev": true + } } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "eslint-visitor-keys": { + "version": "3.3.0", "dev": true }, - "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "espree": { + "version": "9.3.3", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" } }, - "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==", + "esprima": { + "version": "4.0.1", "dev": true }, - "array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "esquery": { + "version": "1.4.0", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" + "estraverse": "^5.1.0" } }, - "array.prototype.flatmap": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", - "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "esrecurse": { + "version": "4.3.0", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" + "estraverse": "^5.2.0" } }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "estraverse": { + "version": "5.3.0", "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "esutils": { + "version": "2.0.3", + "dev": true }, - "axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "requires": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - } + "eventemitter3": { + "version": "4.0.7" }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, - "basictap": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/basictap/-/basictap-1.1.13.tgz", - "integrity": "sha512-74mw9kmAdmdkHqtP70YFqHMYzO3my92kZA4axHbKI7V7sOUCniiVP1R+0wR7Y5BO4v5wnrt4sMU3nLjlvzTuWw==", - "dev": true, - "requires": { - "colorette": "^1.2.2", - "concurrun": "^1.1.0", - "righto": "^6.1.3" - } + "extendible": { + "version": "0.1.1" }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "failmenot": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/failmenot/-/failmenot-3.0.1.tgz", + "integrity": "sha512-nFgVwPKWp76fLN8HQwJ0g9HnNXnmgx+jC1LGaRzoTaP4JwMcWhQHmDr8EPQJSu+E7gPEcQIqcet2ANNuZhzuNw==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "dev": true + }, + "fastq": { + "version": "1.13.0", "dev": true, "requires": { - "fill-range": "^7.0.1" + "reusify": "^1.0.4" } }, - "c8": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.7.2.tgz", - "integrity": "sha512-8AqNnUMxB3hsgYCYso2GJjlwnaNPlrEEbYbCQb7N76V1nrOgCKXiTcE3gXU18rIj0FeduPywROrIBMC7XAKApg==", + "file-entry-cache": { + "version": "6.0.1", "dev": true, "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.2", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.0.2", - "rimraf": "^3.0.0", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^7.1.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.7" + "flat-cache": "^3.0.4" } }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "fill-range": { + "version": "7.0.1", + "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "to-regex-range": "^5.0.1" } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "final-stream": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/final-stream/-/final-stream-2.0.4.tgz", + "integrity": "sha512-kBaHWwbW2oRFp1WZeY28QrCwv5yJVJTO/tPHYIWLs3ezd2DvCXrBayqgG096tJPqZhUaCM/y1439LkAjnr7xaA==" + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, - "canhazdb-driver-ejdb": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/canhazdb-driver-ejdb/-/canhazdb-driver-ejdb-1.1.5.tgz", - "integrity": "sha512-NR+cJcPBq8+hUuJyYSRAOKn3MaDeByXCh7cXuRD1Z2SiQ+aOosFoKXXGA3QRDT6W9UgMrd1uEqdC2yu1ri/UtQ==", + "find-up": { + "version": "5.0.0", "dev": true, "requires": { - "mql-to-jql": "^1.4.1", - "node-ejdb-lite": "^2.73.8", - "uuid": "^8.3.2" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "flat-cache": { + "version": "3.0.4", + "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "flatted": { + "version": "3.2.2", + "dev": true + }, + "fn.name": { + "version": "1.1.0" + }, + "follow-redirects": { + "version": "1.15.1", + "dev": true + }, + "foreground-child": { + "version": "2.0.0", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" } }, - "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==", + "form-data": { + "version": "4.0.0", + "dev": true, "requires": { - "color-name": "~1.1.4" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "fs.realpath": { + "version": "1.0.0", "dev": true }, - "colornames": { + "function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "function.prototype.name": { + "version": "1.1.5", + "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "functional-red-black-tree": { + "version": "1.0.1", "dev": true }, - "concurrun": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/concurrun/-/concurrun-1.1.0.tgz", - "integrity": "sha512-d6TtuUVtc+zxR/mXiXQLcotv/o5KjKHVADpkz2WAexkGe1nFnv2PP5aAKD+4LP4PLPaZP4wgqdja2yfsCA5YcA==", + "functions-have-names": { + "version": "1.2.3", "dev": true }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "get-caller-file": { + "version": "2.0.5", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" } }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "get-stdin": { + "version": "8.0.0", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", "dev": true, "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" } }, - "debarrel": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debarrel/-/debarrel-1.0.1.tgz", - "integrity": "sha512-0eOJdzuCDb8an9dv/98m3IMicTI5aFlVLz/9ENHADBMea68GFI9grscTOCnvxvKAT1JZtrBPiDahjp91sWOLkw==" + "glob": { + "version": "7.2.0", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "glob-parent": { + "version": "6.0.2", "dev": true, "requires": { - "ms": "2.1.2" + "is-glob": "^4.0.3" } }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "globby": { + "version": "11.1.0", + "dev": true, + "requires": { + "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" + } + }, + "graceful-fs": { + "version": "4.2.8", "dev": true }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "grapheme-splitter": { + "version": "1.0.4", + "dev": true + }, + "has": { + "version": "1.0.3", "dev": true, "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "function-bind": "^1.1.1" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "has-bigints": { + "version": "1.0.2", + "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", "dev": true, "requires": { - "path-type": "^4.0.0" + "get-intrinsic": "^1.1.1" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "has-symbols": { + "version": "1.0.3", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", "dev": true, "requires": { - "esutils": "^2.0.2" + "has-symbols": "^1.0.2" } }, - "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==", + "html-escaper": { + "version": "2.0.2", "dev": true }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "ieee754": { + "version": "1.2.1" + }, + "ignore": { + "version": "5.2.0", + "dev": true + }, + "immediate": { + "version": "3.3.0" + }, + "import-fresh": { + "version": "3.3.0", "dev": true, "requires": { - "ansi-colors": "^4.1.1" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, - "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==", + "imurmurhash": { + "version": "0.1.4", + "dev": true + }, + "increlation": { + "version": "2.0.1" + }, + "inflight": { + "version": "1.0.6", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "once": "^1.3.0", + "wrappy": "1" } }, - "error-with-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/error-with-object/-/error-with-object-1.1.0.tgz", - "integrity": "sha512-ctthqZF3x2gG1CxAGB+irtAOXGYj7S9r+0flbRGe01qCOU/yJJAyvzOKuR/Locu/8pA1+v9jGDiEKS5ZX6OKDw==" + "inherits": { + "version": "2.0.4" }, - "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "internal-slot": { + "version": "1.0.3", "dev": true, "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", + "get-intrinsic": "^1.1.0", "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "side-channel": "^1.0.4" } }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "is-arrayish": { + "version": "0.2.1", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", "dev": true, "requires": { - "has": "^1.0.3" + "has-bigints": "^1.0.1" } }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "is-boolean-object": { + "version": "1.1.2", "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "is-buffer": { + "version": "2.0.5" }, - "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==", + "is-callable": { + "version": "1.2.4", "dev": true }, - "eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "is-core-module": { + "version": "2.8.0", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "ajv": "^6.10.0", - "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.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "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.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - } + "has": "^1.0.3" } }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "is-date-object": { + "version": "1.0.5", "dev": true, "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "has-tostringtag": "^1.0.0" } }, - "eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true + }, + "is-glob": { + "version": "4.0.3", "dev": true, "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "is-extglob": "^2.1.1" } }, - "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==", + "is-negative-zero": { + "version": "2.0.2", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", "dev": true, "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "has-tostringtag": "^1.0.0" } }, - "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "is-regex": { + "version": "1.1.4", "dev": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, - "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==", + "is-shared-array-buffer": { + "version": "1.0.2", "dev": true, "requires": { - "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" + "call-bind": "^1.0.2" } }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "is-string": { + "version": "1.0.7", "dev": true, "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "has-tostringtag": "^1.0.0" } }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "is-symbol": { + "version": "1.0.4", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "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 - } + "has-symbols": "^1.0.2" } }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "is-weakref": { + "version": "1.0.2", "dev": true, "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "call-bind": "^1.0.2" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "isexe": { + "version": "2.0.0", "dev": true }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "istanbul-lib-coverage": { + "version": "3.2.0", + "dev": true + }, + "istanbul-lib-report": { + "version": "3.0.0", "dev": true, "requires": { - "estraverse": "^5.1.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" } }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "istanbul-reports": { + "version": "3.1.5", "dev": true, "requires": { - "estraverse": "^5.2.0" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "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 + "js-tokens": { + "version": "4.0.0" }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "js-yaml": { + "version": "4.1.0", "dev": true, "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "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, - "requires": { - "is-glob": "^4.0.1" - } - } + "argparse": "^2.0.1" } }, - "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==", + "json-parse-better-errors": { + "version": "1.0.2", "dev": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "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 }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "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, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "final-stream": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/final-stream/-/final-stream-2.0.3.tgz", - "integrity": "sha512-THH/DnlYuhWQZBm7vPpavIlLV2hKh3HFMiLORz7kr+CxrbgbG33BP22RWtAn4EmN8OGfGttWcued3xluCA6p9g==" - }, - "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, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "json-schema-traverse": { + "version": "0.4.1", "dev": true }, - "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" - }, - "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, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "jsx-ast-utils": { + "version": "3.3.2", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "array-includes": "^3.1.5", + "object.assign": "^4.1.2" } }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "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 - }, - "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 - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "level-codec": { + "version": "10.0.0", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "buffer": "^6.0.3" } }, - "get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + "level-concat-iterator": { + "version": "3.0.0" }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true + "level-errors": { + "version": "3.0.1" }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, + "level-iterator-stream": { + "version": "5.0.0", "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "level-supports": { + "version": "2.0.2" }, - "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, + "leveldown": { + "version": "6.1.1", "requires": { - "is-glob": "^4.0.3" + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" } }, - "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, + "levelup": { + "version": "5.1.1", "requires": { - "type-fest": "^0.20.2" + "catering": "^2.0.0", + "deferred-leveldown": "^7.0.0", + "level-errors": "^3.0.1", + "level-iterator-stream": "^5.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" } }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "levn": { + "version": "0.4.1", "dev": true, "requires": { - "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" - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "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 }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "load-json-file": { + "version": "5.3.0", "dev": true, "requires": { - "get-intrinsic": "^1.1.1" + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "type-fest": { + "version": "0.3.1", + "dev": true + } } }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "locate-path": { + "version": "6.0.0", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "p-locate": "^5.0.0" } }, - "hex-rgb": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz", - "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==" - }, - "hinton": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hinton/-/hinton-1.0.0.tgz", - "integrity": "sha512-92PiCRxSvcHLB+5f4w29Ex7EWC7/AVok3Zg84X8K+NCtrMmACh0UR7ZgQfos0/xGdc+vPcY4ak7ijaWhluUj8A==", + "lockbase": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/lockbase/-/lockbase-5.0.1.tgz", + "integrity": "sha512-JbQF2eJFAEJPo341Et6sIyTxflop8q/h7gHE7px1OcI6B5ctdwgYpGSiNbdciFkCNKHXNK+b8zHJU5hXsL87eA==", "requires": { - "chalk": "^4.1.0", - "string-to-color": "^2.2.2" + "uuid": "^8.3.2" } }, - "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 - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "lodash.merge": { + "version": "4.6.2", "dev": true }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "lodash.truncate": { + "version": "4.4.2", "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "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 - }, - "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, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "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 - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "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 - }, - "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, - "requires": { - "argparse": "^2.0.1" - } - }, - "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 - }, - "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 - }, - "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - } - }, - "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, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "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, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lockbase": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/lockbase/-/lockbase-1.0.9.tgz", - "integrity": "sha512-6UYmTjzPSZcoAj2DNlmz6J8uXYD5UcIlu3JXcx6FJoFCZbjQ5n78WfQ4CVQebRpL704MXCIOV00Kn1QzuS2zyQ==", - "requires": { - "uuid": "^8.3.1" - } - }, - "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 - }, - "lodash.padend": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", - "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=" - }, - "lodash.trimstart": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/lodash.trimstart/-/lodash.trimstart-4.5.1.tgz", - "integrity": "sha1-j/TexTLYJIavWVc8OURZFOlEp/E=" - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "lodash.words": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.words/-/lodash.words-4.2.0.tgz", - "integrity": "sha1-Xs/q+Oz4rKqODIOGKV8Zk8nPQDY=" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "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, - "requires": { - "yallist": "^4.0.0" - } - }, - "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, - "requires": { - "semver": "^6.0.0" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mql-to-jql": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mql-to-jql/-/mql-to-jql-1.4.1.tgz", - "integrity": "sha512-FBACw40CNcOn2eoR2E3NJolu8J4zsp592D1/xpgU7yufxd/5219Bk02S7Hfo4jfT0pFxcT4EuRFbmmnmRXg+YA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "ndjson-fe": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/ndjson-fe/-/ndjson-fe-1.2.10.tgz", - "integrity": "sha512-KUnVQdm+kWJt/2HhiBmZ4EhzliHWXH6GglJDVZrrF8vr8ps2sBVFzijcz/jsXm7P9ji4lWWU3X1D1RZp0F6lWA==" - }, - "node-ejdb-lite": { - "version": "2.73.8", - "resolved": "https://registry.npmjs.org/node-ejdb-lite/-/node-ejdb-lite-2.73.8.tgz", - "integrity": "sha512-6YptAKZlkVB7ks3zWqagrZyDSEyDgwWIdwiBuAVzbbRyA1a9E8moDFt5EBOvGKo3VGflrYGjDrJNnj4ut+5H5Q==" - }, - "npm": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-8.18.0.tgz", - "integrity": "sha512-G07/yKvNUwhwxYhk8BxcuDPB/4s+y755i6CnH3lf9LQBHP5siUx66WbuNGWEnN3xaBER4+IR3OWApKX7eBO5Dw==", - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^5.0.4", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/config": "^4.2.1", - "@npmcli/fs": "^2.1.0", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/package-json": "^2.0.0", - "@npmcli/run-script": "^4.2.1", - "abbrev": "~1.1.1", - "archy": "~1.0.0", - "cacache": "^16.1.1", - "chalk": "^4.1.2", - "chownr": "^2.0.0", - "cli-columns": "^4.0.0", - "cli-table3": "^0.6.2", - "columnify": "^1.6.0", - "fastest-levenshtein": "^1.0.12", - "glob": "^8.0.1", - "graceful-fs": "^4.2.10", - "hosted-git-info": "^5.0.0", - "ini": "^3.0.0", - "init-package-json": "^3.0.2", - "is-cidr": "^4.0.2", - "json-parse-even-better-errors": "^2.3.1", - "libnpmaccess": "^6.0.2", - "libnpmdiff": "^4.0.2", - "libnpmexec": "^4.0.2", - "libnpmfund": "^3.0.1", - "libnpmhook": "^8.0.2", - "libnpmorg": "^4.0.2", - "libnpmpack": "^4.0.2", - "libnpmpublish": "^6.0.2", - "libnpmsearch": "^5.0.2", - "libnpmteam": "^4.0.2", - "libnpmversion": "^3.0.1", - "make-fetch-happen": "^10.2.0", - "minipass": "^3.1.6", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "ms": "^2.1.2", - "node-gyp": "^9.1.0", - "nopt": "^6.0.0", - "npm-audit-report": "^3.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.1.0", - "npm-pick-manifest": "^7.0.1", - "npm-profile": "^6.2.0", - "npm-registry-fetch": "^13.3.1", - "npm-user-validate": "^1.0.1", - "npmlog": "^6.0.2", - "opener": "^1.5.2", - "p-map": "^4.0.0", - "pacote": "^13.6.2", - "parse-conflict-json": "^2.0.2", - "proc-log": "^2.0.1", - "qrcode-terminal": "^0.12.0", - "read": "~1.0.7", - "read-package-json": "^5.0.1", - "read-package-json-fast": "^2.0.3", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.1", - "tar": "^6.1.11", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^2.0.0", - "validate-npm-package-name": "^4.0.0", - "which": "^2.0.2", - "write-file-atomic": "^4.0.1" - }, - "dependencies": { - "@colors/colors": { - "version": "1.5.0", - "bundled": true, - "dev": true, - "optional": true - }, - "@gar/promisify": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "@isaacs/string-locale-compare": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "@npmcli/arborist": { - "version": "5.6.0", - "bundled": true, - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", - "@npmcli/move-file": "^2.0.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.1.1", - "@npmcli/run-script": "^4.1.3", - "bin-links": "^3.0.0", - "cacache": "^16.0.6", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "minimatch": "^5.1.0", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.0.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.0", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.1", - "proc-log": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.0", - "treeverse": "^2.0.0", - "walk-up-path": "^1.0.0" - } - }, - "@npmcli/ci-detect": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "@npmcli/config": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/map-workspaces": "^2.0.2", - "ini": "^3.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "proc-log": "^2.0.0", - "read-package-json-fast": "^2.0.3", - "semver": "^7.3.5", - "walk-up-path": "^1.0.0" - } - }, - "@npmcli/disparity-colors": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.3.0" - } - }, - "@npmcli/fs": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "requires": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - } - }, - "@npmcli/git": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^3.0.0", - "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^7.0.0", - "proc-log": "^2.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - } - }, - "@npmcli/installed-package-contents": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "@npmcli/map-workspaces": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^8.0.1", - "minimatch": "^5.0.1", - "read-package-json-fast": "^2.0.3" - } - }, - "@npmcli/metavuln-calculator": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "cacache": "^16.0.0", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", - "semver": "^7.3.5" - } - }, - "@npmcli/move-file": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - } - }, - "@npmcli/name-from-folder": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "@npmcli/node-gyp": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "@npmcli/package-json": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.1" - } - }, - "@npmcli/promise-spawn": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "infer-owner": "^1.0.4" - } - }, - "@npmcli/query": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "npm-package-arg": "^9.1.0", - "postcss-selector-parser": "^6.0.10", - "semver": "^7.3.7" - } - }, - "@npmcli/run-script": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/promise-spawn": "^3.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^2.0.3", - "which": "^2.0.2" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "bundled": true, - "dev": true, - "requires": { - "debug": "4" - } - }, - "agentkeepalive": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - } - }, - "aggregate-error": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "aproba": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "are-we-there-yet": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "asap": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "bin-links": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "cmd-shim": "^5.0.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^3.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" - } - }, - "binary-extensions": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "builtins": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "semver": "^7.0.0" - } - }, - "cacache": { - "version": "16.1.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^1.1.1" - } - }, - "chalk": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chownr": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "cidr-regex": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "ip-regex": "^4.1.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "cli-columns": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - } - }, - "cli-table3": { - "version": "0.6.2", - "bundled": true, - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "clone": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "cmd-shim": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "mkdirp-infer-owner": "^2.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "color-support": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "columnify": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "requires": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" - } - }, - "common-ancestor-path": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "debug": { - "version": "4.3.4", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true - } - } - }, - "debuglog": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "defaults": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "depd": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "dezalgo": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "bundled": true, - "dev": true - }, - "encoding": { - "version": "0.1.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - } - }, - "env-paths": { - "version": "2.2.1", - "bundled": true, - "dev": true - }, - "err-code": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "bundled": true, - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "gauge": { - "version": "4.0.4", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - } - }, - "glob": { - "version": "8.0.3", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "bundled": true, - "dev": true - }, - "has": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "hosted-git-info": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^7.5.1" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "humanize-ms": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore-walk": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "minimatch": "^5.0.1" - } - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "ini": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "init-package-json": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "npm-package-arg": "^9.0.1", - "promzard": "^0.3.0", - "read": "^1.0.7", - "read-package-json": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^4.0.0" - } - }, - "ip": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "ip-regex": { - "version": "4.3.0", - "bundled": true, - "dev": true - }, - "is-cidr": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "cidr-regex": "^3.1.1" - } - }, - "is-core-module": { - "version": "2.10.0", - "bundled": true, - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "is-lambda": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "bundled": true, - "dev": true - }, - "json-stringify-nice": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "bundled": true, - "dev": true - }, - "just-diff": { - "version": "5.1.1", - "bundled": true, - "dev": true - }, - "just-diff-apply": { - "version": "5.4.1", - "bundled": true, - "dev": true - }, - "libnpmaccess": { - "version": "6.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmdiff": { - "version": "4.0.4", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/disparity-colors": "^2.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^5.0.1", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1", - "tar": "^6.1.0" - } - }, - "libnpmexec": { - "version": "4.0.11", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/arborist": "^5.0.0", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/fs": "^2.1.1", - "@npmcli/run-script": "^4.2.0", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^9.0.1", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "proc-log": "^2.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "semver": "^7.3.7", - "walk-up-path": "^1.0.0" - } - }, - "libnpmfund": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/arborist": "^5.0.0" - } - }, - "libnpmhook": { - "version": "8.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmorg": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmpack": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/run-script": "^4.1.3", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1" - } - }, - "libnpmpublish": { - "version": "6.0.4", - "bundled": true, - "dev": true, - "requires": { - "normalize-package-data": "^4.0.0", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0", - "semver": "^7.3.7", - "ssri": "^9.0.0" - } - }, - "libnpmsearch": { - "version": "5.0.3", - "bundled": true, - "dev": true, - "requires": { - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmteam": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmversion": { - "version": "3.0.6", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/git": "^3.0.0", - "@npmcli/run-script": "^4.1.3", - "json-parse-even-better-errors": "^2.3.1", - "proc-log": "^2.0.0", - "semver": "^7.3.7" - } - }, - "lru-cache": { - "version": "7.13.2", - "bundled": true, - "dev": true - }, - "make-fetch-happen": { - "version": "10.2.1", - "bundled": true, - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minipass": { - "version": "3.3.4", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minipass-collect": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-fetch": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } - }, - "minipass-flush": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-json-stream": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-sized": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "mkdirp-infer-owner": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - } - }, - "ms": { - "version": "2.1.3", - "bundled": true, - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "bundled": true, - "dev": true - }, - "node-gyp": { - "version": "9.1.0", - "bundled": true, - "dev": true, - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "glob": { - "version": "7.2.3", - "bundled": true, - "dev": true, - "requires": { - "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" - } - }, - "minimatch": { - "version": "3.1.2", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "nopt": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "abbrev": "1" - } - } - } - }, - "nopt": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "abbrev": "^1.0.0" - } - }, - "normalize-package-data": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - } - }, - "npm-audit-report": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - }, - "npm-bundled": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-install-checks": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "semver": "^7.1.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "npm-package-arg": { - "version": "9.1.0", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" - } - }, - "npm-packlist": { - "version": "5.1.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^1.1.2", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "7.0.1", - "bundled": true, - "dev": true, - "requires": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^9.0.0", - "semver": "^7.3.5" - } - }, - "npm-profile": { - "version": "6.2.1", - "bundled": true, - "dev": true, - "requires": { - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0" - } - }, - "npm-registry-fetch": { - "version": "13.3.1", - "bundled": true, - "dev": true, - "requires": { - "make-fetch-happen": "^10.0.6", - "minipass": "^3.1.6", - "minipass-fetch": "^2.0.3", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.1", - "proc-log": "^2.0.0" - } - }, - "npm-user-validate": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "npmlog": { - "version": "6.0.2", - "bundled": true, - "dev": true, - "requires": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.2", - "bundled": true, - "dev": true - }, - "p-map": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "pacote": { - "version": "13.6.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/git": "^3.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/run-script": "^4.1.0", - "cacache": "^16.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.6", - "mkdirp": "^1.0.4", - "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^5.0.0", - "read-package-json-fast": "^2.0.3", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11" - } - }, - "parse-conflict-json": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", - "just-diff-apply": "^5.2.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "postcss-selector-parser": { - "version": "6.0.10", - "bundled": true, - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "proc-log": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "promise-all-reject-late": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-call-limit": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "read": "1" - } - }, - "qrcode-terminal": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "read": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "read-cmd-shim": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "read-package-json": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "^8.0.1", - "json-parse-even-better-errors": "^2.3.1", - "normalize-package-data": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "read-package-json-fast": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "readable-stream": { - "version": "3.6.0", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "retry": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "glob": { - "version": "7.2.3", - "bundled": true, - "dev": true, - "requires": { - "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" - } - }, - "minimatch": { - "version": "3.1.2", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "safe-buffer": { - "version": "5.2.1", - "bundled": true, - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "7.3.7", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "bundled": true, - "dev": true - }, - "smart-buffer": { - "version": "4.2.0", - "bundled": true, - "dev": true - }, - "socks": { - "version": "2.7.0", - "bundled": true, - "dev": true, - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - } - }, - "socks-proxy-agent": { - "version": "7.0.0", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - } - }, - "spdx-correct": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.11", - "bundled": true, - "dev": true - }, - "ssri": { - "version": "9.0.1", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.1.1" - } - }, - "string_decoder": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar": { - "version": "6.1.11", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "tiny-relative-date": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "treeverse": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validate-npm-package-name": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtins": "^5.0.0" - } - }, - "walk-up-path": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "wcwidth": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "which": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "yallist": { - "version": "4.0.0", - "bundled": true, - "dev": true - } + }, + "logslot": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/logslot/-/logslot-2.1.1.tgz", + "integrity": "sha512-IvnKXlw+tXBnguDdmpyHRdiUzoG86s8EXsAYP6TkSICEwiFTcT0VwiGV7eT20TCHTf7XsYzRXdWlkyge29j7bQ==", + "requires": { + "chalk": "^5.0.1" } }, - "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==", + "loose-envify": { + "version": "1.4.0", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "millisecond": { + "version": "0.1.2" + }, + "mime": { + "version": "3.0.0" + }, + "mime-db": { + "version": "1.52.0", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "modification": { + "version": "1.0.0" + }, + "mql-to-jql": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mql-to-jql/-/mql-to-jql-1.4.1.tgz", + "integrity": "sha512-FBACw40CNcOn2eoR2E3NJolu8J4zsp592D1/xpgU7yufxd/5219Bk02S7Hfo4jfT0pFxcT4EuRFbmmnmRXg+YA==" + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "napi-macros": { + "version": "2.0.0" + }, + "natural-compare": { + "version": "1.4.0", "dev": true }, + "node-ejdb-lite": { + "version": "2.73.9", + "resolved": "https://registry.npmjs.org/node-ejdb-lite/-/node-ejdb-lite-2.73.9.tgz", + "integrity": "sha512-ND5a12zfR+Wq1mBWQe/uy48UbyJpFMzI9t+eAuGqPr4JQ/bLrbUdk2b/pUkLGt5lMWfXXS1sELka5z+7ZYGWzw==" + }, + "node-gyp-build": { + "version": "4.5.0" + }, + "object-assign": { + "version": "4.1.1" + }, "object-inspect": { "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "dev": true }, "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 }, "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.2", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", "object-keys": "^1.1.1" } }, "object.entries": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -9584,8 +6617,6 @@ }, "object.fromentries": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -9595,8 +6626,6 @@ }, "object.values": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -9606,17 +6635,19 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { "deep-is": "^0.1.3", @@ -9629,8 +6660,6 @@ }, "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, "requires": { "yocto-queue": "^0.1.0" @@ -9638,62 +6667,64 @@ }, "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, "requires": { "p-limit": "^3.0.2" } }, + "p-try": { + "version": "1.0.0", + "dev": true + }, "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, "requires": { "callsites": "^3.0.0" } }, + "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, + "requires": { + "@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" + } + }, "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 }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "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 }, "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 }, "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 }, "picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", "dev": true }, "pkg-conf": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", "dev": true, "requires": { "find-up": "^3.0.0", @@ -9702,30 +6733,13 @@ "dependencies": { "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, "requires": { "locate-path": "^3.0.0" } }, - "load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" - } - }, "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, "requires": { "p-locate": "^3.0.0", @@ -9734,8 +6748,6 @@ }, "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, "requires": { "p-try": "^2.0.0" @@ -9743,8 +6755,6 @@ }, "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, "requires": { "p-limit": "^2.0.0" @@ -9752,56 +6762,75 @@ }, "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 }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "path-exists": { + "version": "3.0.0", + "dev": true + } + } + }, + "pkg-dir": { + "version": "2.0.0", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "locate-path": "^2.0.0" } }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "locate-path": { + "version": "2.0.0", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "p-limit": { + "version": "1.3.0", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } }, - "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "p-locate": { + "version": "2.0.0", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", "dev": true } } }, "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 }, "progress": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "promise-limit": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", + "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==", + "dev": true + }, + "promise-queue": { + "version": "2.2.5" + }, "prop-types": { "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, "requires": { "loose-envify": "^1.4.0", @@ -9811,39 +6840,61 @@ }, "punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "queue-microtask": { + "version": "1.2.3" + }, + "queue-tick": { + "version": "1.0.0" + }, + "react": { + "version": "17.0.2", + "peer": true, "requires": { - "side-channel": "^1.0.4" + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" } }, - "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 + "react-dom": { + "version": "17.0.2", + "peer": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "dependencies": { + "scheduler": { + "version": "0.20.2", + "peer": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } + } }, "react-is": { "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "reconnecting-websocket": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz", - "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==" + "readable-stream": { + "version": "3.6.0", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true }, "regexp.prototype.flags": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -9853,64 +6904,34 @@ }, "regexpp": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.20.0", "dev": true, "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, "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 }, "reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "rgb-hex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rgb-hex/-/rgb-hex-3.0.0.tgz", - "integrity": "sha512-8h7ZcwxCBDKvchSWbWngJuSCqJGQ6nDuLLg+QcRyQDbX9jMWt+PpPeXAhSla0GOooEomk3lCprUpGkMdsLjKyg==" - }, - "righto": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/righto/-/righto-6.1.3.tgz", - "integrity": "sha512-tfnK3e10FjBCKSfVI69vJCzSCsHNaxCK7pdEhnxGM89KxHm4ykxT5B1jq6Xoj12+vK1atUvcKwAIFG84IBrPLw==", - "dev": true, - "requires": { - "abbott": "^1.1.3", - "setimmediate": "^1.0.5" - } - }, "rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -9918,8 +6939,6 @@ }, "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, "requires": { "queue-microtask": "^1.2.2" @@ -9927,8 +6946,6 @@ }, "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 }, "semistandard": { @@ -9948,10 +6965,15 @@ "standard-engine": "^14.0.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, "@eslint/eslintrc": { "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -9967,8 +6989,6 @@ }, "@humanwhocodes/config-array": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.0", @@ -9978,23 +6998,25 @@ }, "acorn": { "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" } }, + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "eslint": { "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, "requires": { "@babel/code-frame": "7.12.11", @@ -10041,36 +7063,26 @@ }, "eslint-config-semistandard": { "version": "16.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-16.0.0.tgz", - "integrity": "sha512-oD8QOo4mSInRJhQb3Zi6L8HebwZaB6SI3A+NNrPdVN0nN1K45L5pXK3joY+ksWDlT3ew/M+fJk2tuMCjIpjRzQ==", "dev": true, "requires": {} }, "eslint-config-standard": { "version": "16.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", - "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", "dev": true, "requires": {} }, "eslint-config-standard-jsx": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", - "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", "dev": true, "requires": {} }, "eslint-plugin-promise": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", - "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", "dev": true, "requires": {} }, "eslint-plugin-react": { "version": "7.21.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", - "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", "dev": true, "requires": { "array-includes": "^3.1.1", @@ -10088,8 +7100,6 @@ "dependencies": { "doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -10099,8 +7109,6 @@ }, "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, "requires": { "esrecurse": "^4.3.0", @@ -10109,14 +7117,10 @@ }, "eslint-visitor-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "espree": { "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { "acorn": "^7.4.0", @@ -10126,37 +7130,34 @@ "dependencies": { "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 } } }, "estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "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, "requires": { "is-glob": "^4.0.1" } }, + "globals": { + "version": "13.17.0", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, "ignore": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "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, "requires": { "argparse": "^1.0.7", @@ -10165,36 +7166,37 @@ }, "semver": { "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "type-fest": { + "version": "0.20.2", + "dev": true } } }, "semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "servatron": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/servatron/-/servatron-2.3.1.tgz", + "integrity": "sha512-PZz/KPi1vVwXRN57CJtJIUS1qfNrcRDXbsu/lAxU5B/d08ugXlQ3w3e1vIPWN8/30GkEdoml98/qKduGwhYtmw==", + "requires": { + "mime": "^3.0.0", + "minimist": "^1.2.6" + } + }, "server-destroy": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", - "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==" }, "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, "requires": { "shebang-regex": "^3.0.0" @@ -10202,14 +7204,11 @@ }, "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 }, "side-channel": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -10217,21 +7216,15 @@ } }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.5", "dev": true }, "slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "slice-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -10240,21 +7233,17 @@ } }, "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true }, "sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "standard-engine": { "version": "14.0.1", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-14.0.1.tgz", - "integrity": "sha512-7FEzDwmHDOGva7r9ifOzD3BGdTbA7ujJ50afLVdW/tK14zQEptJjbFuUfn50irqdHDcTbNh0DTIoMPynMCXb0Q==", "dev": true, "requires": { "get-stdin": "^8.0.0", @@ -10263,23 +7252,19 @@ "xdg-basedir": "^4.0.0" } }, - "string-to-color": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/string-to-color/-/string-to-color-2.2.2.tgz", - "integrity": "sha512-XeA2goP7PNsSlz8RRn6KhYswnMf5Tl+38ajfy8n4oZJyMGC4qqKgHNHsZ/3qwvr42NRIjf9eSr721SyetDeMkA==", + "string_decoder": { + "version": "1.3.0", "requires": { - "colornames": "^1.1.1", - "hex-rgb": "^4.1.0", - "lodash.padend": "^4.6.1", - "lodash.trimstart": "^4.5.1", - "lodash.words": "^4.2.0", - "rgb-hex": "^3.0.0" + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1" + } } }, "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, "requires": { "emoji-regex": "^8.0.0", @@ -10289,8 +7274,6 @@ }, "string.prototype.matchall": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", - "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10305,8 +7288,6 @@ }, "string.prototype.trimend": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10316,8 +7297,6 @@ }, "string.prototype.trimstart": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10327,8 +7306,6 @@ }, "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, "requires": { "ansi-regex": "^5.0.1" @@ -10336,34 +7313,21 @@ }, "strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "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 }, "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, "requires": { "has-flag": "^4.0.0" } }, - "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 - }, "table": { "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -10375,8 +7339,6 @@ "dependencies": { "ajv": { "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -10387,24 +7349,20 @@ }, "json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true } } }, "tcpocket": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/tcpocket/-/tcpocket-5.0.6.tgz", - "integrity": "sha512-9VeOfMGJd0x0vPdz6b2PUT0O5R5l+xWaDLxfpHJJPYpB3INE7ZEfeGo+3GrUjKZ9U1sjJNCvN7WjW6x44HFJ0Q==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tcpocket/-/tcpocket-7.5.2.tgz", + "integrity": "sha512-3U8Jw8MI0q8se1f6gk2vCNjzEiSyFifB/A2TH4xauptwEaGCalCNAboaO8U2fMn3mexzLh5vcq7prPU0KhYQfg==", "requires": { - "ndjson-fe": "^1.2.7" + "increlation": "^2.0.1" } }, "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, "requires": { "@istanbuljs/schema": "^0.1.2", @@ -10414,50 +7372,58 @@ }, "text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "tick-tock": { + "version": "1.0.0", + "requires": { + "millisecond": "0.1.x" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true }, "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, "requires": { "is-number": "^7.0.0" } }, "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "version": "3.11.0", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.6", + "minimist": "^1.2.0", "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } } }, "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, "requires": { "prelude-ls": "^1.2.1" } }, "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 + "version": "2.18.0" }, "unbox-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10468,13 +7434,37 @@ }, "uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" } }, + "use-http": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/use-http/-/use-http-1.0.26.tgz", + "integrity": "sha512-yB0dXX2S0Doyiti/kHqMsvlShL3tlI8YkoEARao1OVFKrGvyXejmWvrYkEI+oVTPvUqGzOsHbNROY0qKDC88Pg==", + "requires": { + "urs": "^0.0.8", + "use-ssr": "^1.0.24", + "utility-types": "^3.10.0" + }, + "dependencies": { + "urs": { + "version": "0.0.8", + "requires": {} + }, + "use-ssr": { + "version": "1.0.24", + "requires": {} + } + } + }, + "util-deprecate": { + "version": "1.0.2" + }, + "utility-types": { + "version": "3.10.0" + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -10482,25 +7472,19 @@ }, "v8-compile-cache": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", + "version": "9.0.1", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^1.6.0" } }, "which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -10508,8 +7492,6 @@ }, "which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "requires": { "is-bigint": "^1.0.1", @@ -10521,14 +7503,10 @@ }, "word-wrap": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, "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, "requires": { "ansi-styles": "^4.0.0", @@ -10538,51 +7516,37 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-response": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/write-response/-/write-response-1.2.3.tgz", "integrity": "sha512-Na6IPeWSJJsu3sqGmvVVsEAhgCSjbycZOQJJc8mm8Ek3zX4u2kkoFXDHouWw6Wd0VdAJLfuoWEnHVsGqKv0/LQ==", + "dev": true, "requires": { "error-with-object": "^1.1.0" } }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "requires": {} - }, - "wtfnode": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.8.4.tgz", - "integrity": "sha512-64GEKtMt/MUBuAm+8kHqP74ojjafzu00aT0JKsmkIwYmjRQ/odO0yhbzKLm+Z9v1gMla+8dwITRKzTAlHsB+Og==" - }, "xdg-basedir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, "y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true }, "yargs": { "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -10595,15 +7559,11 @@ } }, "yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "version": "20.2.9", "dev": true }, "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 } } diff --git a/package.json b/package.json index 3200c7a..961b326 100644 --- a/package.json +++ b/package.json @@ -1,56 +1,50 @@ { "name": "canhazdb-server", - "version": "7.1.1", - "description": "A shaded and clustered database communicated over http rest.", - "main": "./lib/index.js", - "bin": { - "canhazdb-server": "lib/cli.js" + "version": "8.0.0", + "type": "module", + "description": "", + "main": "lib/index.js", + "scripts": { + "test": "./makeCerts.sh && NODE_ENV=test c8 -x client --check-coverage --lines 83 node test" + }, + "keywords": [], + "author": { + "name": "Mark Wylde", + "email": "me@markwylde.com", + "url": "https://github.com/markwylde" }, - "directories": { - "lib": "lib", - "test": "test" + "semistandard": { + "ignore": "client" }, + "license": "AGPL-3.0", "dependencies": { - "axios": "^0.27.2", - "chalk": "^4.1.1", - "debarrel": "^1.0.1", - "final-stream": "^2.0.3", - "get-port": "^5.1.1", - "hinton": "^1.0.0", - "lockbase": "^1.0.9", - "minimist": "^1.2.5", - "ndjson-fe": "^1.2.7", - "node-ejdb-lite": "^2.73.8", - "qs": "^6.10.1", - "reconnecting-websocket": "^4.4.0", + "@markwylde/liferaft": "^1.3.1", + "chalk": "^5.0.1", + "crypto-random-string": "^5.0.0", + "debarrel": "^1.0.2", + "failmenot": "^3.0.1", + "final-stream": "^2.0.4", + "lockbase": "^5.0.1", + "logslot": "^2.1.1", + "minimist": "^1.2.6", + "mql-to-jql": "^1.5.0", + "node-ejdb-lite": "^2.73.17", + "servatron": "^2.3.2", "server-destroy": "^1.0.1", - "tcpocket": "^5.0.6", - "uuid": "^8.3.2", - "write-response": "^1.2.3", - "ws": "^7.4.6", - "wtfnode": "^0.8.4" + "tcpocket": "^7.5.2", + "use-http": "^1.0.27", + "uuid": "^9.0.0" }, "devDependencies": { - "basictap": "^1.1.13", - "c8": "^7.7.2", - "canhazdb-driver-ejdb": "^1.1.5", - "eslint": "^8.22.0", - "npm": "^8.18.0", - "semistandard": "^16.0.1" - }, - "scripts": { - "lint": "eslint .", - "test": "./makeCerts.sh && c8 -o /tmp node --unhandled-rejections=strict test" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/canhazdb/server.git" - }, - "keywords": [], - "author": "", - "license": "AGPL-3.0", - "bugs": { - "url": "https://github.com/canhazdb/server/issues" - }, - "homepage": "https://github.com/canhazdb/server#readme" + "@emotion/styled": "^11.10.4", + "axios": "^0.27.2", + "basictap": "^3.4.3", + "c8": "^7.12.0", + "classnames": "^2.3.2", + "esbuild": "^0.15.10", + "eslint": "^8.24.0", + "eslint-plugin-react-hooks": "^4.6.0", + "semistandard": "^16.0.1", + "write-response": "^1.2.3" + } } diff --git a/redeploy.sh b/redeploy.sh deleted file mode 100755 index 59559a4..0000000 --- a/redeploy.sh +++ /dev/null @@ -1,7 +0,0 @@ -docker build -t canhazdb . -docker stack rm canhazdb -docker rm -f $(docker ps -aq) -sleep 6 -docker stack deploy -c docker-compose.yml canhazdb -docker service logs canhazdb_canhazdb -f - diff --git a/stack.yml b/stack.yml deleted file mode 100644 index 31a4e16..0000000 --- a/stack.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: "3.8" - -services: - canhazdb: - image: canhazdb/server - command: - - "--join-from-dns=tasks.canhazdb" - - "--tls-ca=/certs/ca.cert.pem" - - "--tls-cert=/certs/canhazdb.cert.pem" - - "--tls-key=/certs/canhazdb.privkey.pem" - - "--host=canhazdb" - - "--data-dir=/data" - environment: - - CANHAZDB_NODE_NAME={{.Task.Name}} - volumes: - - ./data:/data - - ./certs:/certs - deploy: - replicas: 3 diff --git a/stress/index.js b/stress/index.js new file mode 100644 index 0000000..f41f826 --- /dev/null +++ b/stress/index.js @@ -0,0 +1,88 @@ +import tcpocket from 'tcpocket'; +import fs from 'fs'; +import c from '../lib/constants.js'; + +const tls = { + key: fs.readFileSync('./certs/localhost.privkey.pem'), + cert: fs.readFileSync('./certs/localhost.cert.pem'), + ca: [fs.readFileSync('./certs/ca.cert.pem')], + requestCert: true +}; + +const metrics = {}; + +async function main () { + let count = 0; + const client = tcpocket.createClient({ + host: 'localhost', + port: 7060, + ...tls + }); + console.log('Waiting for server to connect...'); + await client.waitUntilConnected(); + setInterval(() => { + console.log(metrics); + }, 500); + console.log('Successfully connected'); + + await Promise.all([ + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar1' + } + }), + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar2' + } + }), + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar3' + } + }) + ]); + + async function run () { + const promises = []; + for (let x = 0; x < 2000; x++) { + promises.push( + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + x + } + }).then((r) => { + count = count + 1; + const seconds = Math.floor(Date.now() / 1000); + metrics[seconds] = metrics[seconds] || 0; + metrics[seconds] = metrics[seconds] + 1; + }) + + // client.send(c.GET, { + // [c.COLLECTION_ID]: 'tests' + // }).then((r) => { + // count = count + 1; + // const seconds = Math.floor(Date.now() / 1000); + // metrics[seconds] = metrics[seconds] || 0; + // metrics[seconds] = metrics[seconds] + 1; + // }) + ); + } + + await Promise.all(promises); + + setTimeout(run); + } + run(); + // client.close(); + + // setTimeout(function () { + // log() // logs out active handles that are keeping node running + // }, 100) +} + +main(); diff --git a/stress/server.js b/stress/server.js new file mode 100644 index 0000000..32763c1 --- /dev/null +++ b/stress/server.js @@ -0,0 +1,8 @@ +import createTestServers from '../test/helpers/createTestServers.js'; + +async function main () { + const servers = await createTestServers(1); + console.log('server started', servers[0].clientConfig); +} + +main(); diff --git a/test/batch.js b/test/batch.js deleted file mode 100644 index 3515c0e..0000000 --- a/test/batch.js +++ /dev/null @@ -1,42 +0,0 @@ -const fs = require('fs'); - -const test = require('basictap'); -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); - -const tls = { - key: fs.readFileSync('./certs/localhost.privkey.pem'), - cert: fs.readFileSync('./certs/localhost.cert.pem'), - ca: [fs.readFileSync('./certs/ca.cert.pem')], - requestCert: true -}; - -test('batch: post two records', async t => { - t.plan(7); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - data: [{ - a: 1 - }, { - a: 2 - }] - }); - - const getRequest1 = await httpRequest(`${node.url}/tests/${postRequest.data[0].document.id}`); - const getRequest2 = await httpRequest(`${node.url}/tests/${postRequest.data[1].document.id}`); - cluster.closeAll(); - - t.equal(postRequest.data[0].status, 201); - t.equal(postRequest.data[0].document.a, 1); - t.equal(getRequest1.data.a, 1); - - t.equal(postRequest.data[1].status, 201); - t.equal(postRequest.data[1].document.a, 2); - t.equal(getRequest2.data.a, 2); - - t.equal(postRequest.status, 201); -}); diff --git a/test/collectionMetadata.js b/test/collectionMetadata.js deleted file mode 100644 index 6b3fb71..0000000 --- a/test/collectionMetadata.js +++ /dev/null @@ -1,119 +0,0 @@ -const fs = require('fs'); - -const test = require('basictap'); -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); - -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); - -const tls = { - key: fs.readFileSync('./certs/localhost.privkey.pem'), - cert: fs.readFileSync('./certs/localhost.cert.pem'), - ca: [fs.readFileSync('./certs/ca.cert.pem')], - requestCert: true -}; - -test('collectionMetadata - create a record', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - await sleep(100); - - const metadataRequest = await httpRequest(`${cluster.nodes[1].url}/system.collections`, { - method: 'GET' - }); - - t.equal(metadataRequest.data[0].documentCount, 1); - - const deleteRequest = await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`, { - method: 'DELETE' - }); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests/${postRequest.data.id}`); - - cluster.closeAll(); - - t.deepEqual(getRequest.data, {}); - - t.equal(postRequest.status, 201); - t.equal(deleteRequest.status, 200); - t.equal(getRequest.status, 404); -}); - -test('collectionMetadata - delete a record before debarrel', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - const deleteRequest = await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`, { - method: 'DELETE' - }); - - await sleep(100); - - const metadataRequest = await httpRequest(`${cluster.nodes[1].url}/system.collections`, { - method: 'GET' - }); - - t.equal(metadataRequest.data[0].documentCount, 0); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests/${postRequest.data.id}`); - - cluster.closeAll(); - - t.deepEqual(getRequest.data, {}); - - t.equal(postRequest.status, 201); - t.equal(deleteRequest.status, 200); - t.equal(getRequest.status, 404); -}); - -test('collectionMetadata - delete a record after tick', async t => { - t.plan(4); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - await sleep(300); - - const deleteRequest = await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`, { - method: 'DELETE' - }); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests/${postRequest.data.id}`); - - cluster.closeAll(); - - t.deepEqual(getRequest.data, {}); - - t.equal(postRequest.status, 201); - t.equal(deleteRequest.status, 200); - t.equal(getRequest.status, 404); -}); diff --git a/test/features/basic.js b/test/features/basic.js new file mode 100644 index 0000000..4efc309 --- /dev/null +++ b/test/features/basic.js @@ -0,0 +1,303 @@ +import test from 'basictap'; +import createTestServers from '../helpers/createTestServers.js'; + +import c from '../../lib/constants.js'; +import tcpocket from 'tcpocket'; + +function createExampleDocuments (client, count, extraData) { + const counts = Array(count).fill('').map((_, index) => index); + + return Promise.all( + counts.map(count => { + return client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + ...extraData, + foo: 'bar' + (count + 1) + } + }); + }) + ); +} + +test('invalid command', async t => { + t.plan(1); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 1); + + const getResponse = await client.send(254); + + t.equal(getResponse.command, c.STATUS_NOT_FOUND, 'has status'); + + await client.close(); + await servers.close(); +}); + +test('info', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + + await client.waitUntilConnected(); + const result = await client.send(c.INFO, { + [c.SYSTEM]: true + }); + + t.equal(result.command, c.STATUS_OK, 'response had 200 status'); + t.equal(result.json()[c.DATA].nodeName.length, 36, 'nodeName has correct length'); + t.equal(result.json()[c.DATA].nodes.length, 1, 'one node was returned'); + t.equal(result.json()[c.DATA].nodes[0].host, servers[0].options.host, 'first node had correct host'); + t.equal(result.json()[c.DATA].nodes[0].port, servers[0].options.port, 'first node had correct port'); + + await Promise.all([ + client.close(), + servers.close() + ]); +}); + +test('count', async t => { + t.plan(2); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 3); + + const getResponse = await client.send(c.COUNT, { + [c.COLLECTION_ID]: 'tests' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA], 3, 'returned 3'); + + await client.close(); + await servers.close(); +}); + +test('get - with order (descending)', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 3); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests', + [c.ORDER]: ['desc(foo)'] + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'returned 1 document'); + + t.equal(getResponse.json()[c.DATA][0].foo, 'bar3', 'has foo property'); + t.equal(getResponse.json()[c.DATA][1].foo, 'bar2', 'has foo property'); + t.equal(getResponse.json()[c.DATA][2].foo, 'bar1', 'has foo property'); + + await client.close(); + await servers.close(); +}); + +test('get - with limit', async t => { + t.plan(2); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 5); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests', + [c.LIMIT]: 3 + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'returned 1 document'); + + await client.close(); + await servers.close(); +}); + +test('post', async t => { + t.plan(11); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const postResponses = await createExampleDocuments(client, 3); + + t.equal(postResponses[0].command, c.STATUS_CREATED, 'has status'); + t.ok(postResponses[0].json()[c.DATA].id, 'has id'); + t.equal(postResponses[0].json()[c.DATA].foo, 'bar1', 'has foo property'); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'returned 1 document'); + + const sortedDocuments = getResponse.json()[c.DATA] + .sort((a, b) => a.foo > b.foo ? 1 : -1); + + t.ok(sortedDocuments[0].id, 'has id property'); + t.equal(sortedDocuments[0].foo, 'bar1', 'has foo property'); + t.ok(sortedDocuments[1].id, 'has id property'); + t.equal(sortedDocuments[1].foo, 'bar2', 'has foo property'); + t.ok(sortedDocuments[2].id, 'has id property'); + t.equal(sortedDocuments[2].foo, 'bar3', 'has foo property'); + + await client.close(); + await servers.close(); +}); + +test('put', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 3); + + const putResponse = await client.send(c.PUT, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { foo: 'barz' } + }); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests' + }); + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(putResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'put 3 documents'); + + const foos = getResponse.json()[c.DATA] + .map(item => item.foo); + t.deepEqual(foos, ['barz', 'barz', 'barz'], 'returned 3 documents'); + + t.equal(putResponse.json()[c.DATA].length, 3, 'altered the correct number of documents'); + + await client.close(); + await servers.close(); +}); + +test('patch', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 3, { b: 1 }); + + const patchResponse = await client.send(c.PATCH, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { foo: 'barz' } + }); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(patchResponse.command, c.STATUS_OK, 'has status'); + t.equal(patchResponse.json()[c.DATA].length, 3, 'patched 3 documents'); + + const finalResponse = getResponse.json()[c.DATA] + .map(item => { + const { id, ...withoutId } = item; + return withoutId; + }); + t.deepEqual(finalResponse, [ + { foo: 'barz', b: 1 }, + { foo: 'barz', b: 1 }, + { foo: 'barz', b: 1 } + ], 'returned 1 document'); + + t.equal(patchResponse.json()[c.DATA].length, 3, 'altered the correct number of documents'); + + await client.close(); + await servers.close(); +}); + +test('delete', async t => { + t.plan(2); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 3); + + const deleteResponse = await client.send(c.DELETE, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { foo: 'bar2' } + }); + + t.equal(deleteResponse.command, c.STATUS_OK, 'has status'); + t.equal(deleteResponse.json()[c.DATA].length, 1, 'returned 1 change'); + + await client.close(); + await servers.close(); +}); + +test('get - with order (ascending)', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createExampleDocuments(client, 3); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests', + [c.ORDER]: ['asc(foo)'] + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'returned 1 document'); + + t.equal(getResponse.json()[c.DATA][0].foo, 'bar1', 'has foo property'); + t.equal(getResponse.json()[c.DATA][1].foo, 'bar2', 'has foo property'); + t.equal(getResponse.json()[c.DATA][2].foo, 'bar3', 'has foo property'); + + await client.close(); + await servers.close(); +}); + +test('system.nodes', async t => { + t.plan(7); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'system.nodes' + }); + + const nodes = getResponse.json()[c.DATA]; + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(nodes.length, 1, 'returned 1'); + + t.equal(nodes[0].connected, true, 'connected was correct'); + t.equal(nodes[0].online, true, 'online was correct'); + t.equal(nodes[0].host, 'localhost', 'host was correct'); + t.ok(nodes[0].port, 'port existed'); + t.equal(nodes[0].status, 'healthy', 'status was correct'); + + await client.close(); + await servers.close(); +}); diff --git a/test/features/cluster.js b/test/features/cluster.js new file mode 100644 index 0000000..4de91e9 --- /dev/null +++ b/test/features/cluster.js @@ -0,0 +1,141 @@ +import test from 'basictap'; +import createTestServers from '../helpers/createTestServers.js'; + +import c from '../../lib/constants.js'; +import tcpocket from 'tcpocket'; + +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +test('cluster - post', async t => { + t.plan(11); + + const servers = await createTestServers(5); + + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const postResponses = await Promise.all([ + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar1' + } + }), + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar2' + } + }), + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar3' + } + }) + ]); + + t.equal(postResponses[0].command, c.STATUS_CREATED, 'has status'); + t.ok(postResponses[0].json()[c.DATA].id, 'has id'); + t.equal(postResponses[0].json()[c.DATA].foo, 'bar1', 'has foo property'); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'returned 1 document'); + + const sortedDocuments = getResponse.json()[c.DATA] + .sort((a, b) => a.foo > b.foo ? 1 : -1); + + t.ok(sortedDocuments[0].id, 'has id property'); + t.equal(sortedDocuments[0].foo, 'bar1', 'has foo property'); + t.ok(sortedDocuments[1].id, 'has id property'); + t.equal(sortedDocuments[1].foo, 'bar2', 'has foo property'); + t.ok(sortedDocuments[2].id, 'has id property'); + t.equal(sortedDocuments[2].foo, 'bar3', 'has foo property'); + + await client.close(); + await servers.close(); +}); + +test('cluster - post - one goes down', async t => { + t.plan(12); + + const servers = await createTestServers(3); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const postResponses = await Promise.all([ + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar1' + } + }), + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar2' + } + }), + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar3' + } + }) + ]); + + t.equal(postResponses[0].command, c.STATUS_CREATED, 'has status'); + t.ok(postResponses[0].json()[c.DATA].id, 'has id'); + t.equal(postResponses[0].json()[c.DATA].foo, 'bar1', 'has foo property'); + + await Promise.all([ + servers[1].close() + ]); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'getResponse has status'); + t.equal(getResponse.json()[c.DATA].length, 3, 'returned 1 document'); + + const sortedDocuments = getResponse.json()[c.DATA] + .sort((a, b) => a.foo > b.foo ? 1 : -1); + + t.ok(sortedDocuments[0].id, 'has id property'); + t.equal(sortedDocuments[0].foo, 'bar1', 'has foo=bar1 property'); + t.ok(sortedDocuments[1].id, 'has id property'); + t.equal(sortedDocuments[1].foo, 'bar2', 'has foo=bar2 property'); + t.ok(sortedDocuments[2].id, 'has id property'); + t.equal(sortedDocuments[2].foo, 'bar3', 'has foo=bar3 property'); + + await client.close(); + await servers.close(); + + t.pass(); +}); + +test('cluster - syncing - node goes down', async t => { + t.plan(1); + + const servers = await createTestServers(2); + await sleep(50); + + await Promise.all([ + servers[1].close() + ]); + + await sleep(500); + + t.pass('completed at least one sync without crashing'); + + await servers.close(); +}); diff --git a/test/features/conflicts.js b/test/features/conflicts.js new file mode 100644 index 0000000..fa49d4d --- /dev/null +++ b/test/features/conflicts.js @@ -0,0 +1,174 @@ +import assert from 'assert'; +import c from '../../lib/constants.js'; +import createTestServers from '../helpers/createTestServers.js'; +import tcpocket from 'tcpocket'; +import test from 'basictap'; +import waitUntil from '../../lib/utils/waitUntil.js'; + +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +async function createConflict (servers, client) { + let disablePost = true; + + servers[1].controllers.internal.add({ + command: c.POST, + priority: 10, + conditions: [() => disablePost], + handler: async () => { + throw new Error('some error, preventing post'); + } + }); + + // Post a new document + const result = await client.send(c.POST, { + [c.COLLECTION_ID]: 'test', + [c.DATA]: { + foo: 'bar' + } + }); + + assert.equal(result.command, c.STATUS_CREATED); + + // Test all servers receive the conflict + await sleep(500); + + for (const server of servers) { + const foundConflict = server.conflicts.items.find(conflict => { + return conflict.document && conflict.document.foo === 'bar'; + }); + + assert.ok(foundConflict); + } + + // Disable our fake error and test all servers receive the resolution + disablePost = false; +} + +test.skip('conflicts - post failure creates conflict', async t => { + t.plan(2); + t.timeout(3000); + + console.log('THERE IS A RACE CONDITION BUG IN THIS TEST'); + + const servers = await createTestServers(2); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createConflict(servers, client); + + await sleep(500); + + for (const server of servers) { + const foundConflict = server.conflicts.items.find(conflict => { + return !conflict.resolved && conflict.document && conflict.document.foo === 'bar'; + }); + + t.equal(foundConflict, undefined, 'conflict not found'); + } + + await waitUntil(() => { + const unhealthyServers = servers.filter((server) => { + console.log('RACE CONDITION: May be here?'); + return server.thisNode.status !== 'healthy'; + }); + + return unhealthyServers.length === 0; + }); + + await Promise.all([ + client.close(), + servers.close() + ]); +}); + +test('conflicts - cleanup resolved', async t => { + t.plan(4); + t.timeout(3000); + + const servers = await createTestServers(2); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await createConflict(servers, client); + + await sleep(500); + + for (const server of servers) { + const foundConflict = server.conflicts.items.find(conflict => { + return !conflict.resolved && conflict.document && conflict.document.foo === 'bar'; + }); + + t.equal(foundConflict, undefined, 'conflict not found'); + } + + await sleep(1500); + + for (const server of servers) { + const foundConflict = server.conflicts.items.find(conflict => { + return conflict.document && conflict.document.foo === 'bar'; + }); + + t.equal(foundConflict, undefined, 'conflict should not be found'); + } + + await Promise.all([ + client.close(), + servers.close() + ]); +}); + +test('conflicts - post to offline node', async t => { + t.plan(9); + t.timeout(5000); + + const servers = await createTestServers(3); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await servers[2].close(); + + // Post a new document + const result = await client.send(c.POST, { + [c.COLLECTION_ID]: 'test', + [c.DATA]: { + foo: 'bar' + } + }); + + t.equal(result.command, c.STATUS_CREATED, 'post should return STATUS_CREATED'); + + // Test all servers receive the conflict + await sleep(500); + + for (const server of servers.slice(0, -1)) { + const foundConflict = server.conflicts.items.find(conflict => { + return conflict.document && conflict.document.foo === 'bar'; + }); + + t.ok(foundConflict, 'found conflict'); + } + + // Disable our fake error and test all servers receive the resolution + servers[2] = await servers[2].recreate(); + + await sleep(500); + + for (const server of servers) { + const foundConflict = server.conflicts.items.find(conflict => { + return !conflict.resolved && conflict.document && conflict.document.foo === 'bar'; + }); + + t.equal(foundConflict, undefined, 'conflict not found'); + } + + await sleep(500); + + for (const server of servers) { + t.equal(server.thisNode.status, 'healthy', 'server status is healthy'); + } + + await Promise.all([ + client.close(), + servers.close() + ]); +}); diff --git a/test/features/health.js b/test/features/health.js new file mode 100644 index 0000000..c0595af --- /dev/null +++ b/test/features/health.js @@ -0,0 +1,74 @@ +import test from 'basictap'; +import { v4 as uuid } from 'uuid'; +import { getNewPort, tls } from '../helpers/createTestServers.js'; + +import c from '../../lib/constants.js'; +import tcpocket from 'tcpocket'; +import canhazdb from '../../lib/index.js'; + +test('health - info system route works as intended', async t => { + t.plan(4); + + const port = getNewPort(); + const nodeName = uuid(); + + const server = await canhazdb({ + dataDirectory: './canhazdata/' + nodeName, + nodeName: nodeName, + host: 'localhost', + port: port, + join: ['localhost:10001'], + tls + }); + + const client = tcpocket.createClient(server.clientConfig); + await client.waitUntilConnected(); + + const result = await client.send(c.INFO, { + [c.SYSTEM]: true + }); + + const resultData = result.json()[c.DATA]; + + t.equal(server.thisNode.status, 'unhealthy', 'server had unhealthy status'); + + t.equal(result.command, c.STATUS_OK, 'response had 200 status'); + t.equal(resultData.nodeName.length, 36, 'nodeName has correct length'); + t.equal(resultData.nodes.length, 2, 'two nodes where returned'); + + await Promise.all([ + client.close(), + server.close() + ]); +}); + +test('health - unhealthy nodes reject external routes', async t => { + t.plan(2); + + const port = getNewPort(); + const nodeName = uuid(); + + const server = await canhazdb({ + dataDirectory: './canhazdata/' + nodeName, + nodeName: nodeName, + host: 'localhost', + port: port, + join: ['localhost:10001'], + tls + }); + + const client = tcpocket.createClient(server.clientConfig); + await client.waitUntilConnected(); + + const result = await client.send(c.GET, { + [c.COLLECTION_ID]: 'test' + }); + + t.equal(result.command, c.STATUS_SERVER_UNHEALTHY, 'response had offline status'); + t.equal(result.data, undefined); + + await Promise.all([ + client.close(), + server.close() + ]); +}); diff --git a/test/features/http/index.js b/test/features/http/index.js new file mode 100644 index 0000000..ef70782 --- /dev/null +++ b/test/features/http/index.js @@ -0,0 +1,80 @@ +import fs from 'fs'; +import test from 'basictap'; +import httpRequest from '../../helpers/httpRequest.js'; +import c from '../../../lib/constants.js'; + +import prepareTest from './prepareTest.js'; +import rootMethodNotAllowed from './rootMethodNotAllowed.js'; +import validateBodyExists from './validateBodyExists.js'; +import validateBodyJson from './validateBodyJson.js'; + +const packageJson = JSON.parse( + fs.readFileSync('./package.json', 'utf8') +); + +test('get: root pathname', async t => { + t.plan(2); + + const { client, servers, domain } = await prepareTest(); + + const request = await httpRequest(`https://${domain}/`); + + await client.close(); + await servers.close(); + + t.equal(request.headers['content-type'], 'application/json'); + + t.deepEqual(request.data, { + info: 'https://canhazdb.com', + name: packageJson.name, + status: 200, + version: packageJson.version + }); +}); + +test('post: root pathname', rootMethodNotAllowed('post')); +test('put: root pathname', rootMethodNotAllowed('put')); +test('patch: root pathname', rootMethodNotAllowed('patch')); +test('delete: root pathname', rootMethodNotAllowed('delete')); + +test('post: body exists', validateBodyExists('post')); +test('put: body exists', validateBodyExists('put')); +test('patch: body exists', validateBodyExists('patch')); + +test('post: body is json', validateBodyJson('post')); +test('put: body is json', validateBodyJson('put')); +test('patch: body is json', validateBodyJson('patch')); + +test('http - get collection', async t => { + t.plan(3); + + const { client, servers, domain } = await prepareTest(); + + const request = await httpRequest(`https://${domain}/tests`); + const documents = request.data.sort((a, b) => { + return a.foo > b.foo ? 1 : -1; + }); + + t.equal(request.status, 200); + t.equal(documents.length, 3); + t.equal(documents[0].foo, 'bar1'); + + await client.close(); + await servers.close(); +}); + +test('http - get document', async t => { + t.plan(3); + + const { client, servers, domain, exampleDocuments } = await prepareTest(); + const document = exampleDocuments[0].json()[c.DATA]; + + const request = await httpRequest(`https://${domain}/tests/${document.id}`); + + t.equal(request.status, 200); + t.ok(request.data.id, 'has an id'); + t.equal(request.data.foo, 'bar1'); + + await client.close(); + await servers.close(); +}); diff --git a/test/features/http/prepareTest.js b/test/features/http/prepareTest.js new file mode 100644 index 0000000..f21e93a --- /dev/null +++ b/test/features/http/prepareTest.js @@ -0,0 +1,16 @@ +import tcpocket from 'tcpocket'; +import createTestServers from '../../helpers/createTestServers.js'; +import createExampleDocuments from '../../helpers/createExampleDocuments.js'; + +async function prepareTest () { + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + const domain = `${servers[0].options.httpHost}:${servers[0].options.httpPort}`; + + const exampleDocuments = await createExampleDocuments(client, 3); + + return { client, servers, domain, exampleDocuments }; +} + +export default prepareTest; diff --git a/test/features/http/rootMethodNotAllowed.js b/test/features/http/rootMethodNotAllowed.js new file mode 100644 index 0000000..670f8ee --- /dev/null +++ b/test/features/http/rootMethodNotAllowed.js @@ -0,0 +1,20 @@ +import httpRequest from '../../helpers/httpRequest.js'; +import prepareTest from './prepareTest.js'; + +function rootMethodNotAllowed (method) { + return async t => { + t.plan(2); + + const { client, servers, domain } = await prepareTest(); + + const request = await httpRequest(`https://${domain}/`, { method }); + + await client.close(); + await servers.close(); + + t.deepEqual(request.data, { error: 'method not allowed' }); + t.equal(request.status, 405); + }; +} + +export default rootMethodNotAllowed; diff --git a/test/features/http/validateBodyExists.js b/test/features/http/validateBodyExists.js new file mode 100644 index 0000000..2ed5cb5 --- /dev/null +++ b/test/features/http/validateBodyExists.js @@ -0,0 +1,20 @@ +import httpRequest from '../../helpers/httpRequest.js'; +import prepareTest from './prepareTest.js'; + +function validateBodyExists (method) { + return async t => { + t.plan(2); + + const { client, servers, domain } = await prepareTest(); + + const request = await httpRequest(`https://${domain}/tests`, { method }); + + await client.close(); + await servers.close(); + + t.deepEqual(request.data, { error: 'empty request body not allowed' }); + t.equal(request.status, 400); + }; +} + +export default validateBodyExists; diff --git a/test/features/http/validateBodyJson.js b/test/features/http/validateBodyJson.js new file mode 100644 index 0000000..6f7fbfd --- /dev/null +++ b/test/features/http/validateBodyJson.js @@ -0,0 +1,23 @@ +import httpRequest from '../../helpers/httpRequest.js'; +import prepareTest from './prepareTest.js'; + +function validateBodyJson (method) { + return async t => { + t.plan(2); + + const { client, servers, domain } = await prepareTest(); + + const request = await httpRequest(`https://${domain}/tests`, { + method, + data: 'this is not json' + }); + + await client.close(); + await servers.close(); + + t.deepEqual(request.data, { error: 'request body not valid json' }); + t.equal(request.status, 400); + }; +} + +export default validateBodyJson; diff --git a/test/features/lock.js b/test/features/lock.js new file mode 100644 index 0000000..6e207e0 --- /dev/null +++ b/test/features/lock.js @@ -0,0 +1,407 @@ +import test from 'basictap'; +import createTestServers from '../helpers/createTestServers.js'; + +import c from '../../lib/constants.js'; +import tcpocket from 'tcpocket'; +import waitUntil from '../../lib/utils/waitUntil.js'; + +test('lock - and post some data (success)', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const lockRequest = await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + const postRequest = await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID], + [c.DATA]: { + foo: 'bar' + } + }); + + const getRequest = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { id: postRequest.json()[c.DATA].id } + }); + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID] + }); + t.equal(unlockRequest.command, c.STATUS_OK); + + await client.close(); + await servers.close(); + + t.equal(postRequest.command, c.STATUS_CREATED); + + const getData = getRequest.json()[c.DATA]; + + t.deepEqual(getRequest.json()[c.DATA], [{ + id: getData[0].id ? getData[0].id : t.fail(), + foo: 'bar' + }]); + + t.equal(postRequest.command, c.STATUS_CREATED); + t.equal(getRequest.command, c.STATUS_OK); +}); + +test('lock - delete lock with incorrect id', async t => { + t.plan(1); + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: 'wrong' + }); + + t.equal(unlockRequest.command, c.STATUS_NOT_FOUND); + + await client.close(); + await servers.close(); +}); + +test('lock - multiple happen in order', async t => { + t.plan(6); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + let firstFinished = false; + let secondFinished = false; + + const first = client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }).then(async lockRequest => { + const postRequest = await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID], + [c.DATA]: { + a: 1 + } + }); + + t.equal(postRequest.command, c.STATUS_CREATED); + + firstFinished = true; + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID] + }); + + t.equal(unlockRequest.command, c.STATUS_OK); + }); + + const second = client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }).then(async lockRequest => { + t.ok(firstFinished, 'first lock has finished before second starts'); + + const postRequest = await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID], + [c.DATA]: { + a: 2 + } + }); + + t.equal(postRequest.command, c.STATUS_CREATED); + + secondFinished = true; + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID] + }); + + t.equal(unlockRequest.command, c.STATUS_OK); + }); + + await Promise.all([first, second]); + + await client.close(); + await servers.close(); + + t.ok(secondFinished, 'second lock ran'); +}); + +test('lock - and post some data (conflict + fail)', async t => { + t.plan(2); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const lockRequest = await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + const postRequest = await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_STRATEGY]: c.LOCK_STRATEGY_FAIL, + [c.DATA]: { + foo: 'bar' + } + }); + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID] + }); + + t.equal(unlockRequest.command, c.STATUS_OK); + + await client.close(); + await servers.close(); + + t.equal(postRequest.command, c.STATUS_SERVER_ERROR); +}); + +test('lock - and post some data (conflict + wait)', async t => { + t.plan(5); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const lockRequest = await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID], + [c.LOCK_STRATEGY]: c.LOCK_STRATEGY_WAIT, + [c.DATA]: { + foo: 'bar' + } + }).then(async postRequest => { + const postDocument = postRequest.json()[c.DATA]; + + const getRequest = await client.send(c.GET, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { id: postDocument.id } + }); + + await servers.close(); + + t.equal(postRequest.command, c.STATUS_CREATED); + t.deepEqual(postDocument, { + id: postDocument.id ? postDocument.id : t.fail(), + foo: 'bar' + }); + + t.equal(postRequest.command, c.STATUS_CREATED); + t.equal(getRequest.command, c.STATUS_OK); + }); + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID] + }); + + t.equal(unlockRequest.command, c.STATUS_OK); +}); + +test('lock - all methods lock', async t => { + t.plan(4); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + let unlocked = false; + + const postRequest = await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + } + }); + + const postDocument = postRequest.json()[c.DATA]; + + const lockRequest = await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + const putRequest = client.send(c.PUT, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { id: postDocument.id }, + [c.DATA]: { + foo: 'baz' + } + }); + + const patchRequest = client.send(c.PATCH, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { id: postDocument.id }, + [c.DATA]: { + foo: 'baz' + } + }); + + Promise.all([putRequest, patchRequest]) + .then(async (args) => { + const deleteRequest = await client.send(c.DELETE, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { id: postDocument.id } + }); + + await await servers.close(); + t.deepEqual(args.map(arg => arg.command), [c.STATUS_OK, c.STATUS_OK]); + t.equal(deleteRequest.command, c.STATUS_OK); + t.ok(unlocked, 'requests happened after unlock'); + }); + + const unlockRequest = await client.send(c.UNLOCK, { + [c.LOCK_ID]: lockRequest.json()[c.LOCK_ID] + }); + + t.equal(unlockRequest.command, c.STATUS_OK); + + unlocked = true; +}); + +test('lock - and wait but client closes', async t => { + t.plan(1); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_STRATEGY]: c.LOCK_STRATEGY_WAIT, + [c.DATA]: { + foo: 'bar' + } + }).then(() => { + t.fail('should not have resolved successfully'); + }).catch(async error => { + await servers.close(); + t.equal(error.message, 'client disconnected'); + }); + + setTimeout(() => { + client.close(); + }, 200); +}); + +test('lock - and wait but node closes', async t => { + t.plan(1); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + await servers.waitForInitialLocks(); + + await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.LOCK_STRATEGY]: c.LOCK_STRATEGY_WAIT, + [c.DATA]: { + foo: 'bar' + } + }).then((postResponse) => { + t.equal(postResponse.command, c.STATUS_SERVER_ERROR); + client.close(); + }); + + setTimeout(() => { + servers.close(); + }, 500); +}); + +test('lock - system collection (system.locks)', async t => { + t.plan(4); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const lockRequest = await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + t.equal(lockRequest.command, c.STATUS_OK, 'lockRequest has ok status'); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'system.locks' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'getResponse has ok status'); + + const locks = getResponse.json()[c.DATA]; + + const filteredLocks = locks.filter(lock => lock.path === 'tests'); + + t.equal(filteredLocks.length, 1, 'had 1 lock'); + t.ok(filteredLocks[0].id, 'first lock had id'); + + await client.close(); + await servers.close(); +}); + +test('lock - resolves only after all servers are synced with lock', async t => { + t.plan(3); + + const servers = await createTestServers(3); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + await servers.waitForInitialLocks(); + + await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + t.equal(servers[0].locks.queue.length, 1); + t.equal(servers[1].locks.queue.length, 1); + t.equal(servers[2].locks.queue.length, 1); + + await client.close(); + await servers.close(); +}); + +test('lock - releases when node disconnects', async t => { + t.plan(3); + + const servers = await createTestServers(3); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + // await servers.waitForInitialLocks(); + + const lockResult = await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + t.equal(lockResult.command, c.STATUS_OK, 'lock had ok status'); + + { + const testLocks = servers[1].locks.queue.filter(lock => lock.path === 'tests'); + t.equal(testLocks.length, 1, 'lock was added'); + } + + await servers[0].close(); + + const testLocks = await waitUntil(() => { + const testLocks = servers[1].locks.queue.filter(lock => lock.path === 'tests'); + + return testLocks.length === 0 ? testLocks : null; + }); + + t.equal(testLocks.length, 0, 'lock was removed'); + + await client.close(); + await servers.close(); +}); diff --git a/test/features/notify.js b/test/features/notify.js new file mode 100644 index 0000000..7303c57 --- /dev/null +++ b/test/features/notify.js @@ -0,0 +1,394 @@ +import test from 'basictap'; +import createTestServers from '../helpers/createTestServers.js'; + +import c from '../../lib/constants.js'; +import tcpocket from 'tcpocket'; + +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +function createExampleDocuments (client, count, extraData) { + const counts = Array(count).fill('').map((_, index) => index); + + return Promise.all( + counts.map(count => { + return client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + ...extraData, + foo: 'bar' + (count + 1) + } + }); + }) + ); +} + +test('notify - with multiple servers', async t => { + t.plan(4); + + const servers = await createTestServers(2); + const client1 = tcpocket.createClient(servers[0].clientConfig); + const client2 = tcpocket.createClient(servers[1].clientConfig); + await client1.waitUntilConnected(); + await client2.waitUntilConnected(); + + client1.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"POST:/tests/')); + }); + + const notifyResponse = await client1.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + await client2.send(c.POST, { + [c.COLLECTION_ID]: 'notests', + [c.DATA]: { + baz: 'baz' + } + }); + + const postResponse = await client2.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + } + }); + + t.equal(postResponse.command, c.STATUS_CREATED, 'postResponse has STATUS_CREATED'); + + await sleep(200); + + await client1.send(c.NOTIFY_OFF, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + await client2.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + } + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + setTimeout(async () => { + await client1.close(); + await client2.close(); + await servers.close(); + t.pass('instance closed successfully'); + }, 200); +}); + +test('notify', async t => { + t.plan(4); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + client.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"POST:/tests/')); + }); + + const notifyResponse = await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + await client.send(c.POST, { + [c.COLLECTION_ID]: 'notests', + [c.DATA]: { + baz: 'baz' + } + }); + + const postResponse = await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + } + }); + + t.equal(postResponse.command, c.STATUS_CREATED, 'postResponse has STATUS_CREATED'); + + await sleep(200); + + await client.send(c.NOTIFY_OFF, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + } + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + setTimeout(async () => { + await client.close(); + await servers.close(); + t.pass('instance closed successfully'); + }, 200); +}); + +test('notify - post', async t => { + t.plan(3); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + client.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"POST:/tests/')); + }); + + const notifyResponse = await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: 'POST:/tests/.*' + }); + + await client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + food: 'bar' + } + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + await sleep(100); + + await client.close(); + await servers.close(); +}); + +test('notify - put', async t => { + t.plan(3); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const documents = await createExampleDocuments(client, 3); + const documentId = documents[0].json()[c.DATA].id; + + client.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"PUT:/tests/' + documentId)); + }); + + const notifyResponse = await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: 'PUT:/tests/.*' + }); + + await client.send(c.PUT, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { + foo: 'bar1' + }, + [c.DATA]: { + foo: 'baz' + } + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + await sleep(100); + + await client.close(); + await servers.close(); +}); + +test('notify - patch', async t => { + t.plan(3); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const documents = await createExampleDocuments(client, 3); + const documentId = documents[0].json()[c.DATA].id; + + client.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"PATCH:/tests/' + documentId)); + }); + + const notifyResponse = await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: 'PATCH:/tests/.*' + }); + + await client.send(c.PATCH, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { + foo: 'bar1' + }, + [c.DATA]: { + foo: 'baz' + } + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + await sleep(100); + + await client.close(); + await servers.close(); +}); + +test('notify - delete', async t => { + t.plan(3); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const documents = await createExampleDocuments(client, 3); + const documentId = documents[0].json()[c.DATA].id; + + client.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"DELETE:/tests/' + documentId)); + }); + + const notifyResponse = await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: 'DELETE:/tests/.*' + }); + + await client.send(c.DELETE, { + [c.COLLECTION_ID]: 'tests', + [c.QUERY]: { + foo: 'bar1' + } + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + await sleep(100); + + await client.close(); + await servers.close(); +}); + +test('notify - client disconnections clean up', async t => { + t.plan(1); + + const servers = await createTestServers(2); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + client.close(); + + await sleep(100); + + t.equal(servers[0].notify.internalNotifiers.length, 0, 'internal notifier was removed'); + + await servers.close(); +}); + +test('notify - reconnections', async t => { + t.plan(3); + + let [server1, server2, server3] = await createTestServers(3); + const [client1] = [ + tcpocket.createClient(server1.clientConfig) + ]; + await client1.waitUntilConnected(); + + client1.on('message', ({ command, data }) => { + if (command !== c.NOTIFY) { + return; + } + + t.equal(command, c.NOTIFY); + t.ok(data.toString().startsWith('{"' + c.DATA + '":"POST:/tests/')); + }); + + await client1.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + await server2.close(); + await sleep(100); + server2 = await server2.recreate(); + await sleep(100); + + const client2 = tcpocket.createClient(server2.clientConfig); + await client2.waitUntilConnected(); + + const postResponse = await client2.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + foo: 'bar' + } + }); + + t.equal(postResponse.command, c.STATUS_CREATED); + + await sleep(200); + + await Promise.all([ + client1.close(), + client2.close(), + server1.close(), + server2.close(), + server3.close() + ]); +}); + +test('notify - system collection (system.notifys)', async t => { + t.plan(3); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const notifyResponse = await client.send(c.NOTIFY_ON, { + [c.NOTIFY_PATH]: '.*:/tests/.*' + }); + + t.equal(notifyResponse.command, c.STATUS_OK, 'has status'); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'system.notifys' + }); + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + + t.deepEqual(getResponse.json()[c.DATA], [ + { notifyPath: '.*:/tests/.*' } + ]); + + await client.close(); + await servers.close(); +}); diff --git a/test/features/raft.js b/test/features/raft.js new file mode 100644 index 0000000..408642b --- /dev/null +++ b/test/features/raft.js @@ -0,0 +1,54 @@ +import test from 'basictap'; +import tcpocket from 'tcpocket'; +import createTestServers from '../helpers/createTestServers.js'; +import waitUntil from '../../lib/utils/waitUntil.js'; +import c from '../../lib/constants.js'; + +test('raft - one node elect self as leader', async t => { + t.plan(1); + + const servers = await createTestServers(1); + const leader = await waitUntil(() => { + return servers[0]?.raft?.leader; + }); + + t.ok(leader, 'leader was elected'); + + await servers.close(); +}); + +test('raft - two nodes elect a leader', async t => { + t.plan(1); + + const servers = await createTestServers(2); + const leader = await waitUntil(() => { + return servers[0]?.raft?.leader; + }); + + t.ok(leader, 'leader was elected'); + + await servers.close(); +}); + +test('raft - lock syncs raft state to all nodes', async t => { + t.plan(2); + t.timeout(5000); + + const servers = await createTestServers(2); + + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + await servers.waitForInitialLocks(); + + await client.send(c.LOCK, { + [c.LOCK_KEY]: 'tests' + }); + + await t.waitFor(async () => { + t.deepEqual(servers[0].raft.state.locks?.queue?.length, 1); + t.deepEqual(servers[1].raft.state.locks?.queue?.length, 1); + }); + + await client.close(); + await servers.close(); +}); diff --git a/test/features/systemCollections.js b/test/features/systemCollections.js new file mode 100644 index 0000000..585f28a --- /dev/null +++ b/test/features/systemCollections.js @@ -0,0 +1,102 @@ +import test from 'basictap'; +import createTestServers from '../helpers/createTestServers.js'; + +import c from '../../lib/constants.js'; +import tcpocket from 'tcpocket'; + +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +function createExampleDocuments (client, count, extraData) { + const counts = Array(count).fill('').map((_, index) => index); + + return Promise.all( + counts.map(count => { + return client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + ...extraData, + foo: 'bar' + (count + 1) + } + }); + }) + ); +} + +test('systemCollections - post increments documentCount', async t => { + t.plan(6); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + const postResponses = await createExampleDocuments(client, 3); + + t.equal(postResponses[0].command, c.STATUS_CREATED, 'has correct status'); + + await sleep(3000); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'system.collections', + [c.QUERY]: { collectionId: 'tests' } + }); + + const documents = getResponse.json()[c.DATA]; + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(documents.length, 1, 'returned 1 document'); + t.ok(documents[0].id, 'had id'); + t.equal(documents[0].collectionId, 'tests', 'collectionId is tests'); + t.equal(documents[0].documentCount, 3, 'documentCount is 3'); + + await client.close(); + await servers.close(); +}); + +test('systemCollections - post batch increments documentCount', async t => { + t.plan(10); + + const servers = await createTestServers(1); + const client = tcpocket.createClient(servers[0].clientConfig); + await client.waitUntilConnected(); + + // First batch + { + await createExampleDocuments(client, 3); + await sleep(3000); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'system.collections', + [c.QUERY]: { collectionId: 'tests' } + }); + + const documents = getResponse.json()[c.DATA]; + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(documents.length, 1, 'returned 1 document'); + t.ok(documents[0].id, 'had id'); + t.equal(documents[0].collectionId, 'tests', 'collectionId is tests'); + t.equal(documents[0].documentCount, 3, 'documentCount is 3'); + } + + // Second batch + { + await createExampleDocuments(client, 3); + await sleep(250); + + const getResponse = await client.send(c.GET, { + [c.COLLECTION_ID]: 'system.collections', + [c.QUERY]: { collectionId: 'tests' } + }); + + const documents = getResponse.json()[c.DATA]; + + t.equal(getResponse.command, c.STATUS_OK, 'has status'); + t.equal(documents.length, 1, 'returned 1 document'); + t.ok(documents[0].id, 'had id'); + t.equal(documents[0].collectionId, 'tests', 'collectionId is tests'); + t.equal(documents[0].documentCount, 6, 'documentCount is 6'); + } + + await client.close(); + await servers.close(); +}); diff --git a/test/helpers/createExampleDocuments.js b/test/helpers/createExampleDocuments.js new file mode 100644 index 0000000..0d44db4 --- /dev/null +++ b/test/helpers/createExampleDocuments.js @@ -0,0 +1,19 @@ +import c from '../../lib/constants.js'; + +function createExampleDocuments (client, count, extraData) { + const counts = Array(count).fill('').map((_, index) => index); + + return Promise.all( + counts.map(count => { + return client.send(c.POST, { + [c.COLLECTION_ID]: 'tests', + [c.DATA]: { + ...extraData, + foo: 'bar' + (count + 1) + } + }); + }) + ); +} + +export default createExampleDocuments; diff --git a/test/helpers/createTestCluster.js b/test/helpers/createTestCluster.js deleted file mode 100644 index de5aa27..0000000 --- a/test/helpers/createTestCluster.js +++ /dev/null @@ -1,55 +0,0 @@ -const fs = require('fs'); -const uuid = require('uuid').v4; -const canhazdb = require('../../lib'); - -const selectRandomItemFromArray = require('../../utils/selectRandomItemFromArray'); - -try { - fs.rmdirSync('./canhazdata', { recursive: true }); -} catch (error) { - console.log(error); -} - -let lastUsedPort = 11000; -const getNewPort = () => { - lastUsedPort = lastUsedPort + 1; - return lastUsedPort; -}; - -async function createTestCluster (count, tls) { - const nodeOptions = Array(count) - .fill(null) - .map((_, index) => { - const port = getNewPort(); - - return { - host: 'localhost', - logger: () => {}, - port, - queryPort: getNewPort(), - dataDirectory: './canhazdata/' + uuid(), - tls - }; - }); - - const nodePromises = nodeOptions - .map((options) => canhazdb({ - ...options, - join: nodeOptions.map(options => `localhost:${options.port}`) - })); - - const nodes = await Promise.all(nodePromises); - - return { - getRandomNodeUrl: () => { - return selectRandomItemFromArray(nodes); - }, - - closeAll: () => { - return Promise.all(nodes.map(node => node.close())); - }, - - nodes - }; -} -module.exports = createTestCluster; diff --git a/test/helpers/createTestServers.js b/test/helpers/createTestServers.js new file mode 100644 index 0000000..04bc039 --- /dev/null +++ b/test/helpers/createTestServers.js @@ -0,0 +1,110 @@ +import fs from 'fs'; +import { promisify } from 'util'; +import { v4 as uuid } from 'uuid'; +import canhazdb from '../../lib/index.js'; + +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +try { + fs.rmSync('./canhazdata', { recursive: true }); +} catch (error) {} +fs.mkdirSync('./canhazdata'); + +export const tls = { + key: fs.readFileSync('./certs/localhost.privkey.pem'), + cert: fs.readFileSync('./certs/localhost.cert.pem'), + ca: [fs.readFileSync('./certs/ca.cert.pem')], + requestCert: true +}; + +let lastUsedPort = 11000; +export const getNewPort = () => { + lastUsedPort = lastUsedPort + 1; + return lastUsedPort; +}; + +const waitUntil = promisify(function (fn, cb) { + const result = fn(); + if (!result) { + setTimeout(() => waitUntil(fn, cb)); + return; + } + + cb(); +}); + +const defaultOptions = { + waitUntilOnline: true +}; + +async function createTestServers (count, options = {}) { + options = Object.assign({}, defaultOptions, options); + + const join = []; + + const servers = await Promise.all( + Array(count) + .fill(null) + .map(async (_, index) => { + const port = getNewPort(); + const httpPort = getNewPort(); + const nodeName = uuid(); + + const create = async () => { + const server = await canhazdb({ + dataDirectory: './canhazdata/' + nodeName, + nodeName: nodeName, + host: 'localhost', + port: port, + httpHost: 'localhost', + httpPort: httpPort, + join, + tls, + settings: { + infoInterval: 250, + conflictSyncInterval: 100, + conflictCleanupInterval: 1000, + replicas: 3 + } + }); + + server.recreate = create; + + if (options.waitUntilOnline) { + await waitUntil(() => { + return ( + server.thisNode && server.thisNode.status === 'healthy' && + server.nodes.every(node => node.status === 'healthy') && + server?.raft?.leader + ); + }); + } + + return server; + }; + + const server = create(); + + join.push('localhost:' + port); + + return server; + }) + ); + + servers.waitForInitialLocks = function () { + return waitUntil(() => { + return ( + servers[0]?.locks?.incremental > 0 && + servers[0]?.locks?.queue?.length === 0 + ); + }); + }; + + servers.close = function () { + return Promise.all(servers.map(server => server.close())); + }; + + return servers; +} + +export default createTestServers; diff --git a/test/helpers/httpRequest.js b/test/helpers/httpRequest.js index e5dd85f..40be678 100644 --- a/test/helpers/httpRequest.js +++ b/test/helpers/httpRequest.js @@ -1,5 +1,6 @@ -const fs = require('fs'); -const https = require('https'); +import fs from 'fs'; +import https from 'https'; +import axios from 'axios'; const httpsAgent = new https.Agent({ key: fs.readFileSync('./certs/localhost.privkey.pem'), @@ -7,5 +8,7 @@ const httpsAgent = new https.Agent({ ca: [fs.readFileSync('./certs/ca.cert.pem')] }); -module.exports = require('axios') +const instance = axios .create({ httpsAgent, validateStatus: () => true }); + +export default instance; diff --git a/test/helpers/whyAreWeStillRunning.js b/test/helpers/whyAreWeStillRunning.js new file mode 100644 index 0000000..9beee2d --- /dev/null +++ b/test/helpers/whyAreWeStillRunning.js @@ -0,0 +1,26 @@ +import log from 'why-is-node-running'; +import basictap from 'basictap'; + +let timer; +let testsFinished; + +basictap.on('finish', () => { + testsFinished = true; + console.log('Finding hanging tasks...'); + setTimeout(() => { + log(); + }, 5000); +}); + +process.on('beforeExit', () => { + if (testsFinished) { + clearInterval(timer); + return; + } + timer = setInterval(() => { + if (testsFinished) { + clearInterval(timer); + } + log(); + }, 5000); +}); diff --git a/test/index.js b/test/index.js index 7fc01ae..0c621e5 100644 --- a/test/index.js +++ b/test/index.js @@ -1,7 +1,15 @@ -require('../utils/validateAlphaNumericDashDot'); -require('./notify'); -require('./locking'); -require('./integration'); -require('./batch'); -require('./collectionMetadata'); -require('./ws'); +import('./lib/driver/index.js'); +import('./lib/utils/calculateAllowedErrorCount.js'); +import('./lib/prepareOptions.js'); +import('./modules/controllers/createControllerStore.js'); + +import('./features/basic.js'); +import('./features/http/index.js'); +import('./features/raft.js'); +import('./features/lock.js'); +import('./features/cluster.js'); +import('./features/conflicts.js'); +import('./features/notify.js'); +import('./features/systemCollections.js'); + +// import('./features/health.js'); diff --git a/test/integration.js b/test/integration.js deleted file mode 100644 index a465665..0000000 --- a/test/integration.js +++ /dev/null @@ -1,720 +0,0 @@ -const fs = require('fs'); - -const packageJson = require('../package.json'); - -const test = require('basictap'); -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); -const canhazdb = require('../lib'); - -const mapTimes = (times, fn) => Array(times).fill().map((_, index) => fn(index)); -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); - -const tls = { - key: fs.readFileSync('./certs/localhost.privkey.pem'), - cert: fs.readFileSync('./certs/localhost.cert.pem'), - ca: [fs.readFileSync('./certs/ca.cert.pem')], - requestCert: true -}; - -test('get: root pathname', async t => { - t.plan(1); - - const node = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, single: true }); - - const request = await httpRequest(`${node.url}/`); - - await node.close(); - - t.deepEqual(request.data, { - info: 'https://canhazdb.com', - name: packageJson.name, - status: 200, - version: packageJson.version - }); -}); - -function rootMethodNotAllowed (method) { - return async t => { - t.plan(2); - - const node = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, single: true }); - - const request = await httpRequest(`${node.url}/`, { method }); - - await node.close(); - - t.deepEqual(request.data, { error: 'method not allowed' }); - t.equal(request.status, 405); - }; -} - -function validateBodyExists (method) { - return async t => { - t.plan(2); - - const node = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, single: true }); - - const request = await httpRequest(`${node.url}/exampleCollection`, { method }); - - await node.close(); - - t.deepEqual(request.data, { error: 'empty request body not allowed' }); - t.equal(request.status, 400); - }; -} - -function validateBodyJson (method) { - return async t => { - t.plan(2); - - const node = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, single: true }); - - const request = await httpRequest(`${node.url}/exampleCollection`, { method, data: 'not json' }); - - await node.close(); - - t.deepEqual(request.data, { error: 'request body not valid json' }); - t.equal(request.status, 400); - }; -} - -test('post: root pathname', rootMethodNotAllowed('post')); -test('put: root pathname', rootMethodNotAllowed('put')); -test('patch: root pathname', rootMethodNotAllowed('patch')); -test('delete: root pathname', rootMethodNotAllowed('delete')); - -test('post: body exists', validateBodyExists('post')); -test('put: body exists', validateBodyExists('put')); -test('patch: body exists', validateBodyExists('patch')); - -test('post: body is json', validateBodyJson('post')); -test('put: body is json', validateBodyJson('put')); -test('patch: body is json', validateBodyJson('patch')); - -test('post: and get some data', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - const getRequest = await httpRequest(`${node.url}/tests/${postRequest.data.id}`); - await cluster.closeAll(); - - t.deepEqual(getRequest.data, { - id: getRequest.data.id ? getRequest.data.id : t.fail(), - a: 1, - b: 2, - c: 3 - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); -}); - -test('post: and count some data', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - await Promise.all([ - httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 1 } - }), - - httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 2 } - }) - ]); - - const getRequest = await httpRequest(`${node.url}/tests?count=true`); - await cluster.closeAll(); - - t.deepEqual(getRequest.data, { - documentCount: 2 - }); - - t.equal(getRequest.status, 200); -}); - -test('post: and getAll specific fields only', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - const getRequest = await httpRequest(`${node.url}/tests?fields=["b"]`); - await cluster.closeAll(); - - t.deepEqual(getRequest.data[0], { - id: getRequest.data[0].id ? getRequest.data[0].id : t.fail(), - b: 2 - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); -}); - -test('post: and getOne specific fields only', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - const getRequest = await httpRequest(`${node.url}/tests/${postRequest.data.id}?fields=["b"]`); - await cluster.closeAll(); - - t.deepEqual(getRequest.data, { - id: getRequest.data.id ? getRequest.data.id : t.fail(), - b: 2 - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); -}); - -test('post: some data with invalid collection name', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/not$allowed/notfound`, { - method: 'POST', - data: { - a: 1 - } - }); - - await cluster.closeAll(); - - t.deepEqual(postRequest.data, { - errors: ['collectionId can only contain a-z, A-Z, 0-9, dashs or dots'] - }); - - t.equal(postRequest.status, 422); -}); - -test('put: some data', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { - a: 1 - } - }); - - await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`, { - method: 'PUT', - data: { - a: 2 - } - }); - - const getRequest = await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`); - - await cluster.closeAll(); - - t.deepEqual(getRequest.data, { - id: postRequest.data.id, - a: 2 - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); -}); - -test('patch: some data', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { - a: 1 - } - }); - - await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`, { - method: 'PATCH', - data: { - b: "a'2" - } - }); - - const getRequest = await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`); - - await cluster.closeAll(); - - t.deepEqual(getRequest.data, { - id: postRequest.data.id, - a: 1, - b: "a'2" - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); -}); - -test('delete: record returns a 404', async t => { - t.plan(4); - - const cluster = await createTestCluster(3, tls); - - const postRequest = await httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { - a: 1, - b: 2, - c: 3 - } - }); - - const deleteRequest = await httpRequest(`${cluster.nodes[1].url}/tests/${postRequest.data.id}`, { - method: 'DELETE' - }); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests/${postRequest.data.id}`); - - await cluster.closeAll(); - - t.deepEqual(getRequest.data, {}); - - t.equal(postRequest.status, 201); - t.equal(deleteRequest.status, 200); - t.equal(getRequest.status, 404); -}); - -test('find: collection has no records', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests`); - - await cluster.closeAll(); - - t.deepEqual(getRequest.status, 200); - t.deepEqual(getRequest.data, []); -}); - -test('find: return all three records', async t => { - t.plan(8); - - const cluster = await createTestCluster(3, tls); - - await Promise.all([ - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { a: 1, b: 2, c: 3 } - }), - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { d: 4, e: 5, f: 6 } - }), - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { g: 7, h: 8, i: 9 } - }) - ]); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 3); - t.equal(getRequest.status, 200); - - t.ok(getRequest.data[0].id); - t.ok(getRequest.data[1].id); - t.ok(getRequest.data[2].id); - - getRequest.data.forEach(item => { - delete item.id; - }); - - t.deepEqual(getRequest.data.find(item => item.a), { a: 1, b: 2, c: 3 }); - t.deepEqual(getRequest.data.find(item => item.d), { d: 4, e: 5, f: 6 }); - t.deepEqual(getRequest.data.find(item => item.g), { g: 7, h: 8, i: 9 }); -}); - -test('find: filter by querystring', async t => { - t.plan(4); - - const cluster = await createTestCluster(3, tls); - - await Promise.all([ - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { a: 1, b: 2, c: 3 } - }), - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { d: 4, e: 5, f: 6 } - }), - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { g: 7, h: 8, i: 9 } - }) - ]); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests?query={"d":4}`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 1); - t.equal(getRequest.status, 200); - - t.ok(getRequest.data[0].id); - delete getRequest.data[0].id; - - t.deepEqual(getRequest.data[0], { d: 4, e: 5, f: 6 }); -}); - -test('filter: find one out of three records', async t => { - t.plan(4); - - const cluster = await createTestCluster(3, tls); - - await Promise.all([ - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { a: 1, b: 2, c: 3 } - }), - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { d: 4, e: 5, f: 6 } - }), - httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { g: 7, h: 8, i: 9 } - }) - ]); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests?query={"d":4}`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 1); - t.equal(getRequest.status, 200); - - t.ok(getRequest.data[0].id); - delete getRequest.data[0].id; - - t.deepEqual(getRequest.data[0], { d: 4, e: 5, f: 6 }); -}); - -test('filter: delete two out of three records', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const posts = Array(10).fill('').map((_, index) => { - return httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { index } - }); - }); - - await Promise.all(posts); - - const deletions = await httpRequest(`${cluster.nodes[2].url}/tests?query={"index":{"$gt":5}}`, { method: 'DELETE' }); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests`); - - await cluster.closeAll(); - - t.equal(deletions.status, 200); - t.equal(deletions.data.changes, 4); - - t.equal(getRequest.status, 200); - t.equal(getRequest.data.length, 6); - - t.ok(getRequest.data[0].id); - delete getRequest.data[0].id; -}); - -test('filter: put two out of three records', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const posts = Array(10).fill('').map((_, index) => { - return httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { index } - }); - }); - - await Promise.all(posts); - - const putResponse = await httpRequest(`${cluster.nodes[2].url}/tests?query={"index":{"$gt":5}}`, { - method: 'PUT', - data: { - a: 1 - } - }); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests`); - - await cluster.closeAll(); - - t.equal(putResponse.status, 200); - t.equal(putResponse.data.changes, 4); - - t.equal(getRequest.status, 200); - t.equal(getRequest.data.length, 10); - - t.equal(getRequest.data.filter(item => item.a === 1).length, 4); -}); - -test('limit: find three records', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - - const posts = Array(10).fill('').map((_, index) => { - return httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { index } - }); - }); - - await Promise.all(posts); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests?limit=3`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 3); - t.equal(getRequest.status, 200); -}); - -test('order: ascending order three records', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const posts = Array(10).fill('').map((_, index) => { - return httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { index } - }); - }); - - await Promise.all(posts); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests?order=["asc(index)"]`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 10); - t.equal(getRequest.status, 200); - - t.deepEqual(getRequest.data[0].index, 0); - t.deepEqual(getRequest.data[1].index, 1); - t.deepEqual(getRequest.data[5].index, 5); -}); - -test('order: descending order three records', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const posts = Array(10).fill('').map((_, index) => { - return httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { index } - }); - }); - - await Promise.all(posts); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests?order=["desc(index)"]`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 10); - t.equal(getRequest.status, 200); - - t.deepEqual(getRequest.data[0].index, 9); - t.deepEqual(getRequest.data[1].index, 8); - t.deepEqual(getRequest.data[5].index, 4); -}); - -test('order: multiple descending order three records', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - - const posts = Array(10).fill('').map((_, index) => { - return httpRequest(`${cluster.nodes[1].url}/tests`, { - method: 'POST', - data: { index, otherIndex: index } - }); - }); - - await Promise.all(posts); - - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests?order=["desc(index)","desc(otherIndex)"]`); - - await cluster.closeAll(); - - t.equal(getRequest.data.length, 10); - t.equal(getRequest.status, 200); - - t.deepEqual(getRequest.data[0].index, 9); - t.deepEqual(getRequest.data[1].index, 8); - t.deepEqual(getRequest.data[5].index, 4); -}); - -test('autojoin: join learned nodes automatically', async t => { - t.plan(4); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const node4 = await canhazdb({ host: 'localhost', port: 7071, queryPort: 8071, tls, join: [`${node.host}:${node.port}`] }); - - await sleep(2500); - - await cluster.closeAll(); - await node4.close(); - - const getAllPorts = node => node.nodes.map(node => node.port).sort(); - t.deepEqual(getAllPorts(node4), [cluster.nodes[0].port, cluster.nodes[1].port, cluster.nodes[2].port]); - - t.deepEqual(getAllPorts(cluster.nodes[0]), [cluster.nodes[0].port, cluster.nodes[1].port, cluster.nodes[2].port]); - t.deepEqual(getAllPorts(cluster.nodes[1]), [cluster.nodes[0].port, cluster.nodes[1].port, cluster.nodes[2].port]); - t.deepEqual(getAllPorts(cluster.nodes[2]), [cluster.nodes[0].port, cluster.nodes[1].port, cluster.nodes[2].port]); -}); - -test('disaster: one node goes offline', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - - await cluster.nodes[1].close(); - const getRequest = await httpRequest(`${cluster.nodes[2].url}/tests`); - - await cluster.closeAll(); - - t.equal(getRequest.status, 503); - t.deepEqual(getRequest.data, { - errors: [ - 'a node in the cluster is unhealthy, therefore the database is down' - ] - }); -}); - -test('disaster: one node goes offline then online', async t => { - t.plan(4); - - const cluster = await createTestCluster(3); - - await cluster.nodes[1].close(); - - const getRequestAfterClose = await httpRequest(`${cluster.nodes[2].url}/tests`); - - t.equal(getRequestAfterClose.status, 503); - t.deepEqual(getRequestAfterClose.data, { - errors: [ - 'a node in the cluster is unhealthy, therefore the database is down' - ] - }); - - await cluster.nodes[1].open(); - - await sleep(1000); - - const getRequestAfterReopen = await httpRequest(`${cluster.nodes[2].url}/tests`); - - await cluster.closeAll(); - - t.equal(getRequestAfterReopen.status, 200); - t.deepEqual(getRequestAfterReopen.data, []); -}); - -test('disaster: recover and still works', async t => { - t.plan(6); - - const cluster = await createTestCluster(10); - - await Promise.all([ - cluster.nodes[1].close(), - cluster.nodes[3].close(), - cluster.nodes[7].close() - ]); - - const getRequestAfterClose = await httpRequest(`${cluster.nodes[2].url}/tests`); - - t.equal(getRequestAfterClose.status, 503); - t.deepEqual(getRequestAfterClose.data, { - errors: [ - 'a node in the cluster is unhealthy, therefore the database is down' - ] - }); - - await Promise.all([ - cluster.nodes[1].open(), - cluster.nodes[3].open(), - cluster.nodes[7].open() - ]); - - await sleep(1000); - - const getRequestAfterReopen = await httpRequest(`${cluster.nodes[2].url}/tests`); - - t.equal(getRequestAfterReopen.status, 200); - t.deepEqual(getRequestAfterReopen.data, []); - - await Promise.all(mapTimes(100, index => { - return httpRequest(`${cluster.nodes[index % 10].url}/tests`, { - method: 'POST', - data: { a: index } - }); - })); - - const getRequests = await Promise.all(mapTimes(10, index => { - return httpRequest(`${cluster.nodes[index].url}/tests`).then(response => response.data); - })); - - t.deepEqual(getRequests.flatMap(data => data.length), [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]); - - await cluster.closeAll(); - - t.ok('finished'); -}); diff --git a/test/lib/driver/index.js b/test/lib/driver/index.js new file mode 100644 index 0000000..fc1d14f --- /dev/null +++ b/test/lib/driver/index.js @@ -0,0 +1,184 @@ +import fs from 'fs'; +import test from 'basictap'; + +import createDriver from '../../../lib/driver/index.js'; + +test('count: no records', async t => { + t.plan(1); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + const result = await driver.count('tests'); + + await driver.close(); + + t.deepEqual(result, 0); +}); + +test('get: no records', async t => { + t.plan(1); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + const result = await driver.get('tests'); + + await driver.close(); + + t.deepEqual(result, []); +}); + +test('post: records', async t => { + t.plan(2); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + const postResult = await driver.post('tests', { a: 1 }); + const getResult = await driver.get('tests'); + + await driver.close(); + + t.deepEqual(postResult.a, 1); + t.deepEqual(getResult, [postResult]); +}); + +test('get: records - with projection', async t => { + t.plan(1); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + await Promise.all([ + driver.post('tests', { a: 1, b: 'yes' }), + driver.post('tests', { a: 2, b: 'yes' }), + driver.post('tests', { a: 3, b: 'yes' }) + ]); + + let result = await driver.get('tests', null, ['a']); + result = result.sort((a, b) => a.a >= b.a ? 1 : -1); + + await driver.close(); + + t.deepEqual(result, [ + { a: 1 }, + { a: 2 }, + { a: 3 } + ]); +}); + +test('put: record', async t => { + t.plan(2); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + await Promise.all([ + driver.post('tests', { a: 1, b: 'yes' }), + driver.post('tests', { a: 2, b: 'yes' }), + driver.post('tests', { a: 3, b: 'yes' }) + ]); + + const { changes } = await driver.put('tests', { b: 'no' }, {}); + + let result = await driver.get('tests'); + result = result.sort((a, b) => a.a >= b.a ? 1 : -1); + + await driver.close(); + + t.equal(changes, 3); + t.deepEqual(result, [ + { b: 'no' }, + { b: 'no' }, + { b: 'no' } + ]); +}); + +test('patch: record', async t => { + t.plan(2); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + await Promise.all([ + driver.post('tests', { a: 1, b: 'yes' }), + driver.post('tests', { a: 2, b: 'yes' }), + driver.post('tests', { a: 3, b: 'yes' }) + ]); + + const { changes } = await driver.patch('tests', { b: 'no' }, {}); + + let result = await driver.get('tests'); + result = result.sort((a, b) => a.a >= b.a ? 1 : -1); + + await driver.close(); + + t.equal(changes, 3); + t.deepEqual(result, [ + { a: 1, b: 'no' }, + { a: 2, b: 'no' }, + { a: 3, b: 'no' } + ]); +}); + +test('del: record', async t => { + t.plan(2); + + await fs.promises.rm('./canhazdata/tmptest', { recursive: true }).catch(_ => {}); + + const driver = await createDriver({ + options: { + dataDirectory: './canhazdata/tmptest' + } + }); + + await Promise.all([ + driver.post('tests', { a: 1, b: 'yes' }), + driver.post('tests', { a: 2, b: 'yes' }), + driver.post('tests', { a: 3, b: 'yes' }) + ]); + + const { changes } = await driver.del('tests', { a: 2 }); + + let result = await driver.get('tests'); + result = result.sort((a, b) => a.a >= b.a ? 1 : -1); + + await driver.close(); + + t.equal(changes, 1); + t.deepEqual(result, [ + { a: 1, b: 'yes' }, + { a: 3, b: 'yes' } + ]); +}); diff --git a/test/lib/prepareOptions.js b/test/lib/prepareOptions.js new file mode 100644 index 0000000..2fd7e66 --- /dev/null +++ b/test/lib/prepareOptions.js @@ -0,0 +1,36 @@ +import test from 'basictap'; +import prepareOptions from '../../lib/prepareOptions.js'; + +test('prepareOptions.js - all tls arguments must be passed', async t => { + t.plan(1); + + prepareOptions({ + tlsKey: 'a' + }).catch(error => { + t.equal(error.message, 'You must specifiy either all [tls-key, tls-cert, tls-ca] or none of them'); + }); +}); + +test('prepareOptions.js - with tls', async t => { + t.plan(3); + + prepareOptions({ + tlsKey: './certs/localhost.privkey.pem', + tlsCert: './certs/localhost.cert.pem', + tlsCa: './certs/ca.cert.pem' + }).then(result => { + t.equal(result.tls.key.constructor.name, 'Buffer', 'tls key was read'); + t.equal(result.tls.cert.constructor.name, 'Buffer', 'tls cert was read'); + t.equal(result.tls.ca.constructor.name, 'Array', 'tls ca was read'); + }); +}); + +test('prepareOptions.js - join from dns', async t => { + t.plan(1); + + prepareOptions({ + joinFromDns: 'localhost' + }).then(result => { + t.ok(result.join.length > 0, 'at least one item in join'); + }); +}); diff --git a/test/lib/utils/calculateAllowedErrorCount.js b/test/lib/utils/calculateAllowedErrorCount.js new file mode 100644 index 0000000..455e183 --- /dev/null +++ b/test/lib/utils/calculateAllowedErrorCount.js @@ -0,0 +1,65 @@ +import test from 'basictap'; +import calculateAllowedErrorCount from '../../../lib/utils/calculateAllowedErrorCount.js'; + +test('with 0 nodes', t => { + try { + calculateAllowedErrorCount(3, 0); + } catch (error) { + t.equal(error.message, 'calculateAllowedErrorCount: nodeCount can not be less than 1'); + } +}); + +test('with 1 nodes', t => { + const result = calculateAllowedErrorCount(3, 1); + t.equal(result, 0); +}); + +test('with 2 nodes', t => { + const result = calculateAllowedErrorCount(3, 2); + t.equal(result, 1); +}); + +test('with 3 nodes', t => { + const result = calculateAllowedErrorCount(3, 3); + t.equal(result, 2); +}); + +test('with 4 nodes', t => { + const result = calculateAllowedErrorCount(3, 4); + t.equal(result, 1); +}); + +test('with 5 nodes', t => { + const result = calculateAllowedErrorCount(3, 5); + t.equal(result, 2); +}); + +test('with 6 nodes', t => { + const result = calculateAllowedErrorCount(3, 6); + t.equal(result, 2); +}); + +test('with 7 nodes', t => { + const result = calculateAllowedErrorCount(3, 7); + t.equal(result, 2); +}); + +test('with 5 replicas 6 nodes', t => { + const result = calculateAllowedErrorCount(5, 6); + t.equal(result, 1); +}); + +test('with 5 replicas 10 nodes', t => { + const result = calculateAllowedErrorCount(5, 10); + t.equal(result, 4); +}); + +test('with 5 replicas 5 nodes', t => { + const result = calculateAllowedErrorCount(5, 5); + t.equal(result, 4); +}); + +test('with 5 replicas 2 nodes', t => { + const result = calculateAllowedErrorCount(5, 2); + t.equal(result, 1); +}); diff --git a/test/locking.js b/test/locking.js deleted file mode 100644 index 4754555..0000000 --- a/test/locking.js +++ /dev/null @@ -1,278 +0,0 @@ -const fs = require('fs'); - -const test = require('basictap'); -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); - -const tls = { - key: fs.readFileSync('./certs/localhost.privkey.pem'), - cert: fs.readFileSync('./certs/localhost.cert.pem'), - ca: [fs.readFileSync('./certs/ca.cert.pem')], - requestCert: true -}; - -test('lock: and post some data (success)', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const lockRequest = await httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tests'] - }); - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - headers: { - 'x-lock-id': lockRequest.data.id - }, - data: { - a: 1, - b: 2, - c: 3 - } - }); - - const getRequest = await httpRequest(`${node.url}/tests/${postRequest.data.id}`); - - const unlockRequest = await httpRequest(`${node.url}/_/locks/${lockRequest.data.id}`, { - method: 'DELETE' - }); - t.equal(unlockRequest.status, 200); - - cluster.closeAll(); - - t.equal(postRequest.status, 201); - - t.deepEqual(getRequest.data, { - id: getRequest.data.id ? getRequest.data.id : t.fail(), - a: 1, - b: 2, - c: 3 - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); -}); - -test('lock: delete lock with incorrect id', async t => { - t.plan(1); - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const unlockRequest = await httpRequest(`${node.url}/_/locks/dunno`, { - method: 'DELETE' - }); - t.equal(unlockRequest.status, 404); - - cluster.closeAll(); -}); - -test('lock: multiple happen in order', async t => { - t.plan(6); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - let firstFinished = false; - let secondFinished = false; - - const first = httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tests'] - }).then(async lockRequest => { - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - headers: { - 'x-lock-id': lockRequest.data.id - }, - data: { a: 1 } - }); - t.equal(postRequest.status, 201); - - firstFinished = true; - - const unlockRequest = await httpRequest(`${node.url}/_/locks/${lockRequest.data.id}`, { - method: 'DELETE' - }); - - t.equal(unlockRequest.status, 200); - }); - - const second = httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tests'] - }).then(async lockRequest => { - t.ok(firstFinished, 'first lock has finished before second starts'); - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - headers: { - 'x-lock-id': lockRequest.data.id - }, - data: { a: 1 } - }); - - t.equal(postRequest.status, 201); - - secondFinished = true; - const unlockRequest = await httpRequest(`${node.url}/_/locks/${lockRequest.data.id}`, { - method: 'DELETE' - }); - t.equal(unlockRequest.status, 200); - }); - - await Promise.all([first, second]); - - cluster.closeAll(); - - t.ok(secondFinished, 'second lock ran'); -}); - -test('lock: and post some data (conflict + fail)', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const lockRequest = await httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tests'] - }); - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - headers: { - 'x-lock-strategy': 'fail' - }, - data: { - a: 1 - } - }); - - const unlockRequest = await httpRequest(`${node.url}/_/locks/${lockRequest.data.id}`, { - method: 'DELETE' - }); - t.equal(unlockRequest.status, 200); - - cluster.closeAll(); - - t.equal(postRequest.status, 409); -}); - -test('lock: and post some data (conflict + wait)', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const lockRequest = await httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tests'] - }); - - httpRequest(`${node.url}/tests`, { - method: 'POST', - headers: { - 'x-lock-strategy': 'wait' - }, - data: { - a: 1, - b: 2, - c: 3 - } - }).then(async postRequest => { - const getRequest = await httpRequest(`${node.url}/tests/${postRequest.data.id}`); - cluster.closeAll(); - - t.equal(postRequest.status, 201); - t.deepEqual(getRequest.data, { - id: getRequest.data.id ? getRequest.data.id : t.fail(), - a: 1, - b: 2, - c: 3 - }); - - t.equal(postRequest.status, 201); - t.equal(getRequest.status, 200); - }); - - const unlockRequest = await httpRequest(`${node.url}/_/locks/${lockRequest.data.id}`, { - method: 'DELETE' - }); - t.equal(unlockRequest.status, 200); -}); - -test('lock: all methods lock', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - let unlocked = false; - - const postRequest = await httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 1 } - }); - - const lockRequest = await httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tessts'] - }); - - const putRequest = httpRequest(`${node.url}/tests/${postRequest.data.id}`, { - method: 'PUT', - data: { a: 2 } - }); - - const patchRequest = httpRequest(`${node.url}/tests/${postRequest.data.id}`, { - method: 'PATCH', - data: { a: 2 } - }); - - Promise.all([putRequest, patchRequest]) - .then(async (args) => { - const deleteRequest = await httpRequest(`${node.url}/tests/${postRequest.data.id}`, { - method: 'DELETE' - }); - await cluster.closeAll(); - t.deepEqual(args.map(arg => arg.status), [200, 200]); - t.equal(deleteRequest.status, 200); - t.ok(unlocked, 'requests happened after unlock'); - }); - - await httpRequest(`${node.url}/_/locks/${lockRequest.data.id}`, { - method: 'DELETE' - }); - - unlocked = true; -}); - -test('lock: and wait but node closes', async t => { - t.plan(1); - - const cluster = await createTestCluster(1, tls); - const node = cluster.getRandomNodeUrl(); - - await httpRequest(`${node.url}/_/locks`, { - method: 'POST', - data: ['tests'] - }); - - httpRequest(`${node.url}/tests`, { - method: 'POST', - headers: { - 'x-lock-strategy': 'wait' - }, - data: { a: 1 } - }).then(postRequest => { - t.fail('should not have resolved successfully'); - }).catch(error => { - t.equal(error.message, 'socket hang up'); - }); - - setTimeout(() => { - cluster.closeAll(); - }, 500); -}); diff --git a/test/modules/controllers/createControllerStore.js b/test/modules/controllers/createControllerStore.js new file mode 100644 index 0000000..0d798cb --- /dev/null +++ b/test/modules/controllers/createControllerStore.js @@ -0,0 +1,84 @@ +import test from 'basictap'; +import createControllerStore from '../../../lib/modules/controllers/createControllerStore.js'; + +test('createControllerStore: no applicable controller test', t => { + t.pass(); + + const controllerStore = createControllerStore(); + + controllerStore.add({ + command: 2, + conditions: [], + handler: request => console.log() + }); + + controllerStore.add({ + command: 1, + conditions: [], + handler: request => console.log() + }); + + const controllers = controllerStore.find({ + command: 3, + json: () => ({ + test: 2 + }) + }); + + t.ok(controllers.length === 0, 'has 0 controllers'); +}); + +test('createControllerStore: one applicable controller test', t => { + t.pass(); + + const controllerStore = createControllerStore(); + + controllerStore.add({ + command: 2, + conditions: [], + handler: request => console.log() + }); + + controllerStore.add({ + command: 1, + conditions: [], + handler: request => console.log() + }); + + const controllers = controllerStore.find({ + command: 1, + json: () => ({ + test: 2 + }) + }); + + t.ok(controllers.length === 1, 'has 1 controller'); +}); + +test('createControllerStore: multiple controller test with condition', t => { + t.pass(); + + const controllerStore = createControllerStore(); + + controllerStore.add({ + command: 1, + conditions: [], + handler: () => 10 + }); + + controllerStore.add({ + command: 1, + conditions: [() => false], + handler: () => 20 + }); + + const controllers = controllerStore.find({ + command: 1, + json: () => ({ + test: 2 + }) + }); + + t.ok(controllers.length === 1, 'has 1 controller'); + t.equal(controllers[0].handler(), 10, 'handler returned correctly'); +}); diff --git a/test/notify.js b/test/notify.js deleted file mode 100644 index f7dcdeb..0000000 --- a/test/notify.js +++ /dev/null @@ -1,214 +0,0 @@ -const fs = require('fs'); - -const WebSocket = require('ws'); -const test = require('basictap'); - -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); - -const tls = { - key: fs.readFileSync('./certs/localhost.privkey.pem'), - cert: fs.readFileSync('./certs/localhost.cert.pem'), - ca: [fs.readFileSync('./certs/ca.cert.pem')], - requestCert: true -}; - -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); - -test('notify: post some data', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', function open () { - ws.send(JSON.stringify([1, 'NOTIFY', 'POST:/tests/.*'])); - - httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 1 } - }).then(() => { - cluster.closeAll(); - }); - }); - - ws.on('message', function incoming (rawData) { - const [type, data] = JSON.parse(rawData); - - if (type === 'A') { - t.equal(data, 1); - return; - } - - const [path, collectionId, resourceId, pattern] = data; - - t.ok(path.startsWith('POST:/tests/')); - t.equal(collectionId, 'tests'); - t.equal(resourceId.length, 36); - t.equal(pattern, 'POST:/tests/.*'); - }); -}); - -test('unnotify', async t => { - t.plan(2); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', async function open () { - ws.send(JSON.stringify([1, 'NOTIFY', 'POST:/tests/.*'])); - await sleep(50); - ws.send(JSON.stringify([1, 'UNNOTIFY', 'POST:/tests/.*'])); - await sleep(50); - - httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 1 } - }).then(() => { - cluster.closeAll(); - }); - }); - - ws.on('message', function incoming (rawData) { - const [type, data] = JSON.parse(rawData); - - if (type === 'A') { - t.equal(data, 1); - return; - } - - t.fail('should not have been called'); - }); -}); - -test('notify: twos posts', async t => { - t.plan(8); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', function open () { - ws.send(JSON.stringify([1, 'NOTIFY', 'POST:/tests1/.*'])); - ws.send(JSON.stringify([2, 'NOTIFY', 'POST:/tests2/.*'])); - - const promises = []; - promises[0] = httpRequest(`${node.url}/tests1`, { - method: 'POST', - data: { a: 1 } - }); - - promises[1] = httpRequest(`${node.url}/tests2`, { - method: 'POST', - data: { a: 2 } - }); - - Promise.all(promises).then(() => cluster.closeAll()); - }); - - const store = []; - function done () { - if (store.length !== 2) { - return; - } - - store.sort((a, b) => a[3] > b[3] ? 1 : -1); - - { - const [path, collectionId, resourceId, pattern] = store[0]; - - t.ok(path.startsWith('POST:/tests1/')); - t.equal(collectionId, 'tests1'); - t.equal(resourceId.length, 36); - t.equal(pattern, 'POST:/tests1/.*'); - } - - { - const [path, collectionId, resourceId, pattern] = store[1]; - - t.ok(path.startsWith('POST:/tests2/')); - t.equal(collectionId, 'tests2'); - t.equal(resourceId.length, 36); - t.equal(pattern, 'POST:/tests2/.*'); - } - } - - ws.on('message', function incoming (rawData) { - const [type, parsedData] = JSON.parse(rawData); - if (type === 'A') { - return; - } - - store.push(parsedData); - done(); - }); -}); - -test('notify: one not the other', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', function open () { - ws.send(JSON.stringify([1, 'NOTIFY', 'POST:/tests2/.*'])); - - const promises = []; - promises[0] = httpRequest(`${node.url}/tests1`, { - method: 'POST', - data: { a: 1 } - }); - - promises[1] = httpRequest(`${node.url}/tests2`, { - method: 'POST', - data: { a: 2 } - }); - - promises[3] = httpRequest(`${node.url}/tests3`, { - method: 'POST', - data: { a: 3 } - }); - - Promise.all(promises).then(() => cluster.closeAll()); - }); - - ws.on('message', function incoming (rawData) { - const [type, data] = JSON.parse(rawData); - if (type === 'A') { - t.equal(data, 1); - return; - } - - const [path, collectionId, resourceId, pattern] = data; - - t.ok(path.startsWith('POST:/tests2/')); - t.equal(collectionId, 'tests2'); - t.equal(resourceId.length, 36); - t.equal(pattern, 'POST:/tests2/.*'); - }); -}); - -test('ws - unknown command', async t => { - t.plan(3); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', async function open () { - ws.send(JSON.stringify([1, 'UNKNOWN'])); - }); - - ws.on('message', function incoming (rawData) { - const [type, acceptId, data] = JSON.parse(rawData); - - t.equal(type, 'R'); - t.equal(acceptId, 1); - t.equal(data, 'COMMAND_NOT_FOUND'); - - cluster.closeAll(); - }); -}); diff --git a/test/problems.js b/test/problems.js deleted file mode 100644 index 4b10d35..0000000 --- a/test/problems.js +++ /dev/null @@ -1,35 +0,0 @@ -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); - -const mapTimes = (times, fn) => Array(times).fill().map((_, index) => fn(index)); -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); - -// setInterval(console.log, 250); - -async function problems2 () { - const serverCount = 2; - const interationsPer = 300; - const cluster = await createTestCluster(serverCount); - - await sleep(2000); - - while (true) { - console.log('Starting'); - console.time(' posting'); - await Promise.all(mapTimes(interationsPer, index => { - return httpRequest(`${cluster.nodes[index % serverCount].url}/tests`, { - method: 'POST', - data: { a: index } - }); - })); - console.timeEnd(' posting'); - - console.time(' getting'); - await Promise.all(mapTimes(serverCount, index => { - return httpRequest(`${cluster.nodes[index].url}/tests`).then(response => response.data); - })); - console.timeEnd(' getting'); - } -} - -problems2(); diff --git a/test/utils/validateAlphaNumericDashDot.js b/test/utils/validateAlphaNumericDashDot.js deleted file mode 100644 index e1eef35..0000000 --- a/test/utils/validateAlphaNumericDashDot.js +++ /dev/null @@ -1,19 +0,0 @@ -const test = require('basictap'); - -const validateAlphaNumericDashDot = require('../../utils/validateAlphaNumericDashDot'); - -test('correct', t => { - t.plan(1); - - const result = validateAlphaNumericDashDot('correct'); - - t.ok(result); -}); - -test('wrong', t => { - t.plan(1); - - const result = validateAlphaNumericDashDot('cor$rect'); - - t.notOk(result); -}); diff --git a/test/ws.js b/test/ws.js deleted file mode 100644 index 135b9d8..0000000 --- a/test/ws.js +++ /dev/null @@ -1,97 +0,0 @@ -const fs = require('fs'); - -const WebSocket = require('ws'); -const test = require('basictap'); - -const httpRequest = require('./helpers/httpRequest'); -const createTestCluster = require('./helpers/createTestCluster'); - -const { - STATUS, - DOCUMENT, - DOCUMENTS, - QUERY, - COLLECTION_ID -} = require('../lib/constants'); - -const tls = { - key: fs.readFileSync('./certs/localhost.privkey.pem'), - cert: fs.readFileSync('./certs/localhost.cert.pem'), - ca: [fs.readFileSync('./certs/ca.cert.pem')], - requestCert: true -}; - -test('get: getAll some data', async t => { - t.plan(5); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const insertResponses = await Promise.all([ - httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 1 } - }), - - httpRequest(`${node.url}/tests`, { - method: 'POST', - data: { a: 2 } - }) - ]); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', function open () { - ws.send(JSON.stringify([1, 'GET', { - [COLLECTION_ID]: 'tests', - [QUERY]: { - a: 1 - } - }])); - }); - - ws.on('message', async function incoming (rawData) { - const [type, acceptId, data] = JSON.parse(rawData); - - t.equal(type, 'A', 'should have correct type'); - t.equal(acceptId, 1, 'should have correct acceptId'); - t.equal(data[STATUS], 200, 'should have correct status'); - t.equal(data[DOCUMENTS][0].id, insertResponses[0].data.id, 'had correct document id'); - t.equal(data[DOCUMENTS][0].a, 1, 'should return document field'); - - cluster.closeAll(); - }); -}); - -test('post: post some data', async t => { - t.plan(6); - - const cluster = await createTestCluster(3, tls); - const node = cluster.getRandomNodeUrl(); - - const ws = new WebSocket(node.wsUrl, tls); - ws.on('open', function open () { - ws.send(JSON.stringify([1, 'POST', { - [COLLECTION_ID]: 'tests', - [DOCUMENT]: { - a: 1 - } - }])); - }); - - ws.on('message', async function incoming (rawData) { - const [type, acceptId, data] = JSON.parse(rawData); - - t.equal(type, 'A', 'should have correct type'); - t.equal(acceptId, 1, 'should have correct acceptId'); - t.equal(data[STATUS], 201, 'should have correct status'); - t.equal(data[DOCUMENT].id.length, 36, 'should return valid id'); - t.equal(data[DOCUMENT].a, 1, 'should return document field'); - - const response = await httpRequest(`${node.url}/tests`, { - method: 'GET' - }); - - t.deepEqual(response.data[0], data[DOCUMENT], 'future query returns document'); - cluster.closeAll(); - }); -}); diff --git a/utils/buildInsertStatement.js b/utils/buildInsertStatement.js deleted file mode 100644 index 5a15588..0000000 --- a/utils/buildInsertStatement.js +++ /dev/null @@ -1,10 +0,0 @@ -function buildInsertStatement (tableName, object) { - const fields = Object.keys(object).map(field => `"${field}"`).join(', '); - const parameters = Object.values(object); - return { - sql: `INSERT INTO "${tableName}" (${fields}) VALUES (${parameters.map((_, index) => '$' + (index + 1))})`, - parameters - }; -} - -module.exports = buildInsertStatement; diff --git a/utils/selectRandomItemFromArray.js b/utils/selectRandomItemFromArray.js deleted file mode 100644 index df9b432..0000000 --- a/utils/selectRandomItemFromArray.js +++ /dev/null @@ -1,8 +0,0 @@ -function selectRandomItemFromArray (array) { - if (!array || array.length === 0) { - return; - } - return array[Math.floor(Math.random() * array.length)]; -} - -module.exports = selectRandomItemFromArray; diff --git a/utils/validateQueryOptions.js b/utils/validateQueryOptions.js deleted file mode 100644 index bdaae21..0000000 --- a/utils/validateQueryOptions.js +++ /dev/null @@ -1,9 +0,0 @@ -function validateQueryOptions (options) { - Object.keys(options).forEach(key => { - if (options[key] === undefined) { - throw new Error('canhazdb:client can not serialise an object with undefined'); - } - }); -} - -module.exports = validateQueryOptions; diff --git a/web/.eslintrc.json b/web/.eslintrc.json new file mode 100644 index 0000000..69eb78d --- /dev/null +++ b/web/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "plugins": [ + "react-hooks" + ], + "extends": [ + "semistandard", + "standard-jsx", + "plugin:react/recommended" + ], + "rules": { + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + "react/prop-types": "off", + "no-use-before-define": "off" + }, + "settings": { + "react": { + "pragma": "React", + "version": "detect" + } + } +} \ No newline at end of file diff --git a/web/css/index.css b/web/css/index.css new file mode 100644 index 0000000..c020a07 --- /dev/null +++ b/web/css/index.css @@ -0,0 +1,90 @@ +body { + margin: 0; + padding: 0; + font-family: arial; + background-color: #cedddd; +} + +app { + display: flex; + flex-direction: column; + height: 100vh; +} + +header { + background: white; + border-bottom: 5px solid #588486; + display: flex; + place-items: center; +} + +header > img { + margin-bottom: 5px; + height: 50px; + width: 55px; +} + +header > div { + display: flex; + flex-direction: column; + font-size: 20px; +} + +.form-field { + padding-bottom: 10px; +} + +.form-field label:after { + content: ':'; +} + +.form-field label { + display: block; + font-weight: bold; + padding-bottom: 5px; +} + +dialog > article > h1 { + margin: 0; + padding: 0; +} + +dialog { + background-color: rgba(0, 0, 0, 0.4); + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + height: 100vh; + width: 100vw; + margin: 0; + padding: 0; + overflow: auto; +} + +dialog > article { + margin: auto; + margin-top: max(10vh); + padding: 20px; + max-width: 500px; + margin-bottom: 20vh; + background-color: white; + border: 5px solid #588486; + border-radius: 10px; + box-shadow: 1px 1px 45px -25px black; +} + +.file-value { + display: flex; + place-items: center; + border: 2px solid #939393; + padding: 4px 0; + margin-bottom: 2px; +} + +.file-value > img { + width: 20px; + height: 20px; + margin-right: 5px; +} \ No newline at end of file diff --git a/web/html/index.html b/web/html/index.html new file mode 100644 index 0000000..8e0943c --- /dev/null +++ b/web/html/index.html @@ -0,0 +1,13 @@ + + + + + + canhazdb web + + + + + + + \ No newline at end of file diff --git a/web/img/file.svg b/web/img/file.svg new file mode 100644 index 0000000..fc65063 --- /dev/null +++ b/web/img/file.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/web/img/fileWhite.svg b/web/img/fileWhite.svg new file mode 100644 index 0000000..5eaf003 --- /dev/null +++ b/web/img/fileWhite.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/web/img/folderWhite.svg b/web/img/folderWhite.svg new file mode 100644 index 0000000..5d48b96 --- /dev/null +++ b/web/img/folderWhite.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/web/img/logo.svg b/web/img/logo.svg new file mode 100644 index 0000000..11edb45 --- /dev/null +++ b/web/img/logo.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/js/components/AuthenticationDialog.js b/web/js/components/AuthenticationDialog.js new file mode 100644 index 0000000..59feaa2 --- /dev/null +++ b/web/js/components/AuthenticationDialog.js @@ -0,0 +1,85 @@ +import React from 'react'; +import useLocalStorage from '../hooks/useLocalStorage.js'; +import FileInput from '../components/FileInput.js'; +import useApi from '../hooks/useApi.js'; +import useHttp from 'use-http'; + +const allowCustomCA = false; + +function AuthenticationDialog (props) { + const { post } = useHttp({ + cachePolicy: 'no-cache' + }); + const [settings] = useApi('/api/settings'); + const [authenticationData, setAuthenticationData] = + useLocalStorage('authenticationData', {}); + + React.useEffect(() => { + if (!settings) { + return; + } + + const sameCA = authenticationData.ca === settings.ca; + + if (!authenticationData.ca || (!sameCA && !allowCustomCA)) { + setAuthenticationData({ + ...authenticationData, + ca: settings.ca + }); + } + }, [settings, authenticationData, setAuthenticationData]); + + function handleChange (name) { + return (file) => { + setAuthenticationData({ + ...authenticationData, + [name]: file + }); + }; + } + + async function submit (event) { + event.preventDefault(); + const response = await post('/api/authenticate', authenticationData); + const token = response.token; + props.onAuthenticate && props.onAuthenticate(token); + } + + const continueDisabled = !( + authenticationData && + authenticationData.ca && + authenticationData.cert && + authenticationData.privateKey + ); + + return ( + +
+

Authenticate

+

+ Select the client tls files below to authenticate with this data server. +

+
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+
+ ); +} + +export default AuthenticationDialog; diff --git a/web/js/components/FileInput.js b/web/js/components/FileInput.js new file mode 100644 index 0000000..6da155e --- /dev/null +++ b/web/js/components/FileInput.js @@ -0,0 +1,45 @@ +import React from 'react'; +import readFile from '../utils/readFile.js'; + +function FileInput (props) { + const [state, setState] = React.useState(props.value); + + React.useEffect(function () { + if (state !== props.value) { + setState(props.value); + } + }, [state, props]); + + async function handleChange (event) { + const file = event.target.files[0]; + + if (!file) { + setState(null); + return; + } + + const newState = { + name: file.name, + data: await readFile(file) + }; + + setState(newState); + props.onChange && props.onChange(newState); + } + + return ( + <> + {state + ? ( +
+ + {state.name} +
+ ) + : null} + {!props.readonly && } + + ); +} + +export default FileInput; diff --git a/web/js/components/MainUI.js b/web/js/components/MainUI.js new file mode 100644 index 0000000..055a488 --- /dev/null +++ b/web/js/components/MainUI.js @@ -0,0 +1,122 @@ +import React from 'react'; +import useApi from '../hooks/useApi.js'; +import styled from '@emotion/styled'; +import classnames from 'classnames'; + +const mainUiStyle = { + display: 'flex', + flexGrow: 1 +}; + +const CollectionsListView = styled.div(` + flex-grow: 1; + + ul { + margin: 5px; + padding: 0; + } + + ul > li { + margin: 0 0 3px 0; + padding: 0; + list-style: none; + } + ul > li { + display: flex; + place-items: center; + padding: 5px; + background-color: white; + border-radius: 3px; + } + + .panel-title { + padding: 5px 10px 0 10px; + font-weight: bold; + } +`); + +const CollectionsTree = styled.div(` + background-color: white; + + ul { + padding: 0; + margin: 0; + } + + ul > li > a:hover { + background-color: #325759; + } + + ul > li > a > img { + height: 20px; + margin-right: 5px; + } + ul > li.active > a { + background-color: #325759; + } + ul > li > a { + display: flex; + place-items: center; + background-color: #588486; + color: white; + padding: 5px 10px 5px 5px; + text-decoration: none; + } +`); + +function MainUI (props) { + const collectionId = window.location.pathname.substr(1) || 'system.collections'; + + const [collections] = useApi('/api/system.collections', { + headers: { + authorisation: props.authToken + } + }); + + const [documents] = useApi(`/api/${collectionId}?limit=10`, { + headers: { + authorisation: props.authToken + } + }); + + return ( +
+ + + + + +
{collectionId}
+ +
+
+ ); +} + +export default MainUI; diff --git a/web/js/hooks/useApi.js b/web/js/hooks/useApi.js new file mode 100644 index 0000000..1984481 --- /dev/null +++ b/web/js/hooks/useApi.js @@ -0,0 +1,26 @@ +import React from 'react'; + +function useApi (url, options) { + const [data, setData] = React.useState(); + const [state, setState] = React.useState('idle'); + + React.useEffect(() => { + (async function () { + setState('loading'); + + try { + const response = await window.fetch(url, options); + const data = await response.json(); + setData(data); + setState('loaded'); + } catch (error) { + console.log(error); + setState('error'); + } + }()); + }, [url, JSON.stringify(options)]); + + return [data, state]; +} + +export default useApi; diff --git a/web/js/hooks/useLocalStorage.js b/web/js/hooks/useLocalStorage.js new file mode 100644 index 0000000..5471401 --- /dev/null +++ b/web/js/hooks/useLocalStorage.js @@ -0,0 +1,28 @@ +// https://usehooks.com/useLocalStorage/ + +import React from 'react'; + +function useLocalStorage (key, initialValue) { + const [storedValue, setStoredValue] = React.useState(() => { + try { + const item = window.localStorage.getItem(key); + return item ? JSON.parse(item) : initialValue; + } catch (error) { + console.error(error); + return initialValue; + } + }); + const setValue = (value) => { + try { + const valueToStore = + value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + console.log(error); + } + }; + return [storedValue, setValue]; +} + +export default useLocalStorage; diff --git a/web/js/index.js b/web/js/index.js new file mode 100644 index 0000000..d96810c --- /dev/null +++ b/web/js/index.js @@ -0,0 +1,65 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import AuthenticationDialog from './components/AuthenticationDialog.js'; +import MainUI from './components/MainUI.js'; +import useLocalStorage from './hooks/useLocalStorage.js'; + +async function checkToken (authToken) { + if (!authToken) { + return false; + } + + try { + const collectionsResponse = await window.fetch('/api/authenticate/' + authToken, { + headers: { + authorisation: authToken + } + }); + + return collectionsResponse.status === 200; + } catch (error) { + console.error(error); + return false; + } +} + +function App () { + const [authToken, setAuthToken] = useLocalStorage('authToken'); + const [authValid, setAuthValid] = React.useState(false); + + function handleAuthenticate (token) { + setAuthToken(token); + } + + React.useEffect(() => { + checkToken(authToken).then(valid => { + if (!valid) { + setAuthToken(null); + } else { + setAuthValid(true); + } + }); + }, [authToken, setAuthToken]); + + return ( + <> +
+ +
+ canhazdb + Web UI +
+
+ + {!authToken && } + + {authValid && } + + ); +} + +document.addEventListener('DOMContentLoaded', function () { + const appElement = document.body.getElementsByTagName('app')[0]; + ReactDOM.render(, appElement); +}); diff --git a/web/js/utils/readFile.js b/web/js/utils/readFile.js new file mode 100644 index 0000000..b7068ba --- /dev/null +++ b/web/js/utils/readFile.js @@ -0,0 +1,14 @@ +function readFile (file) { + return new Promise(resolve => { + const reader = new window.FileReader(); + + reader.onload = function (e) { + const content = reader.result; + resolve(content); + }; + + reader.readAsText(file); + }); +} + +export default readFile;