From a30e3a590b58b1505b10f7e369acc1256831f0cb Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 12 Dec 2022 11:53:41 +0000 Subject: [PATCH 01/40] working with fetch --- README.md | 108 +- examples/bulk_transform.js | 2 +- examples/express.js | 2 +- examples/lazy_creation_of_views.js | 2 +- examples/lazy_db_creation_and_replication.js | 4 +- examples/pipe.js | 2 +- lib/changesreader.js | 2 +- lib/nano.d.ts | 35 +- lib/nano.js | 208 +- package-lock.json | 9974 +----------------- package.json | 19 +- test/attachment.destroy.test.js | 41 +- test/attachment.get.test.js | 39 +- test/attachment.getAsStream.test.js | 33 +- test/attachment.insert.test.js | 99 +- test/database.changes.test.js | 103 - test/database.changesAsStream.test.js | 42 +- test/database.compact.test.js | 55 +- test/database.create.test.js | 58 +- test/database.destroy.test.js | 42 +- test/database.get.test.js | 58 +- test/database.list.test.js | 20 +- test/database.listAsStream.test.js | 25 +- test/database.replicate.test.js | 66 +- test/database.replication.disable.test.js | 54 +- test/database.replication.enable.test.js | 80 +- test/database.replication.query.test.js | 60 +- test/design.atomic.test.js | 64 +- test/design.createIndex.test.js | 43 +- test/design.find.test.js | 43 +- test/design.findAsStream.test.js | 29 +- test/design.search.test.js | 47 +- test/design.searchAsStream.test.js | 29 +- test/design.show.test.js | 39 +- test/design.view.test.js | 79 +- test/design.viewAsStream.test.js | 25 +- test/design.viewWithList.test.js | 19 +- test/design.viewWithListAsStream.test.js | 29 +- test/document.bulk.test.js | 37 +- test/document.changesreader.test.js | 545 +- test/document.destroy.test.js | 43 +- test/document.fetch.test.js | 67 +- test/document.fetchRevs.test.js | 67 +- test/document.get.test.js | 67 +- test/document.head.test.js | 70 +- test/document.insert.test.js | 140 +- test/document.list.test.js | 39 +- test/document.listAsStream.test.js | 39 +- test/mock.js | 14 + test/multipart.get.test.js | 65 +- test/multipart.insert.test.js | 81 +- test/multipart.test.js | 63 +- test/nano.agent.test.js | 48 - test/nano.auth.test.js | 46 +- test/nano.config.test.js | 47 +- test/nano.customheaders.test.js | 33 +- test/nano.info.test.js | 19 +- test/nano.logger.test.js | 21 +- test/nano.request.test.js | 315 +- test/nano.session.test.js | 19 +- test/nano.timeout.test.js | 64 - test/nano.updates.test.js | 40 +- test/nano.use.test.js | 21 +- test/nano.uuids.test.js | 45 +- test/notnocked.test.js | 20 +- test/partition.find.test.js | 45 +- test/partition.findAsStream.test.js | 27 +- test/partition.info.test.js | 59 +- test/partition.list.test.js | 83 +- test/partition.listAsStream.test.js | 37 +- test/partition.search.test.js | 45 +- test/partition.searchAsStream.test.js | 23 +- test/partition.view.test.js | 55 +- test/partition.viewAsStream.test.js | 23 +- 74 files changed, 2205 insertions(+), 11946 deletions(-) delete mode 100644 test/database.changes.test.js create mode 100644 test/mock.js delete mode 100644 test/nano.agent.test.js delete mode 100644 test/nano.timeout.test.js diff --git a/README.md b/README.md index c0ef5f25..49b9c219 100644 --- a/README.md +++ b/README.md @@ -105,10 +105,10 @@ Note the minimum required version of Node.js is 10. To use `nano` you need to connect it to your CouchDB install, to do that: ```js -const nano = require('nano')('http://localhost:5984'); +const nano = require('nano')('http://127.0.0.1:5984'); ``` -> Note: The URL you supply may also contain authentication credentials e.g. `http://admin:mypassword@localhost:5984`. +> Note: The URL you supply may also contain authentication credentials e.g. `http://admin:mypassword@127.0.0.1:5984`. To create a new database: @@ -189,14 +189,14 @@ you have inserted a document with an _id of rabbit. rev: '1-6e4cb465d49c0368ac3946506d26335d' } ``` -You can also see your document in futon (http://localhost:5984/_utils). +You can also see your document in futon (http://127.0.0.1:5984/_utils). ## Configuration Configuring nano to use your database server is as simple as: ```js -const nano = require('nano')('http://localhost:5984') +const nano = require('nano')('http://127.0.0.1:5984') const db = nano.use('foo'); ``` @@ -204,54 +204,17 @@ If you don't need to instrument database objects you can simply: ```js // nano parses the URL and knows this is a database -const db = require('nano')('http://localhost:5984/foo'); +const db = require('nano')('http://127.0.0.1:5984/foo'); ``` -You can also pass options to the require to specify further configuration options you can pass an object literal instead: - -```js -// nano parses the URL and knows this is a database -const opts = { - url: 'http://localhost:5984/foo', - requestDefaults: { - proxy: { - protocol: 'http', - host: 'myproxy.net' - }, - headers: { - customheader: 'MyCustomHeader' - } - } -}; -const db = require('nano')(opts); -``` - -Nano works perfectly well over HTTPS as long as the SSL cert is signed by a certification authority known by your client operating system. If you have a custom or self-signed certificate, you may need to create your own HTTPS agent and pass it to Nano e.g. - -```js -const httpsAgent = new https.Agent({ - ca: '/path/to/cert', - rejectUnauthorized: true, - keepAlive: true, - maxSockets: 6 -}) -const nano = Nano({ - url: process.env.COUCH_URL, - requestDefaults: { - agent: httpsAgent, - } -}) -``` - -Please check [axios] for more information on the defaults. They support features like proxies, timeout etc. - You can tell nano to not parse the URL (maybe the server is behind a proxy, is accessed through a rewrite rule or other): ```js // nano does not parse the URL and return the server api -// "http://localhost:5984/prefix" is the CouchDB server root +// "http://127.0.0.1:5984/prefix" is the CouchDB server root const couch = require('nano')( - { url : "http://localhost:5984/prefix" + { + url : "http://127.0.0.1:5984/prefix" parseUrl : false }); const db = couch.use('foo'); @@ -259,21 +222,45 @@ const db = couch.use('foo'); ### Pool size and open sockets -A very important configuration parameter if you have a high traffic website and are using `nano` is the HTTP pool size. By default, the Node.js HTTP global agent has a infinite number of active connections that can run simultaneously. This can be limited to user-defined number (`maxSockets`) of requests that are "in flight", while others are kept in a queue. Here's an example explicitly using the Node.js HTTP agent configured with [custom options](https://nodejs.org/api/http.html#http_new_agent_options): +To specify the number of connections, timeouts and pool size, supply an `agentOptions` object when starting up Nano. ```js -const http = require('http') -const myagent = new http.Agent({ - keepAlive: true, - maxSockets: 25 -}) +const agentOptions = { + bodyTimeout: 30000, + headersTimeout: 30000, + keepAliveMaxTimeout: 600000, + keepAliveTimeout: 30000, + keepAliveTimeoutThreshold: 1000, + maxHeaderSize: 16384, + maxResponseSize: -1, + pipelining: 6, + connect: { + timeout: 10000 + }, + strictContentLength: true, + connections: null, + maxRedirections: 0 +} +const nano = Nano({ url: 'http://127.0.0.1:5984', agentOptions }) +``` -const db = require('nano')({ - url: 'http://localhost:5984/foo', - requestDefaults : { - agent : myagent - } -}); +The meanings of the agentOptions attributes is described [here](https://undici.nodejs.org/#/docs/api/Agent?id=new-undiciagentoptions), [here](https://undici.nodejs.org/#/docs/api/Pool?id=parameter-pooloptions) and [here](https://undici.nodejs.org/#/docs/api/Client?id=parameter-clientoptions) + +> Note `requestDefaults` is no longer supported. + +## Custom headers + +To supply customer headers with each request, supply a headers object when starting up Nano: + + +```js +const couch = require('nano')( + { + url : "http://127.0.0.1:5984/prefix" + headers: { + mycustomheader: '42' + } + }); ``` ## TypeScript @@ -283,7 +270,7 @@ There is a full TypeScript definition included in the the *nano* package. Your T ```ts import * as Nano from 'nano' -let n = Nano('http://USERNAME:PASSWORD@localhost:5984') +let n = Nano('http://USERNAME:PASSWORD@127.0.0.1:5984') let db = n.db.use('people') interface iPerson extends Nano.MaybeDocument { @@ -1190,10 +1177,7 @@ Nano supports making requests using CouchDB's [cookie authentication](http://gui ```js const nano = require('nano')({ - url: 'http://localhost:5984', - requestDefaults: { - jar: true - } + url: 'http://127.0.0.1:5984' }) const username = 'user' const userpass = 'pass' diff --git a/examples/bulk_transform.js b/examples/bulk_transform.js index 0bb1a51d..8954f718 100644 --- a/examples/bulk_transform.js +++ b/examples/bulk_transform.js @@ -10,7 +10,7 @@ // License for the specific language governing permissions and limitations under // the License. -const db = require('nano')('http://localhost:5984/emails') +const db = require('nano')('http://127.0.0.1:5984/emails') const async = require('async') function updateRow (row, cb) { diff --git a/examples/express.js b/examples/express.js index 06767a33..f09a7252 100644 --- a/examples/express.js +++ b/examples/express.js @@ -11,7 +11,7 @@ // the License. const express = require('express') -const db = require('nano')('http://localhost:5984/my_couch') +const db = require('nano')('http://127.0.0.1:5984/my_couch') const app = module.exports = express() app.get('/', function (req, res) { diff --git a/examples/lazy_creation_of_views.js b/examples/lazy_creation_of_views.js index cfef9709..47b8524e 100644 --- a/examples/lazy_creation_of_views.js +++ b/examples/lazy_creation_of_views.js @@ -11,7 +11,7 @@ // the License. module.exports = function () { - const nano = require('nano')('http://localhost:5984') + const nano = require('nano')('http://127.0.0.1:5984') const users = nano.use('users') const VIEWS = { by_twitter_id: diff --git a/examples/lazy_db_creation_and_replication.js b/examples/lazy_db_creation_and_replication.js index 98790c83..ae10c5df 100644 --- a/examples/lazy_db_creation_and_replication.js +++ b/examples/lazy_db_creation_and_replication.js @@ -13,8 +13,8 @@ const nano = require('nano') const couch = { - master: 'http://localhost:5984/landing_m', - replica: 'http://localhost:5984/landing_r' + master: 'http://127.0.0.1:5984/landing_m', + replica: 'http://127.0.0.1:5984/landing_r' } function insertWithRetry (db, email, retries, callback) { diff --git a/examples/pipe.js b/examples/pipe.js index 54ea484f..5f2cc9dc 100644 --- a/examples/pipe.js +++ b/examples/pipe.js @@ -11,7 +11,7 @@ // the License. const express = require('express') -const nano = require('nano')('http://localhost:5984') +const nano = require('nano')('http://127.0.0.1:5984') const app = express.createServer() const dbName = 'test' const db = nano.use(dbName) diff --git a/lib/changesreader.js b/lib/changesreader.js index a79c6567..5093b4c0 100644 --- a/lib/changesreader.js +++ b/lib/changesreader.js @@ -1,5 +1,5 @@ const EventEmitter = require('events').EventEmitter -const AbortController = global.AbortController || require('node-abort-controller').AbortController +const AbortController = global.AbortController const stream = require('stream') const EVENT_BATCH = 'batch' const EVENT_CHANGE = 'change' diff --git a/lib/nano.d.ts b/lib/nano.d.ts index abc79d3a..d40d3077 100644 --- a/lib/nano.d.ts +++ b/lib/nano.d.ts @@ -26,19 +26,24 @@ declare function nano( ): nano.ServerScope; declare namespace nano { - /** RequestDefaults.auth options */ - interface RequestDefaultOptionsAuth { - username: string, - password: string - } - - /** RequestDefaults options */ - interface RequestDefaultsOptions { - timeout?: number; - agent?: any; - headers?: object; - auth?: RequestDefaultOptionsAuth; - jar?: boolean; + /** AgentOptionsConnect options */ + interface AgentOptionsConnect { + timeout?: number + } + /** AgentOptions options */ + interface AgentOptions { + bodyTimeout?: number, + headersTimeout?: number, + keepAliveMaxTimeout?: number, + keepAliveTimeout?: number, + keepAliveTimeoutThreshold?: number, + maxHeaderSize?: number, + maxResponseSize?: number, + pipelining?: number, + connect?: AgentOptionsConnect, + strictContentLength?: boolean, + connections: null, + maxRedirections?: null } /** Nano configuration */ @@ -49,10 +54,10 @@ declare namespace nano { url: string; /** For cookie authentication */ cookie?: string; - /** HTTP request options + /** HTTP Agent options * @see README: {@link https://www.npmjs.com/package/nano#pool-size-and-open-sockets} */ - requestDefaults?: RequestDefaultsOptions; + agent?: AgentOptions; /** Logging function * @see README: {@link https://www.npmjs.com/package/nano#logging} */ diff --git a/lib/nano.js b/lib/nano.js index 26a294f6..1608cbdb 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -10,19 +10,16 @@ // License for the specific language governing permissions and limitations under // the License. -const { HttpsCookieAgent, HttpCookieAgent } = require('http-cookie-agent/http') +// const { HttpsCookieAgent, HttpCookieAgent } = require('http-cookie-agent/http') const { URL } = require('url') +const { Readable } = require('node:stream') const assert = require('assert') -const querystring = require('qs') -const axios = require('axios') -const { CookieJar } = require('tough-cookie') -const cookieJar = new CookieJar() +const tough = require('tough-cookie') +const cookieJar = new tough.CookieJar() const stream = require('stream') const pkg = require('../package.json') -const AGENT_DEFAULTS = { jar: cookieJar, keepAlive: true, maxSockets: 50, keepAliveMsecs: 30000 } +const undici = require('undici') const SCRUBBED_STR = 'XXXXXX' -const defaultHttpAgent = new HttpCookieAgent(AGENT_DEFAULTS) -const defaultHttpsAgent = new HttpsCookieAgent(AGENT_DEFAULTS) const ChangesReader = require('./changesreader.js') const MultiPartFactory = require('./multipart.js') @@ -42,7 +39,7 @@ function getCallback (opts, callback) { } } -// feed this any number of arguements, it will return true if +// feed this any number of arguments, it will return true if // any of them are missing (falsey) function missing (...params) { return params.some(param => !param) @@ -71,12 +68,25 @@ module.exports = exports = function dbScope (cfg) { cfg = Object.assign({}, cfg) serverScope.config = cfg - cfg.requestDefaults = cfg.requestDefaults || {} + // cfg.requestDefaults = cfg.requestDefaults || {} const dummyLogger = () => {} const log = typeof cfg.log === 'function' ? cfg.log : dummyLogger const parseUrl = 'parseUrl' in cfg ? cfg.parseUrl : true + // pre-parse the URL to extract URL without auth details + cfg.parsedURL = new URL(cfg.url) + cfg.plainURL = `${cfg.parsedURL.origin}${cfg.parsedURL.pathname}` + cfg.headers = cfg.headers || {} + if (cfg.parsedURL.username && cfg.parsedURL.password) { + cfg.headers.Authorization = 'Basic ' + Buffer.from(`${cfg.parsedURL.username}:${cfg.parsedURL.password}`).toString('base64') + } + + // look for agentOptions + if (cfg.agentOptions && typeof cfg.agentOptions === 'object') { + cfg.agent = new undici.Agent(cfg.agentOptions) + } + function maybeExtractDatabaseComponent () { if (!parseUrl) { return @@ -113,38 +123,47 @@ module.exports = exports = function dbScope (cfg) { req.auth.username = SCRUBBED_STR req.auth.password = SCRUBBED_STR } + if (req.headers.Authorization) { + req.headers.Authorization = 'XXXXXXX' + } } - const responseHandler = function (response, req, opts, resolve, reject, callback) { - const statusCode = response.status || (response.response && response.response.status) || 500 - if (response.isAxiosError && response.response) { - response = response.response - } - let body = response.data + const responseHandler = async function (response, req, opts, resolve, reject, callback) { + const statusCode = response.status || 500 + let body = response.body response.statusCode = statusCode + // cookie parsing + if (response.headers) { + const h = response.headers.get('set-cookie') + if (h) { + const cookie = tough.Cookie.parse(h) + cookieJar.setCookieSync(cookie, req.url) + } + } + // let parsed const responseHeaders = Object.assign({ uri: scrubURL(req.url), statusCode }, response.headers) if (!response.status) { - if (axios.isCancel(response)) { - if (resolve) { - resolve('canceled') - } - if (callback) { - callback(null, 'canceled', responseHeaders) - } - return - } - + // if (axios.isCancel(response)) { + // if (resolve) { + // resolve('canceled') + // } + // if (callback) { + // callback(null, 'canceled', responseHeaders) + // } + // return + // } + response.statusText = response.cause.toString() log({ err: 'socket', body, headers: responseHeaders }) if (reject) { - reject(new Error(`error happened in your connection. Reason: ${response.message}`)) + reject(new Error(`error happened in your connection. Reason: ${response.statusText}`)) } if (callback) { - const returnError = new Error(`error happened in your connection. Reason: ${response.message}`) + const returnError = new Error(`error happened in your connection. Reason: ${response.statusText}`) returnError.scope = 'socket' returnError.errid = 'request' callback(returnError) @@ -163,21 +182,42 @@ module.exports = exports = function dbScope (cfg) { if (statusCode >= 200 && statusCode < 400) { log({ err: null, body, headers: responseHeaders }) - if (resolve) { - resolve(body) + const ct = response.headers.get('content-type') + let retval = '' + if (ct === 'application/json') { + try { + retval = await response.json() + } catch { + // do nothing + } + } else if (ct && (ct.startsWith('text/') || ct.startsWith('multipart/related'))) { + retval = await response.text() + } else { + const ab = await response.arrayBuffer() + retval = Buffer.from(ab) } - if (callback) { - callback(null, body, responseHeaders) + // promisey + if (resolve) { + resolve(retval) + } else if (callback) { + // callbacky + callback(null, retval, Object.fromEntries(response.headers)) } return } // cloudant stacktrace + try { + body = await response.json() + } catch (e) { + body = '' + } + if (typeof body === 'string') { body = { message: body } } - if (!body.message && (body.reason || body.error)) { + if (body && !body.message && (body.reason || body.error)) { body.message = (body.reason || body.error) } @@ -238,7 +278,9 @@ module.exports = exports = function dbScope (cfg) { log({ err: 'couch', body: message, headers: responseHeaders }) - stream.emit('error', error) + setTimeout(() => { + stream.emit('error', error) + }, 10) } function relax (opts, callback) { @@ -259,7 +301,7 @@ module.exports = exports = function dbScope (cfg) { const qs = Object.assign({}, opts.qs) const headers = { - 'content-type': 'application/json', + // 'content-type': 'application/json', accept: 'application/json', 'user-agent': `${pkg.name}/${pkg.version} (Node.js ${process.version})`, 'Accept-Encoding': 'deflate, gzip' @@ -268,23 +310,25 @@ module.exports = exports = function dbScope (cfg) { const req = Object.assign({ method: (opts.method || 'GET'), headers, - uri: cfg.url + uri: cfg.plainURL }, { - ...cfg.requestDefaults, - headers: Object.assign(headers, cfg.requestDefaults && cfg.requestDefaults.headers ? cfg.requestDefaults.headers : {}) + headers: Object.assign(headers, cfg.headers ? cfg.headers : {}) }) + if (!headers['content-type']) { + headers['content-type'] = 'application/json' + } // https://github.com/mikeal/request#requestjar - const isJar = opts.jar || cfg.jar || (cfg.requestDefaults && cfg.requestDefaults.jar) + // const isJar = opts.jar || cfg.jar || (cfg.requestDefaults && cfg.requestDefaults.jar) if (opts.signal) { req.signal = opts.signal } - if (isJar) { - req.jar = cookieJar - req.withCredentials = true - } + // if (isJar) { + // req.jar = cookieJar + // req.withCredentials = true + // } // http://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing if (opts.db) { @@ -302,7 +346,10 @@ module.exports = exports = function dbScope (cfg) { req.headers = Object.assign(req.headers, opts.headers, cfg.defaultHeaders) if (opts.path) { - req.uri += '/' + opts.path + if (!req.uri.endsWith('/')) { + req.uri += '/' + } + req.uri += opts.path } else if (opts.doc) { if (!/^_design|_local/.test(opts.doc)) { // http://wiki.apache.org/couchdb/HTTP_Document_API#Naming.2FAddressing @@ -368,14 +415,14 @@ module.exports = exports = function dbScope (cfg) { if (opts.form) { req.headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8' - req.body = querystring.stringify(opts.form).toString('utf8') + req.body = new URLSearchParams(opts.form) } // ask request to render query string arrays as repeated values e.g. // ?drilldown=["author","Dickens"]&drilldown=["publisher","Penguin"] req.qsStringifyOptions = { arrayFormat: 'repeat' } - cfg.cookies = cookieJar.getCookiesSync(cfg.url) + // cfg.cookies = cookieJar.getCookiesSync(cfg.url) // This where the HTTP request is made. // Nano used to use the now-deprecated "request" library but now we're going to @@ -384,10 +431,7 @@ module.exports = exports = function dbScope (cfg) { delete req.uri req.method = req.method.toLowerCase() req.params = req.qs - delete req.qs - req.paramsSerializer = { - serialize: (params) => querystring.stringify(params, { arrayFormat: 'brackets' }) - } + req.serializedParams = new URLSearchParams(req.params) req.data = req.body delete req.body req.maxRedirects = 0 @@ -407,36 +451,74 @@ module.exports = exports = function dbScope (cfg) { log(scrubbedReq) // add http agents - req.httpAgent = cfg.requestDefaults.agent || defaultHttpAgent - req.httpsAgent = cfg.requestDefaults.agent || defaultHttpsAgent - req.httpAgent.jar = req.httpAgent.jar ? req.httpAgent.jar : cookieJar - req.httpsAgent.jar = req.httpsAgent.jar ? req.httpsAgent.jar : cookieJar - const ax = axios.create({ - httpAgent: req.httpAgent, - httpsAgent: req.httpsAgent - }) + // req.httpAgent = cfg.requestDefaults.agent || defaultHttpAgent + // req.httpsAgent = cfg.requestDefaults.agent || defaultHttpsAgent + // req.httpAgent.jar = req.httpAgent.jar ? req.httpAgent.jar : cookieJar + // req.httpsAgent.jar = req.httpsAgent.jar ? req.httpsAgent.jar : cookieJar + + // insert basic auth headers, if present + Object.assign(req.headers, cfg.headers) + + const fetchOptions = { + method: req.method, + headers: req.headers, + credentials: 'include', + body: req.method !== 'get' && req.data ? req.data : undefined, + redirect: 'error', + keepalive: true, + signal: req.signal + } + + // add custom agent if present + if (cfg.agent) { + fetchOptions.dispatcher = cfg.agent + } + + // add querystring params + const queryString = req.serializedParams.toString() + if (queryString.length > 0) { + req.url += '?' + queryString + } + + // if the body is readable stream + if (fetchOptions.body && fetchOptions.body instanceof stream.Readable) { + fetchOptions.duplex = 'half' + fetchOptions.keepalive = false + } + + // add any cookies for this domain + const cookie = cookieJar.getCookieStringSync(req.url) + if (cookie) { + fetchOptions.headers.cookie = cookie + } // actually do the HTTP request if (opts.stream) { // return the Request object for streaming const outStream = new stream.PassThrough() - ax(req) - .then((response) => { - response.data.pipe(outStream) + fetch(req.url, fetchOptions) + .then(async (response) => { + const readableWebStream = response.body + const readableNodeStream = Readable.fromWeb(readableWebStream) + if (response.status > 300) { + streamResponseHandler(response, req, outStream) + } else { + readableNodeStream.pipe(outStream) + } }).catch(e => { streamResponseHandler(e, req, outStream) }) return outStream } else { if (typeof callback === 'function') { - ax(req).then((response) => { + fetch(req.url, fetchOptions).then((response) => { responseHandler(response, req, opts, null, null, callback) }).catch((e) => { responseHandler(e, req, opts, null, null, callback) }) } else { return new Promise((resolve, reject) => { - ax(req).then((response) => { + fetch(req.url, fetchOptions).then((response) => { responseHandler(response, req, opts, resolve, reject) }).catch((e) => { responseHandler(e, req, opts, resolve, reject) diff --git a/package-lock.json b/package-lock.json index 990d7166..4c8cc28e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9729 +1,140 @@ { "name": "nano", - "version": "10.1.0", + "version": "11.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nano", - "version": "10.1.0", - "license": "Apache-2.0", - "dependencies": { - "@types/tough-cookie": "^4.0.2", - "axios": "^1.1.3", - "http-cookie-agent": "^4.0.2", - "node-abort-controller": "^3.0.1", - "qs": "^6.11.0", - "tough-cookie": "^4.1.2" - }, - "devDependencies": { - "@types/node": "^18.11.9", - "jest": "^29.2.2", - "nock": "^13.2.9", - "standard": "^17.0.0", - "typescript": "^4.8.4" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@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, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", - "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", - "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.6", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.6", - "@babel/helpers": "^7.19.4", - "@babel/parser": "^7.19.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.6", - "@babel/types": "^7.19.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", - "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^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-module-transforms": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", - "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.19.4", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.6", - "@babel/types": "^7.19.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", - "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.19.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", - "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.0" - }, - "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, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "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, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "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, - "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 - }, - "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, - "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, - "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, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", - "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", - "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", - "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "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 - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "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" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/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==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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 - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.2.1.tgz", - "integrity": "sha512-MF8Adcw+WPLZGBiNxn76DOuczG3BhODTcMlDCA4+cFi41OkaY/lyI0XUUhi73F88Y+7IHoGmD80pN5CtxQUdSw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.2.2.tgz", - "integrity": "sha512-susVl8o2KYLcZhhkvSB+b7xX575CX3TmSvxfeDjpRko7KmT89rHkXj6XkDkNpSeFMBzIENw5qIchO9HC9Sem+A==", - "dev": true, - "dependencies": { - "@jest/console": "^29.2.1", - "@jest/reporters": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.2.2", - "jest-haste-map": "^29.2.1", - "jest-message-util": "^29.2.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.2.2", - "jest-resolve-dependencies": "^29.2.2", - "jest-runner": "^29.2.2", - "jest-runtime": "^29.2.2", - "jest-snapshot": "^29.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "jest-watcher": "^29.2.2", - "micromatch": "^4.0.4", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.2.2.tgz", - "integrity": "sha512-OWn+Vhu0I1yxuGBJEFFekMYc8aGBGrY4rt47SOh/IFaI+D7ZHCk7pKRiSoZ2/Ml7b0Ony3ydmEHRx/tEOC7H1A==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "jest-mock": "^29.2.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.2.2.tgz", - "integrity": "sha512-zwblIZnrIVt8z/SiEeJ7Q9wKKuB+/GS4yZe9zw7gMqfGf4C5hBLGrVyxu1SzDbVSqyMSlprKl3WL1r80cBNkgg==", - "dev": true, - "dependencies": { - "expect": "^29.2.2", - "jest-snapshot": "^29.2.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.2.2.tgz", - "integrity": "sha512-vwnVmrVhTmGgQzyvcpze08br91OL61t9O0lJMDyb6Y/D8EKQ9V7rGUb/p7PDt0GPzK0zFYqXWFo4EO2legXmkg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.2.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.2.2.tgz", - "integrity": "sha512-nqaW3y2aSyZDl7zQ7t1XogsxeavNpH6kkdq+EpXncIDvAkjvFD7hmhcIs1nWloengEWUoWqkqSA6MSbf9w6DgA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.2.1", - "jest-mock": "^29.2.2", - "jest-util": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.2.2.tgz", - "integrity": "sha512-/nt+5YMh65kYcfBhj38B3Hm0Trk4IsuMXNDGKE/swp36yydBWfz3OXkLqkSvoAtPW8IJMSJDFCbTM2oj5SNprw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.2.2", - "@jest/expect": "^29.2.2", - "@jest/types": "^29.2.1", - "jest-mock": "^29.2.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.2.2.tgz", - "integrity": "sha512-AzjL2rl2zJC0njIzcooBvjA4sJjvdoq98sDuuNs4aNugtLPSQ+91nysGKRF0uY1to5k0MdGMdOBggUsPqvBcpA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.2.1", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1", - "jest-worker": "^29.2.1", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.2.1.tgz", - "integrity": "sha512-lS4+H+VkhbX6z64tZP7PAUwPqhwj3kbuEHcaLuaBuB+riyaX7oa1txe0tXgrFj5hRWvZKvqO7LZDlNWeJ7VTPA==", - "dev": true, - "dependencies": { - "@jest/console": "^29.2.1", - "@jest/types": "^29.2.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.2.2.tgz", - "integrity": "sha512-Cuc1znc1pl4v9REgmmLf0jBd3Y65UXJpioGYtMr/JNpQEIGEzkmHhy6W6DLbSsXeUA13TDzymPv0ZGZ9jH3eIw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.2.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.2.2.tgz", - "integrity": "sha512-aPe6rrletyuEIt2axxgdtxljmzH8O/nrov4byy6pDw9S8inIrTV+2PnjyP/oFHMSynzGxJ2s6OHowBNMXp/Jzg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.2.1", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.2.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", - "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "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, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "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, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.4.tgz", - "integrity": "sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", - "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "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 - }, - "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==" - }, - "node_modules/@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.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, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "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" - } - }, - "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, - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/babel-jest": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.2.2.tgz", - "integrity": "sha512-kkq2QSDIuvpgfoac3WZ1OOcHsQQDU5xYk2Ql7tLdJ8BVAYbefEXal+NfS45Y5LVZA7cxC8KYcQMObpCt1J025w==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.2.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.2.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/builtins/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001429", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", - "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", - "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "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, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "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==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "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, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.2.0.tgz", - "integrity": "sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "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 - }, - "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, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", - "dev": true, - "dependencies": { - "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.3", - "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.7", - "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.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "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, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "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==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "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.4.0", - "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", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "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" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", - "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "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": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-config-standard-jsx": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", - "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==", - "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": "^8.8.0", - "eslint-plugin-react": "^7.28.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "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==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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==", - "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" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "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==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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-n": { - "version": "15.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.4.0.tgz", - "integrity": "sha512-MkoKy9/lfd52TAXK4fkABgCp0aglk82Q3viy2UOWIEpTVE/Cem5P/UAxMBA4vSw7Gy+2egPqImE9euitLGp5aw==", - "dev": true, - "dependencies": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.10.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.7" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.31.10", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", - "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "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==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "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" - } - }, - "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==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "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==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.2.2.tgz", - "integrity": "sha512-hE09QerxZ5wXiOhqkXy5d2G9ar+EqOyifnCXCpMNu+vZ6DG9TJ6CO2c2kPDSLqERTTWrO7OZj8EkYHQqSd78Yw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.2.2", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.2.2", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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-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": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "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==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "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==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "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" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/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, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "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" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "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==", - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "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" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/http-cookie-agent": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-4.0.2.tgz", - "integrity": "sha512-noTmxdH5CuytTnLj/Qv3Z84e/YFq8yLXAw3pqIYZ25Edhb9pQErIAC+ednw40Cic6Le/h9ryph5/TqsvkOaUCw==", - "dependencies": { - "agent-base": "^6.0.2" - }, - "engines": { - "node": ">=14.18.0 <15.0.0 || >=16.0.0" - }, - "peerDependencies": { - "deasync": "^0.1.26", - "tough-cookie": "^4.0.0", - "undici": "^5.1.1" - }, - "peerDependenciesMeta": { - "deasync": { - "optional": true - }, - "undici": { - "optional": true - } - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "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==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "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": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "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==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "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": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "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" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.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==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.2.2.tgz", - "integrity": "sha512-r+0zCN9kUqoON6IjDdjbrsWobXM/09Nd45kIPRD8kloaRh1z5ZCMdVsgLXGxmlL7UpAJsvCYOQNO+NjvG/gqiQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.2.2", - "@jest/types": "^29.2.1", - "import-local": "^3.0.2", - "jest-cli": "^29.2.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.2.2.tgz", - "integrity": "sha512-upSdWxx+Mh4DV7oueuZndJ1NVdgtTsqM4YgywHEx05UMH5nxxA2Qu9T9T9XVuR021XxqSoaKvSmmpAbjwwwxMw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.2.2", - "@jest/expect": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.2.1", - "jest-matcher-utils": "^29.2.2", - "jest-message-util": "^29.2.1", - "jest-runtime": "^29.2.2", - "jest-snapshot": "^29.2.2", - "jest-util": "^29.2.1", - "p-limit": "^3.1.0", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.2.2.tgz", - "integrity": "sha512-R45ygnnb2CQOfd8rTPFR+/fls0d+1zXS6JPYTBBrnLPrhr58SSuPTiA5Tplv8/PXpz4zXR/AYNxmwIj6J6nrvg==", - "dev": true, - "dependencies": { - "@jest/core": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/types": "^29.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.2.2.tgz", - "integrity": "sha512-Q0JX54a5g1lP63keRfKR8EuC7n7wwny2HoTRDb8cx78IwQOiaYUVZAdjViY3WcTxpR02rPUpvNVmZ1fkIlZPcw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.2.2", - "@jest/types": "^29.2.1", - "babel-jest": "^29.2.2", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.2.2", - "jest-environment-node": "^29.2.2", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.2.2", - "jest-runner": "^29.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.2.1.tgz", - "integrity": "sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.2.0", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.2.1.tgz", - "integrity": "sha512-sGP86H/CpWHMyK3qGIGFCgP6mt+o5tu9qG4+tobl0LNdgny0aitLXs9/EBacLy3Bwqy+v4uXClqJgASJWcruYw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.2.1", - "pretty-format": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.2.2.tgz", - "integrity": "sha512-B7qDxQjkIakQf+YyrqV5dICNs7tlCO55WJ4OMSXsqz1lpI/0PmeuXdx2F7eU8rnPbRkUR/fItSSUh0jvE2y/tw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.2.2", - "@jest/fake-timers": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "jest-mock": "^29.2.2", - "jest-util": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.2.1.tgz", - "integrity": "sha512-wF460rAFmYc6ARcCFNw4MbGYQjYkvjovb9GBT+W10Um8q5nHq98jD6fHZMDMO3tA56S8XnmNkM8GcA8diSZfnA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.2.1", - "jest-worker": "^29.2.1", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.2.1.tgz", - "integrity": "sha512-1YvSqYoiurxKOJtySc+CGVmw/e1v4yNY27BjWTVzp0aTduQeA7pdieLiW05wTYG/twlKOp2xS/pWuikQEmklug==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz", - "integrity": "sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.2.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.2.1.tgz", - "integrity": "sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.2.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.2.2.tgz", - "integrity": "sha512-1leySQxNAnivvbcx0sCB37itu8f4OX2S/+gxLAV4Z62shT4r4dTG9tACDywUAEZoLSr36aYUTsVp3WKwWt4PMQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "@types/node": "*", - "jest-util": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.2.2.tgz", - "integrity": "sha512-3gaLpiC3kr14rJR3w7vWh0CBX2QAhfpfiQTwrFPvVrcHe5VUBtIXaR004aWE/X9B2CFrITOQAp5gxLONGrk6GA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.2.2.tgz", - "integrity": "sha512-wWOmgbkbIC2NmFsq8Lb+3EkHuW5oZfctffTGvwsA4JcJ1IRk8b2tg+hz44f0lngvRTeHvp3Kyix9ACgudHH9aQ==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.2.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.2.2.tgz", - "integrity": "sha512-1CpUxXDrbsfy9Hr9/1zCUUhT813kGGK//58HeIw/t8fa/DmkecEwZSWlb1N/xDKXg3uCFHQp1GCvlSClfImMxg==", - "dev": true, - "dependencies": { - "@jest/console": "^29.2.1", - "@jest/environment": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.2.2", - "jest-haste-map": "^29.2.1", - "jest-leak-detector": "^29.2.1", - "jest-message-util": "^29.2.1", - "jest-resolve": "^29.2.2", - "jest-runtime": "^29.2.2", - "jest-util": "^29.2.1", - "jest-watcher": "^29.2.2", - "jest-worker": "^29.2.1", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.2.2.tgz", - "integrity": "sha512-TpR1V6zRdLynckKDIQaY41od4o0xWL+KOPUCZvJK2bu5P1UXhjobt5nJ2ICNeIxgyj9NGkO0aWgDqYPVhDNKjA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.2.2", - "@jest/fake-timers": "^29.2.2", - "@jest/globals": "^29.2.2", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "jest-message-util": "^29.2.1", - "jest-mock": "^29.2.2", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.2.2", - "jest-snapshot": "^29.2.2", - "jest-util": "^29.2.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.2.2.tgz", - "integrity": "sha512-GfKJrpZ5SMqhli3NJ+mOspDqtZfJBryGA8RIBxF+G+WbDoC7HCqKaeAss4Z/Sab6bAW11ffasx8/vGsj83jyjA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.2.2", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.2.2", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.2.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.2.1", - "jest-matcher-utils": "^29.2.2", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1", - "natural-compare": "^1.4.0", - "pretty-format": "^29.2.1", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", - "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.2.2.tgz", - "integrity": "sha512-eJXATaKaSnOuxNfs8CLHgdABFgUrd0TtWS8QckiJ4L/QVDF4KVbZFBBOwCBZHOS0Rc5fOxqngXeGXE3nGQkpQA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.2.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "leven": "^3.1.0", - "pretty-format": "^29.2.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.2.2.tgz", - "integrity": "sha512-j2otfqh7mOvMgN2WlJ0n7gIx9XCMWntheYGlBK7+5g3b1Su13/UAK7pdKGyd4kDlrLwtH2QPvRv5oNIxWvsJ1w==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.2.1", - "@jest/types": "^29.2.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.2.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", - "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.2.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", - "dev": true - }, - "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/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, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "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-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", - "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": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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", - "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, - "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" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/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==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "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/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, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nock": { - "version": "13.2.9", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.9.tgz", - "integrity": "sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.21", - "propagate": "^2.0.0" - }, - "engines": { - "node": ">= 10.13" - } - }, - "node_modules/node-abort-controller": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", - "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/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, - "engines": { - "node": ">= 0.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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", - "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/object.hasown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", - "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "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": ">= 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" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "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/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "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==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.2.1.tgz", - "integrity": "sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/propagate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", - "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "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==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "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==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "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" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.0.0.tgz", - "integrity": "sha512-GlCM9nzbLUkr+TYR5I2WQoIah4wHA2lMauqbyPLV/oI5gJxqhHzhjl9EG2N0lr/nRqI3KCbCvm/W3smxvLaChA==", - "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": "^8.13.0", - "eslint-config-standard": "17.0.0", - "eslint-config-standard-jsx": "^11.0.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.1.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-react": "^7.28.0", - "standard-engine": "^15.0.0" - }, - "bin": { - "standard": "bin/cmd.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/standard-engine": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.0.0.tgz", - "integrity": "sha512-4xwUhJNo1g/L2cleysUqUv7/btn7GEbYJvmgKrQ2vd/8pkTmN8cpqAZg+BT8Z1hNeEH787iWUdOpL8fmApLtxA==", - "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.6", - "pkg-conf": "^3.1.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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" - } - }, - "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==", - "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" - } - }, - "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" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "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==", - "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" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "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==", - "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" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "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": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "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 - }, - "node_modules/yargs": { - "version": "17.6.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.1.tgz", - "integrity": "sha512-leBuCGrL4dAd6ispNOGsJlhd0uZ6Qehkbu/B9KCR+Pxa/NVdNwi+i31lo0buCm6XxhJQFshXCD0/evfV4xfoUg==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@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" - } - }, - "@babel/compat-data": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", - "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", - "dev": true - }, - "@babel/core": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", - "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.6", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.6", - "@babel/helpers": "^7.19.4", - "@babel/parser": "^7.19.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.6", - "@babel/types": "^7.19.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", - "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", - "dev": true, - "requires": { - "@babel/types": "^7.20.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.20.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@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, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", - "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.19.4", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.6", - "@babel/types": "^7.19.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", - "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", - "dev": true, - "requires": { - "@babel/types": "^7.19.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", - "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "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==", - "dev": true, - "requires": { - "color-convert": "^1.9.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==", - "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", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "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==", - "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" - } - } - } - }, - "@babel/parser": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", - "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", - "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", - "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.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.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "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" - }, - "dependencies": { - "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 - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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, - "requires": { - "type-fest": "^0.20.2" - } - }, - "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" - } - }, - "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 - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@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/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - } - }, - "@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 - }, - "@jest/console": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.2.1.tgz", - "integrity": "sha512-MF8Adcw+WPLZGBiNxn76DOuczG3BhODTcMlDCA4+cFi41OkaY/lyI0XUUhi73F88Y+7IHoGmD80pN5CtxQUdSw==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.2.2.tgz", - "integrity": "sha512-susVl8o2KYLcZhhkvSB+b7xX575CX3TmSvxfeDjpRko7KmT89rHkXj6XkDkNpSeFMBzIENw5qIchO9HC9Sem+A==", - "dev": true, - "requires": { - "@jest/console": "^29.2.1", - "@jest/reporters": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.2.2", - "jest-haste-map": "^29.2.1", - "jest-message-util": "^29.2.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.2.2", - "jest-resolve-dependencies": "^29.2.2", - "jest-runner": "^29.2.2", - "jest-runtime": "^29.2.2", - "jest-snapshot": "^29.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "jest-watcher": "^29.2.2", - "micromatch": "^4.0.4", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.2.2.tgz", - "integrity": "sha512-OWn+Vhu0I1yxuGBJEFFekMYc8aGBGrY4rt47SOh/IFaI+D7ZHCk7pKRiSoZ2/Ml7b0Ony3ydmEHRx/tEOC7H1A==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "jest-mock": "^29.2.2" - } - }, - "@jest/expect": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.2.2.tgz", - "integrity": "sha512-zwblIZnrIVt8z/SiEeJ7Q9wKKuB+/GS4yZe9zw7gMqfGf4C5hBLGrVyxu1SzDbVSqyMSlprKl3WL1r80cBNkgg==", - "dev": true, - "requires": { - "expect": "^29.2.2", - "jest-snapshot": "^29.2.2" - } - }, - "@jest/expect-utils": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.2.2.tgz", - "integrity": "sha512-vwnVmrVhTmGgQzyvcpze08br91OL61t9O0lJMDyb6Y/D8EKQ9V7rGUb/p7PDt0GPzK0zFYqXWFo4EO2legXmkg==", - "dev": true, - "requires": { - "jest-get-type": "^29.2.0" - } - }, - "@jest/fake-timers": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.2.2.tgz", - "integrity": "sha512-nqaW3y2aSyZDl7zQ7t1XogsxeavNpH6kkdq+EpXncIDvAkjvFD7hmhcIs1nWloengEWUoWqkqSA6MSbf9w6DgA==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.2.1", - "jest-mock": "^29.2.2", - "jest-util": "^29.2.1" - } - }, - "@jest/globals": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.2.2.tgz", - "integrity": "sha512-/nt+5YMh65kYcfBhj38B3Hm0Trk4IsuMXNDGKE/swp36yydBWfz3OXkLqkSvoAtPW8IJMSJDFCbTM2oj5SNprw==", - "dev": true, - "requires": { - "@jest/environment": "^29.2.2", - "@jest/expect": "^29.2.2", - "@jest/types": "^29.2.1", - "jest-mock": "^29.2.2" - } - }, - "@jest/reporters": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.2.2.tgz", - "integrity": "sha512-AzjL2rl2zJC0njIzcooBvjA4sJjvdoq98sDuuNs4aNugtLPSQ+91nysGKRF0uY1to5k0MdGMdOBggUsPqvBcpA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.2.1", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1", - "jest-worker": "^29.2.1", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.2.1.tgz", - "integrity": "sha512-lS4+H+VkhbX6z64tZP7PAUwPqhwj3kbuEHcaLuaBuB+riyaX7oa1txe0tXgrFj5hRWvZKvqO7LZDlNWeJ7VTPA==", - "dev": true, - "requires": { - "@jest/console": "^29.2.1", - "@jest/types": "^29.2.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.2.2.tgz", - "integrity": "sha512-Cuc1znc1pl4v9REgmmLf0jBd3Y65UXJpioGYtMr/JNpQEIGEzkmHhy6W6DLbSsXeUA13TDzymPv0ZGZ9jH3eIw==", - "dev": true, - "requires": { - "@jest/test-result": "^29.2.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.2.2.tgz", - "integrity": "sha512-aPe6rrletyuEIt2axxgdtxljmzH8O/nrov4byy6pDw9S8inIrTV+2PnjyP/oFHMSynzGxJ2s6OHowBNMXp/Jzg==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.2.1", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.2.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "@jest/types": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", - "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@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, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@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==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.4.tgz", - "integrity": "sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", - "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@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 - }, - "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", - "dev": true - }, - "@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==" - }, - "@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "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, - "requires": {} - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "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==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "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" - } - }, - "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, - "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" - } - }, - "array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "babel-jest": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.2.2.tgz", - "integrity": "sha512-kkq2QSDIuvpgfoac3WZ1OOcHsQQDU5xYk2Ql7tLdJ8BVAYbefEXal+NfS45Y5LVZA7cxC8KYcQMObpCt1J025w==", - "dev": true, - "requires": { - "@jest/transform": "^29.2.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.2.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "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 - }, - "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, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "requires": { - "semver": "^7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001429", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", - "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", - "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "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, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "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==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^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==" - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.2.0.tgz", - "integrity": "sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "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 - }, - "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, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", - "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.3", - "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.7", - "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.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "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, - "requires": { - "has": "^1.0.3" - } - }, - "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, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "eslint": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", - "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "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.4.0", - "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", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "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" - }, - "dependencies": { - "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 - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "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" - } - }, - "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, - "requires": { - "type-fest": "^0.20.2" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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 - } - } - }, - "eslint-config-standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", - "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "dev": true, - "requires": {} - }, - "eslint-config-standard-jsx": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", - "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==", - "dev": true, - "requires": {} - }, - "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==", - "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" - } - } - } - }, - "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==", - "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" - } - } - } - }, - "eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "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 - } - } - }, - "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==", - "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 - } - } - }, - "eslint-plugin-n": { - "version": "15.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.4.0.tgz", - "integrity": "sha512-MkoKy9/lfd52TAXK4fkABgCp0aglk82Q3viy2UOWIEpTVE/Cem5P/UAxMBA4vSw7Gy+2egPqImE9euitLGp5aw==", - "dev": true, - "requires": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.10.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.7" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", - "dev": true, - "requires": {} - }, - "eslint-plugin-react": { - "version": "7.31.10", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", - "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "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" - } - }, - "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "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==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "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 - } - } - }, - "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.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.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==", - "dev": true, - "requires": { - "estraverse": "^5.2.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 - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.2.2.tgz", - "integrity": "sha512-hE09QerxZ5wXiOhqkXy5d2G9ar+EqOyifnCXCpMNu+vZ6DG9TJ6CO2c2kPDSLqERTTWrO7OZj8EkYHQqSd78Yw==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.2.2", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.2.2", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1" - } - }, - "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 - }, - "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 - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "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" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "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" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.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.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" - }, - "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": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": 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==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "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 - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "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.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "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 - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "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, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "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" - } - }, - "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, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "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" - } - }, - "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==", - "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==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "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==", - "dev": true, - "requires": { - "has-symbols": "^1.0.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 - }, - "http-cookie-agent": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-4.0.2.tgz", - "integrity": "sha512-noTmxdH5CuytTnLj/Qv3Z84e/YFq8yLXAw3pqIYZ25Edhb9pQErIAC+ednw40Cic6Le/h9ryph5/TqsvkOaUCw==", - "requires": { - "agent-base": "^6.0.2" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "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" - }, - "dependencies": { - "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 - } - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "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": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "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.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "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": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "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-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "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-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "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-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "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": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "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-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.2.2.tgz", - "integrity": "sha512-r+0zCN9kUqoON6IjDdjbrsWobXM/09Nd45kIPRD8kloaRh1z5ZCMdVsgLXGxmlL7UpAJsvCYOQNO+NjvG/gqiQ==", - "dev": true, - "requires": { - "@jest/core": "^29.2.2", - "@jest/types": "^29.2.1", - "import-local": "^3.0.2", - "jest-cli": "^29.2.2" - } - }, - "jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.2.2.tgz", - "integrity": "sha512-upSdWxx+Mh4DV7oueuZndJ1NVdgtTsqM4YgywHEx05UMH5nxxA2Qu9T9T9XVuR021XxqSoaKvSmmpAbjwwwxMw==", - "dev": true, - "requires": { - "@jest/environment": "^29.2.2", - "@jest/expect": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.2.1", - "jest-matcher-utils": "^29.2.2", - "jest-message-util": "^29.2.1", - "jest-runtime": "^29.2.2", - "jest-snapshot": "^29.2.2", - "jest-util": "^29.2.1", - "p-limit": "^3.1.0", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.2.2.tgz", - "integrity": "sha512-R45ygnnb2CQOfd8rTPFR+/fls0d+1zXS6JPYTBBrnLPrhr58SSuPTiA5Tplv8/PXpz4zXR/AYNxmwIj6J6nrvg==", - "dev": true, - "requires": { - "@jest/core": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/types": "^29.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.2.2.tgz", - "integrity": "sha512-Q0JX54a5g1lP63keRfKR8EuC7n7wwny2HoTRDb8cx78IwQOiaYUVZAdjViY3WcTxpR02rPUpvNVmZ1fkIlZPcw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.2.2", - "@jest/types": "^29.2.1", - "babel-jest": "^29.2.2", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.2.2", - "jest-environment-node": "^29.2.2", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.2.2", - "jest-runner": "^29.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.2.1.tgz", - "integrity": "sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.2.0", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.2.1" - } - }, - "jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.2.1.tgz", - "integrity": "sha512-sGP86H/CpWHMyK3qGIGFCgP6mt+o5tu9qG4+tobl0LNdgny0aitLXs9/EBacLy3Bwqy+v4uXClqJgASJWcruYw==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.2.1", - "pretty-format": "^29.2.1" - } - }, - "jest-environment-node": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.2.2.tgz", - "integrity": "sha512-B7qDxQjkIakQf+YyrqV5dICNs7tlCO55WJ4OMSXsqz1lpI/0PmeuXdx2F7eU8rnPbRkUR/fItSSUh0jvE2y/tw==", - "dev": true, - "requires": { - "@jest/environment": "^29.2.2", - "@jest/fake-timers": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "jest-mock": "^29.2.2", - "jest-util": "^29.2.1" - } - }, - "jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", - "dev": true - }, - "jest-haste-map": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.2.1.tgz", - "integrity": "sha512-wF460rAFmYc6ARcCFNw4MbGYQjYkvjovb9GBT+W10Um8q5nHq98jD6fHZMDMO3tA56S8XnmNkM8GcA8diSZfnA==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.2.1", - "jest-worker": "^29.2.1", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.2.1.tgz", - "integrity": "sha512-1YvSqYoiurxKOJtySc+CGVmw/e1v4yNY27BjWTVzp0aTduQeA7pdieLiW05wTYG/twlKOp2xS/pWuikQEmklug==", - "dev": true, - "requires": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.2.1" - } - }, - "jest-matcher-utils": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz", - "integrity": "sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.2.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.2.1" - } - }, - "jest-message-util": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.2.1.tgz", - "integrity": "sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.2.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.2.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.2.2.tgz", - "integrity": "sha512-1leySQxNAnivvbcx0sCB37itu8f4OX2S/+gxLAV4Z62shT4r4dTG9tACDywUAEZoLSr36aYUTsVp3WKwWt4PMQ==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "@types/node": "*", - "jest-util": "^29.2.1" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", - "dev": true - }, - "jest-resolve": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.2.2.tgz", - "integrity": "sha512-3gaLpiC3kr14rJR3w7vWh0CBX2QAhfpfiQTwrFPvVrcHe5VUBtIXaR004aWE/X9B2CFrITOQAp5gxLONGrk6GA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.2.1", - "jest-validate": "^29.2.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.2.2.tgz", - "integrity": "sha512-wWOmgbkbIC2NmFsq8Lb+3EkHuW5oZfctffTGvwsA4JcJ1IRk8b2tg+hz44f0lngvRTeHvp3Kyix9ACgudHH9aQ==", - "dev": true, - "requires": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.2.2" - } - }, - "jest-runner": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.2.2.tgz", - "integrity": "sha512-1CpUxXDrbsfy9Hr9/1zCUUhT813kGGK//58HeIw/t8fa/DmkecEwZSWlb1N/xDKXg3uCFHQp1GCvlSClfImMxg==", - "dev": true, - "requires": { - "@jest/console": "^29.2.1", - "@jest/environment": "^29.2.2", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.2.2", - "jest-haste-map": "^29.2.1", - "jest-leak-detector": "^29.2.1", - "jest-message-util": "^29.2.1", - "jest-resolve": "^29.2.2", - "jest-runtime": "^29.2.2", - "jest-util": "^29.2.1", - "jest-watcher": "^29.2.2", - "jest-worker": "^29.2.1", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - } - }, - "jest-runtime": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.2.2.tgz", - "integrity": "sha512-TpR1V6zRdLynckKDIQaY41od4o0xWL+KOPUCZvJK2bu5P1UXhjobt5nJ2ICNeIxgyj9NGkO0aWgDqYPVhDNKjA==", - "dev": true, - "requires": { - "@jest/environment": "^29.2.2", - "@jest/fake-timers": "^29.2.2", - "@jest/globals": "^29.2.2", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.2.1", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.2.1", - "jest-message-util": "^29.2.1", - "jest-mock": "^29.2.2", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.2.2", - "jest-snapshot": "^29.2.2", - "jest-util": "^29.2.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - } - }, - "jest-snapshot": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.2.2.tgz", - "integrity": "sha512-GfKJrpZ5SMqhli3NJ+mOspDqtZfJBryGA8RIBxF+G+WbDoC7HCqKaeAss4Z/Sab6bAW11ffasx8/vGsj83jyjA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.2.2", - "@jest/transform": "^29.2.2", - "@jest/types": "^29.2.1", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.2.2", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.2.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.2.1", - "jest-matcher-utils": "^29.2.2", - "jest-message-util": "^29.2.1", - "jest-util": "^29.2.1", - "natural-compare": "^1.4.0", - "pretty-format": "^29.2.1", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "jest-util": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", - "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.2.2.tgz", - "integrity": "sha512-eJXATaKaSnOuxNfs8CLHgdABFgUrd0TtWS8QckiJ4L/QVDF4KVbZFBBOwCBZHOS0Rc5fOxqngXeGXE3nGQkpQA==", - "dev": true, - "requires": { - "@jest/types": "^29.2.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "leven": "^3.1.0", - "pretty-format": "^29.2.1" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.2.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.2.2.tgz", - "integrity": "sha512-j2otfqh7mOvMgN2WlJ0n7gIx9XCMWntheYGlBK7+5g3b1Su13/UAK7pdKGyd4kDlrLwtH2QPvRv5oNIxWvsJ1w==", - "dev": true, - "requires": { - "@jest/test-result": "^29.2.1", - "@jest/types": "^29.2.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.2.1", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", - "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.2.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", - "dev": true - }, - "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": "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", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "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-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 - }, - "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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true - }, - "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" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "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" - } - }, - "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 - }, - "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" - }, - "dependencies": { - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true - } - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "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 - }, - "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" - } - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "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" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "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.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "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==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "nock": { - "version": "13.2.9", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.9.tgz", - "integrity": "sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.21", - "propagate": "^2.0.0" - } - }, - "node-abort-controller": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", - "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==" - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "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==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "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", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "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", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "version": "11.0.0", + "license": "Apache-2.0", + "dependencies": { + "tough-cookie": "^4.1.2", + "undici": "^5.13.0" + }, + "devDependencies": {}, + "engines": { + "node": ">=18" } }, - "object.hasown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", - "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", - "dev": true, - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" } }, - "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", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "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==", + "engines": { + "node": ">=6" } }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, - "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", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, - "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" + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - }, + "node_modules/tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", "dependencies": { - "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" - } - } - } - }, - "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 - }, - "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" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "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 - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "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", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "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", - "load-json-file": "^5.2.0" - }, + "node_modules/undici": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.13.0.tgz", + "integrity": "sha512-UDZKtwb2k7KRsK4SdXWG7ErXiL7yTGgLWvk2AXO1JMjgjh404nFo6tWSCM2xMpJwMPx3J8i/vfqEh1zOqvj82Q==", "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" - } - }, - "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", - "path-exists": "^3.0.0" - } - }, - "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" - } - }, - "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" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true - } + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.18" } }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" } }, - "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 - }, - "pretty-format": { - "version": "29.2.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.2.1.tgz", - "integrity": "sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" } - }, - "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, + } + }, + "dependencies": { + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - }, - "dependencies": { - "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 - } + "streamsearch": "^1.1.0" } }, - "propagate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", - "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", - "dev": true - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, - "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-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "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", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "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": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve.exports": { + "streamsearch": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "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 - }, - "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" - } - }, - "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" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "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" - } - }, - "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==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - }, - "standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.0.0.tgz", - "integrity": "sha512-GlCM9nzbLUkr+TYR5I2WQoIah4wHA2lMauqbyPLV/oI5gJxqhHzhjl9EG2N0lr/nRqI3KCbCvm/W3smxvLaChA==", - "dev": true, - "requires": { - "eslint": "^8.13.0", - "eslint-config-standard": "17.0.0", - "eslint-config-standard-jsx": "^11.0.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.1.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-react": "^7.28.0", - "standard-engine": "^15.0.0" - } - }, - "standard-engine": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.0.0.tgz", - "integrity": "sha512-4xwUhJNo1g/L2cleysUqUv7/btn7GEbYJvmgKrQ2vd/8pkTmN8cpqAZg+BT8Z1hNeEH787iWUdOpL8fmApLtxA==", - "dev": true, - "requires": { - "get-stdin": "^8.0.0", - "minimist": "^1.2.6", - "pkg-conf": "^3.1.0", - "xdg-basedir": "^4.0.0" - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "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", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "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", - "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" - } - }, - "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", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "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", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "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" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "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 - }, - "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", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "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" - } + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, "tough-cookie": { "version": "4.1.2", @@ -9736,72 +147,12 @@ "url-parse": "^1.5.3" } }, - "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "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" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } - } - }, - "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, + "undici": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.13.0.tgz", + "integrity": "sha512-UDZKtwb2k7KRsK4SdXWG7ErXiL7yTGgLWvk2AXO1JMjgjh404nFo6tWSCM2xMpJwMPx3J8i/vfqEh1zOqvj82Q==", "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - }, - "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "dev": true - }, - "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", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "busboy": "^1.6.0" } }, "universalify": { @@ -9809,25 +160,6 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "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" - } - }, "url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -9836,126 +168,6 @@ "querystringify": "^2.1.1", "requires-port": "^1.0.0" } - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "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" - } - }, - "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", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "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", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "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 - }, - "yargs": { - "version": "17.6.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.1.tgz", - "integrity": "sha512-leBuCGrL4dAd6ispNOGsJlhd0uZ6Qehkbu/B9KCR+Pxa/NVdNwi+i31lo0buCm6XxhJQFshXCD0/evfV4xfoUg==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "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 1c6b47c7..61d00b0f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "license": "Apache-2.0", "homepage": "http://github.com/apache/couchdb-nano", "repository": "http://github.com/apache/couchdb-nano", - "version": "10.1.0", + "version": "11.0.0", "author": "Apache CouchDB (http://couchdb.apache.org)", "keywords": [ "couchdb", @@ -17,29 +17,18 @@ "database" ], "dependencies": { - "http-cookie-agent": "^4.0.2", - "@types/tough-cookie": "^4.0.2", - "axios": "^1.1.3", - "qs": "^6.11.0", "tough-cookie": "^4.1.2", - "node-abort-controller": "^3.0.1" + "undici": "^5.13.0" }, "devDependencies": { - "@types/node": "^18.11.9", - "jest": "^29.2.2", - "nock": "^13.2.9", - "standard": "^17.0.0", - "typescript": "^4.8.4" }, "scripts": { - "standard": "standard --fix", - "test": "standard && tsc lib/nano.d.ts && npm run jest", - "jest": "jest test/* --coverage --env node" + "test": "node --test ./test/*.test.js" }, "main": "./lib/nano.js", "types": "./lib/nano.d.ts", "engines": { - "node": ">=14" + "node": ">=18" }, "pre-commit": [ "test" diff --git a/test/attachment.destroy.test.js b/test/attachment.destroy.test.js index d390a93e..fba5c161 100644 --- a/test/attachment.destroy.test.js +++ b/test/attachment.destroy.test.js @@ -10,27 +10,25 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to destroy an attachment - DELETE /db/id/attname - db.attachment.destroy', async () => { // mocks const response = { ok: true, id: 'id', rev: '2-456' } - const scope = nock(COUCH_URL) - .delete('/db/id/logo.jpg?rev=1-123') - .reply(200, response) + mockPool.intercept({ + method: 'delete', + path: '/db/id/logo.jpg?rev=1-123' + }).reply(200, response, JSON_HEADERS) // test DELETE DELETE /db/id/attname const db = nano.db.use('db') const p = await db.attachment.destroy('id', 'logo.jpg', { rev: '1-123' }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 409 conflicts - DELETE /db/id/attname- db.attachment.destroy', async () => { @@ -39,29 +37,30 @@ test('should be able to handle 409 conflicts - DELETE /db/id/attname- db.attachm error: 'conflict', reason: 'Document update conflict.' } - const scope = nock(COUCH_URL) - .delete('/db/id/logo.jpg?rev=1-123') - .reply(409, response) + mockPool.intercept({ + method: 'delete', + path: '/db/id/logo.jpg?rev=1-123' + }).reply(409, response, JSON_HEADERS) // test DELETE /db/id/attname const db = nano.db.use('db') - await expect(db.attachment.destroy('id', 'logo.jpg', { rev: '1-123' })).rejects.toThrow('Document update conflict.') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.attachment.destroy('id', 'logo.jpg', { rev: '1-123' }), { message: 'Document update conflict.' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing doc id - db.attachment.destroy', async () => { const db = nano.db.use('db') - await expect(db.attachment.destroy()).rejects.toThrow('Invalid parameters') - await expect(db.attachment.destroy('id')).rejects.toThrow('Invalid parameters') - await expect(db.attachment.destroy('id', '')).rejects.toThrow('Invalid parameters') - await expect(db.attachment.destroy('', 'logo.jpg')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.attachment.destroy(), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.destroy('id'), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.destroy('id', ''), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.destroy('', 'logo.jpg'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.attachment.destroy', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.attachment.destroy(undefined, undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/attachment.get.test.js b/test/attachment.get.test.js index ef862e80..703e9523 100644 --- a/test/attachment.get.test.js +++ b/test/attachment.get.test.js @@ -10,55 +10,52 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const image = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64') -afterEach(() => { - nock.cleanAll() -}) - test('should be able to get an attachment - GET /db/id/attname - db.attachment.get', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/id/transparent.gif') - .reply(200, image, { 'content-type': 'image/gif' }) + mockPool + .intercept({ path: '/db/id/transparent.gif' }) + .reply(200, image, { headers: { 'content-type': 'image/gif' } }) // test GET /db/id/attname const db = nano.db.use('db') const p = await db.attachment.get('id', 'transparent.gif') - expect(p).toStrictEqual(image) - expect(scope.isDone()).toBe(true) + assert.equal(p.toString('base64'), image.toString('base64')) + mockAgent.assertNoPendingInterceptors() }) test('should be able to get an attachment with opts - GET /db/id/attname - db.attachment.get', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/id/transparent.gif?r=1') - .reply(200, image, { 'content-type': 'image/gif' }) + mockPool + .intercept({ path: '/db/id/transparent.gif?r=1' }) + .reply(200, image, { headers: { 'content-type': 'image/gif' } }) // test GET /db/id/attname const db = nano.db.use('db') const p = await db.attachment.get('id', 'transparent.gif', { r: 1 }) - expect(p).toStrictEqual(image) - expect(scope.isDone()).toBe(true) + assert.equal(p.toString('base64'), image.toString('base64')) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.attachment.get', async () => { const db = nano.db.use('db') - await expect(db.attachment.get()).rejects.toThrow('Invalid parameters') - await expect(db.attachment.get('id')).rejects.toThrow('Invalid parameters') - await expect(db.attachment.get('id', '')).rejects.toThrow('Invalid parameters') - await expect(db.attachment.get('', 'transparent.gif')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.attachment.get(), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.get('id'), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.get('id', ''), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.get('', 'transparent.gif'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.attachment.get', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.attachment.get(undefined, undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/attachment.getAsStream.test.js b/test/attachment.getAsStream.test.js index 6d80b3b4..b217bed0 100644 --- a/test/attachment.getAsStream.test.js +++ b/test/attachment.getAsStream.test.js @@ -10,21 +10,18 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const image = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64') -afterEach(() => { - nock.cleanAll() -}) - test('should be able to get an attachment as a stream - GET /db/id/attname - db.attachment.getAsStream', () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/id/transparent.gif') - .reply(200, image, { 'content-type': 'image/gif' }) + mockPool + .intercept({ path: '/db/id/transparent.gif' }) + .reply(200, image, { headers: { 'content-type': 'image/gif' } }) // test GET /db/id/attname return new Promise((resolve, reject) => { @@ -35,24 +32,26 @@ test('should be able to get an attachment as a stream - GET /db/id/attname - db. response = Buffer.concat([response, data]) }) .on('end', () => { - expect(response).toStrictEqual(image) - expect(scope.isDone()).toBe(true) + assert.equal(response.toString('base64'), image.toString('base64')) + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) -test('should emit an error when stream attachment does not exist - GET /db/id/attname - db.attachment.getAsStream', () => { +test('should emit an error when stream attachment does not exist - GET /db/id/attname - db.attachment.getAsStream', async () => { // test GET /db/id/attname - nock(COUCH_URL) - .get('/db/id/notexists.gif') - .reply(404, 'Object Not Found', { 'content-type': 'application/json' }) + const response = { error: 'not_found', reason: 'Document is missing attachment' } + mockPool + .intercept({ path: '/db/id/notexist.gif' }) + .reply(404, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') db.attachment.getAsStream('id', 'notexist.gif') .on('error', (e) => { - expect(e.statusCode).toStrictEqual(404) + console.log(e) + assert.equal(e.statusCode, 404) resolve() }) }) diff --git a/test/attachment.insert.test.js b/test/attachment.insert.test.js index 8619e2d9..898fec2d 100644 --- a/test/attachment.insert.test.js +++ b/test/attachment.insert.test.js @@ -10,39 +10,34 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const fs = require('fs') const image = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64') -const image2 = Buffer.from(''.concat( - 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAsV', - 'BMVEUAAAD////////////////////////5ur3rEBn////////////////wDBL/', - 'AADuBAe9EB3IEBz/7+//X1/qBQn2AgP/f3/ilpzsDxfpChDtDhXeCA76AQH/v7', - '/84eLyWV/uc3bJPEf/Dw/uw8bRWmP1h4zxSlD6YGHuQ0f6g4XyQkXvCA36MDH6', - 'wMH/z8/yAwX64ODeh47BHiv/Ly/20dLQLTj98PDXWmP/Pz//39/wGyJ7Iy9JAA', - 'AADHRSTlMAbw8vf08/bz+Pv19jK/W3AAAAg0lEQVR4Xp3LRQ4DQRBD0QqTm4Y5', - 'zMxw/4OleiJlHeUtv2X6RbNO1Uqj9g0RMCuQO0vBIg4vMFeOpCWIWmDOw82fZx', - 'vaND1c8OG4vrdOqD8YwgpDYDxRgkSm5rwu0nQVBJuMg++pLXZyr5jnc1BaH4GT', - 'LvEliY253nA3pVhQqdPt0f/erJkMGMB8xucAAAAASUVORK5CYII='), 'base64') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to insert document attachment - PUT /db/docname/attachment - db.attachment.insert', async () => { // mocks const response = { ok: true, id: 'docname', rev: '2-456' } - const scope = nock(COUCH_URL, { reqheaders: { 'content-type': 'image/gif' } }) - .put('/db/docname/transparent.gif?rev=1-150', image) - .reply(200, response) + mockPool.intercept({ + method: 'put', + path: '/db/docname/transparent.gif?rev=1-150', + body: (value) => { + const buff = Buffer.from(value) + return buff.equals(image) + }, + headers: { + 'content-type': 'image/gif' + } + }).reply(200, response, JSON_HEADERS) // test PUT /db/docname/attachment const db = nano.db.use('db') const p = await db.attachment.insert('docname', 'transparent.gif', image, 'image/gif', { rev: '1-150' }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.attachment.insert', async () => { @@ -51,29 +46,37 @@ test('should be able to handle 404 - db.attachment.insert', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL, { reqheaders: { 'content-type': 'image/gif' } }) - .put('/db/docname/transparent.gif?rev=1-150', image) - .reply(404, response) + mockPool.intercept({ + method: 'put', + path: '/db/docname/transparent.gif?rev=1-150', + body: (value) => { + const buff = Buffer.from(value) + return buff.equals(image) + }, + headers: { + 'content-type': 'image/gif' + } + }).reply(404, response, JSON_HEADERS) // test PUT /db/docname/attachment const db = nano.db.use('db') - await expect(db.attachment.insert('docname', 'transparent.gif', image, 'image/gif', { rev: '1-150' })).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.attachment.insert('docname', 'transparent.gif', image, 'image/gif', { rev: '1-150' }), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.attachment.insert', async () => { const db = nano.db.use('db') - await expect(db.attachment.insert()).rejects.toThrow('Invalid parameters') - await expect(db.attachment.insert('docname')).rejects.toThrow('Invalid parameters') - await expect(db.attachment.insert('docname', 't.gif')).rejects.toThrow('Invalid parameters') - await expect(db.attachment.insert('docname', 't.gif', image)).rejects.toThrow('Invalid parameters') + await assert.rejects(db.attachment.insert(), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.insert('docname'), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.insert('docname', 't.gif'), { message: 'Invalid parameters' }) + await assert.rejects(db.attachment.insert('docname', 't.gif', image), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.attachment.insert', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.attachment.insert(undefined, undefined, undefined, undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -82,24 +85,38 @@ test('should detect missing parameters (callback) - db.attachment.insert', () => test('should be able to insert document attachment as stream - PUT /db/docname/attachment - db.attachment.insert', async () => { // mocks const response = { ok: true, id: 'docname', rev: '2-456' } - const scope = nock(COUCH_URL, { reqheaders: { 'content-type': 'image/jpg' } }) - .put('/db/docname/logo.jpg?rev=1-150', image2) - .reply(200, response) + mockPool.intercept({ + method: 'put', + path: '/db/docname/logo.jpg?rev=1-150', + body: (value) => { + return true + }, + headers: { + 'content-type': 'image/jpg' + } + }).reply(200, response, JSON_HEADERS) // test PUT /db/docname/attachment const rs = fs.createReadStream('./test/logo.jpg') const db = nano.db.use('db') const reply = await db.attachment.insert('docname', 'logo.jpg', rs, 'image/jpg', { rev: '1-150' }) - expect(reply).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(reply, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert document attachment as stream with circular reference - PUT /db/docname/attachment - db.attachment.insert', async () => { // mocks const response = { ok: true, id: 'docname', rev: '2-456' } - const scope = nock(COUCH_URL, { reqheaders: { 'content-type': 'image/jpg' } }) - .put('/db/docname/logo2.jpg?rev=1-150', image2) - .reply(200, response) + mockPool.intercept({ + method: 'put', + path: '/db/docname/logo2.jpg?rev=1-150', + body: (value) => { + return true + }, + headers: { + 'content-type': 'image/jpg' + } + }).reply(200, response, JSON_HEADERS) // test PUT /db/docname/attachment const rs = fs.createReadStream('./test/logo.jpg') @@ -107,6 +124,6 @@ test('should be able to insert document attachment as stream with circular refer rs.test = rs const db = nano.db.use('db') const reply = await db.attachment.insert('docname', 'logo2.jpg', rs, 'image/jpg', { rev: '1-150' }) - expect(reply).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(reply, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/database.changes.test.js b/test/database.changes.test.js deleted file mode 100644 index 3b791577..00000000 --- a/test/database.changes.test.js +++ /dev/null @@ -1,103 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' -const nano = Nano(COUCH_URL) -const nock = require('nock') -const response = { - results: [ - { - seq: '1-nC1J', - id: 'c42ddf1272c7d05b2dc45b6962000b10', - changes: [ - { - rev: '1-23202479633c2b380f79507a776743d5' - } - ] - } - ], - last_seq: '1-C1J', - pending: 0 -} -const errResponse = { - error: 'not_found', - reason: 'Database does not exist.' -} - -afterEach(() => { - nock.cleanAll() -}) - -test('should be able to fetch the changes - GET /db/_changes - nano.db.changes', async () => { - // mocks - const scope = nock(COUCH_URL) - .get('/db/_changes') - .reply(200, response) - - // test GET /db/_changes - const p = await nano.db.changes('db') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) -}) - -test('should be able to fetch the changes with opts - GET /db/_changes - nano.db.changes', async () => { - // mocks - const opts = { include_docs: true, feed: 'continuous' } - const scope = nock(COUCH_URL) - .get('/db/_changes') - .query(opts) - .reply(200, response) - - // test GET /db/_changes - const p = await nano.db.changes('db', opts) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) -}) - -test('should be able to handle a missing database - GET /db/_changes - nano.db.changes', async () => { - // mocks - const scope = nock(COUCH_URL) - .get('/db/_changes') - .reply(404, errResponse) - - // test GET /db/_changes - await expect(nano.db.changes('db')).rejects.toThrow('Database does not exist') - expect(scope.isDone()).toBe(true) -}) - -test('should not attempt invalid parameters - nano.db.changes', async () => { - await expect(nano.db.changes()).rejects.toThrowError('Invalid parameters') - await expect(nano.db.changes('')).rejects.toThrowError('Invalid parameters') -}) - -test('should detect missing parameters (callback) - nano.db.changes', () => { - return new Promise((resolve, reject) => { - nano.db.changes(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() - resolve() - }) - }) -}) - -test('should be able to fetch the changes from db.changes - GET /db/_changes - db.changes', async () => { - // mocks - const scope = nock(COUCH_URL) - .get('/db/_changes') - .reply(200, response) - - // test GET /db/_changes - const db = nano.db.use('db') - const p = await db.changes() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) -}) diff --git a/test/database.changesAsStream.test.js b/test/database.changesAsStream.test.js index c307cc53..149f3af8 100644 --- a/test/database.changesAsStream.test.js +++ b/test/database.changesAsStream.test.js @@ -10,10 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { results: [ { @@ -30,53 +31,48 @@ const response = { pending: 0 } -afterEach(() => { - nock.cleanAll() -}) - -test('should get a streamed list of changes - GET /_changes - nano.db.changesAsStream', () => { +test('should get a streamed list of changes - GET /_changes - nano.db.changesAsStream', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_changes') - .reply(200, response) + mockPool + .intercept({ path: '/db/_changes' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_changes const db = nano.db.use('db') const s = db.changesAsStream() - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) -test('should get a streamed list of changes with opts - GET /_changes - nano.db.changesAsStream', () => { +test('should get a streamed list of changes with opts - GET /_changes - nano.db.changesAsStream', async () => { // mocks const opts = { include_docs: true } - const scope = nock(COUCH_URL) - .get('/db/_changes') - .query(opts) - .reply(200, response) + mockPool + .intercept({ path: '/db/_changes?include_docs=true' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_changes const db = nano.db.use('db') const s = db.changesAsStream(opts) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/database.compact.test.js b/test/database.compact.test.js index 83c5c915..0fb5a8be 100644 --- a/test/database.compact.test.js +++ b/test/database.compact.test.js @@ -10,49 +10,46 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { ok: true } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to send compaction request - POST /db/_compact - nano.db.compact', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/db/_compact') - .reply(200, response) + mockPool + .intercept({ method: 'post', path: '/db/_compact' }) + .reply(200, response, JSON_HEADERS) // test POST /db/_compact const p = await nano.db.compact('db') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to send compaction request with design doc - POST /db/_compact/ddoc - nano.db.compact', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/db/_compact/ddoc') - .reply(200, response) + mockPool + .intercept({ method: 'post', path: '/db/_compact/ddoc' }) + .reply(200, response, JSON_HEADERS) // test POST /db/_compact/ddoc const p = await nano.db.compact('db', 'ddoc') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt compact with invalid parameters - nano.db.compact', async () => { - await expect(nano.db.compact('')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.compact()).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.compact(''), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.compact(), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.compact', () => { return new Promise((resolve, reject) => { nano.db.compact(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -60,26 +57,26 @@ test('should detect missing parameters (callback) - nano.db.compact', () => { test('should be able to send compaction request from db.compact - POST /db/_compact - db.compact', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/db/_compact') - .reply(200, response) + mockPool + .intercept({ method: 'post', path: '/db/_compact' }) + .reply(200, response, JSON_HEADERS) // test POST /db/_compact const db = nano.db.use('db') const p = await db.compact() - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to send compaction request with design doc from db.view.compact - POST /db/_compact/ddoc - db.view.compact', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/db/_compact/ddoc') - .reply(200, response) + mockPool + .intercept({ method: 'post', path: '/db/_compact/ddoc' }) + .reply(200, response, JSON_HEADERS) // test POST /db/_compact/ddoc const db = nano.db.use('db') const p = await db.view.compact('ddoc') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/database.create.test.js b/test/database.create.test.js index e0717dc2..e71d103a 100644 --- a/test/database.create.test.js +++ b/test/database.create.test.js @@ -10,66 +10,64 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { ok: true } -afterEach(() => { - nock.cleanAll() -}) - test('should create a database - PUT /db - nano.db.create', async () => { // mocks - const scope = nock(COUCH_URL) - .put('/db') - .reply(200, response) + mockPool + .intercept({ method: 'put', path: '/db' }) + .reply(200, response, JSON_HEADERS) // test GET /db const p = await nano.db.create('db') - expect(typeof p).toBe('object') - expect(p.ok).toBe(true) - expect(scope.isDone()).toBe(true) + assert.equal(typeof p, 'object') + assert.equal(p.ok, true) + mockAgent.assertNoPendingInterceptors() }) test('should create a database with parameters - PUT /db?partitioned=true - nano.db.create', async () => { // mocks - const scope = nock(COUCH_URL) - .put('/db') - .query({ partitioned: 'true', q: '1' }) - .reply(200, response) + mockPool.intercept({ + method: 'put', + path: '/db?partitioned=true&q=1' + }).reply(200, response, JSON_HEADERS) // test GET /db const p = await nano.db.create('db', { partitioned: true, q: 1 }) - expect(typeof p).toBe('object') - expect(p.ok).toBe(true) - expect(scope.isDone()).toBe(true) + assert.equal(typeof p, 'object') + assert.equal(p.ok, true) + mockAgent.assertNoPendingInterceptors() }) test('should handle pre-existing database - PUT /db - nano.db.create', async () => { // mocks - const scope = nock(COUCH_URL) - .put('/db') - .reply(412, { - error: 'file_exists', - reason: 'The database could not be created, the file already exists.' - }) + mockPool.intercept({ + method: 'put', + path: '/db' + }).reply(412, { + error: 'file_exists', + reason: 'The database could not be created, the file already exists.' + }, JSON_HEADERS) // test PUT /db - await expect(nano.db.create('db')).rejects.toThrow('The database could not be created') - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.db.create('db'), { message: 'The database could not be created, the file already exists.' }) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt to create database with invalid parameters - nano.db.create', async () => { - await expect(nano.db.create()).rejects.toThrowError('Invalid parameters') - await expect(nano.db.create('')).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.create(), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.create(''), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.create', () => { return new Promise((resolve, reject) => { nano.db.create(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/database.destroy.test.js b/test/database.destroy.test.js index 3e1fdd0e..bb5ac2b4 100644 --- a/test/database.destroy.test.js +++ b/test/database.destroy.test.js @@ -10,52 +10,48 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') -const response = { ok: true } -afterEach(() => { - nock.cleanAll() -}) +const response = { ok: true } test('should destroy a database - DELETE /db - nano.db.destroy', async () => { // mocks - const scope = nock(COUCH_URL) - .delete('/db') - .reply(200, response) + mockPool + .intercept({ method: 'delete', path: '/db' }) + .reply(200, response, JSON_HEADERS) // test DELETE /db const p = await nano.db.destroy('db') - expect(typeof p).toBe('object') - expect(p.ok).toBe(true) - expect(scope.isDone()).toBe(true) + assert.equal(typeof p, 'object') + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should handle non-existant database - DELETE /db - nano.db.destroy', async () => { // mocks - const scope = nock(COUCH_URL) - .delete('/db') - .reply(404, { - error: 'not_found', - reason: 'Database does not exist.' - }) + mockPool.intercept({ method: 'delete', path: '/db' }).reply(404, { + error: 'not_found', + reason: 'Database does not exist.' + }, JSON_HEADERS) // test DELETE /db - await expect(nano.db.destroy('db')).rejects.toThrow('Database does not exist') - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.db.destroy('db'), 'Database does not exist') + mockAgent.assertNoPendingInterceptors() }) test('should not attempt to destroy database with empty database name - nano.db.destroy', async () => { - await expect(nano.db.destroy()).rejects.toThrowError('Invalid parameters') - await expect(nano.db.destroy('')).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.destroy(), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.destroy(''), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.destroy', () => { return new Promise((resolve, reject) => { nano.db.destroy(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/database.get.test.js b/test/database.get.test.js index a63c2ab4..5775deab 100644 --- a/test/database.get.test.js +++ b/test/database.get.test.js @@ -10,10 +10,12 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') + const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { db_name: 'db', purge_seq: '0-8KhNZEiqhyjKAgBm5Rxs', @@ -41,62 +43,56 @@ const response = { instance_start_time: '0' } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to fetch the database info - GET /db - nano.db.get', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db') - .reply(200, response) + mockPool + .intercept({ path: '/db' }) + .reply(200, response, JSON_HEADERS) // test GET /db const p = await nano.db.get('db') - expect(typeof p).toBe('object') - expect(p.doc_count).toBe(0) - expect(p.db_name).toBe('db') - expect(scope.isDone()).toBe(true) + assert.strictEqual(typeof p, 'object') + assert.strictEqual(p.doc_count, 0) + assert.strictEqual(p.db_name, 'db') + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch the database info - GET /db - db.info', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db') - .reply(200, response) + mockPool + .intercept({ path: '/db' }) + .reply(200, response, JSON_HEADERS) // test GET /db const db = nano.db.use('db') const p = await db.info() - expect(typeof p).toBe('object') - expect(p.doc_count).toBe(0) - expect(p.db_name).toBe('db') - expect(scope.isDone()).toBe(true) + assert.strictEqual(typeof p, 'object') + assert.strictEqual(p.doc_count, 0) + assert.strictEqual(p.db_name, 'db') + mockAgent.assertNoPendingInterceptors() }) test('should handle missing database - GET /db - nano.db.get', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db') - .reply(404, { - error: 'not_found', - reason: 'Database does not exist.' - }) + mockPool.intercept({ path: '/db' }).reply(404, { + error: 'not_found', + reason: 'Database does not exist.' + }, JSON_HEADERS) // test GET /db - await expect(nano.db.get('db')).rejects.toThrow('Database does not exist') - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.db.get('db'), { message: 'Database does not exist.' }) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt info fetch with missing parameters - nano.db.get', async () => { - await expect(nano.db.get()).rejects.toThrowError('Invalid parameters') - await expect(nano.db.get('')).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.get(), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.get(''), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.get', () => { return new Promise((resolve, reject) => { nano.db.get(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/database.list.test.js b/test/database.list.test.js index abe6e102..6c670da2 100644 --- a/test/database.list.test.js +++ b/test/database.list.test.js @@ -10,24 +10,22 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = ['rita', 'sue', 'bob'] -afterEach(() => { - nock.cleanAll() -}) - test('should be to get list of databases - GET /_all_dbs - nano.db.list', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_all_dbs') - .reply(200, response) + mockPool + .intercept({ path: '/_all_dbs' }) + .reply(200, response, JSON_HEADERS) // test GET /_all_dbs const p = await nano.db.list() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(typeof p, 'object') + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/database.listAsStream.test.js b/test/database.listAsStream.test.js index d10f53b8..f8525d53 100644 --- a/test/database.listAsStream.test.js +++ b/test/database.listAsStream.test.js @@ -10,33 +10,30 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = ['rita', 'sue', 'bob'] -afterEach(() => { - nock.cleanAll() -}) - -test('should get a streamed list of databases - GET /_all_dbs - nano.db.listAsStream', () => { +test('should get a streamed list of databases - GET /_all_dbs - nano.db.listAsStream', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_all_dbs') - .reply(200, response) + mockPool + .intercept({ path: '/_all_dbs' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /_all_dbs const s = nano.db.listAsStream() - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/database.replicate.test.js b/test/database.replicate.test.js index e15095d7..55859467 100644 --- a/test/database.replicate.test.js +++ b/test/database.replicate.test.js @@ -10,10 +10,12 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') + const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { history: [], ok: true, @@ -22,34 +24,34 @@ const response = { source_last_seq: 28 } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to send replication request with local database names - POST /_replicate - nano.db.replicate', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/_replicate', { source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicate', + body: JSON.stringify({ source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicate const p = await nano.db.replicate('source', 'target') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to send replication request with URLs - POST /_replicate - nano.db.replicate', async () => { // mocks const source = 'http://mydomain1.com/source' const target = 'https://mydomain2.com/target' - const scope = nock(COUCH_URL) - .post('/_replicate', { source, target }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicate', + body: JSON.stringify({ source, target }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicate const p = await nano.db.replicate(source, target) - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to supply additional parameters - POST /_replicate - nano.db.replicate', async () => { @@ -57,26 +59,28 @@ test('should be able to supply additional parameters - POST /_replicate - nano.d const source = 'http://mydomain1.com/source' const target = 'https://mydomain2.com/target' const opts = { filter: 'ddoc/func', continuous: true } - const scope = nock(COUCH_URL) - .post('/_replicate', Object.assign(opts, { source, target })) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicate', + body: JSON.stringify(Object.assign(opts, { source, target })) + }).reply(200, response, JSON_HEADERS) // test POST /_replicate const p = await nano.db.replicate(source, target, opts) - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt compact invalid parameters - nano.db.replicate', async () => { - await expect(nano.db.replicate('')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replicate(undefined, 'target')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replicate('', 'target')).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.replicate(''), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replicate(undefined, 'target'), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replicate('', 'target'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.replicate', () => { return new Promise((resolve, reject) => { nano.db.replicate(undefined, undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -84,13 +88,15 @@ test('should detect missing parameters (callback) - nano.db.replicate', () => { test('should be replicate from db.replicate - POST /_replicate - db.replicate', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/_replicate', { source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicate', + body: JSON.stringify({ source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicate const db = nano.db.use('source') const p = await db.replicate('target') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/database.replication.disable.test.js b/test/database.replication.disable.test.js index 273d734d..0baae9ac 100644 --- a/test/database.replication.disable.test.js +++ b/test/database.replication.disable.test.js @@ -10,55 +10,53 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') + const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { ok: true, id: 'rep1', rev: '2-123' } const errResponse = { error: 'not_found', reason: 'missing' } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to delete a replication - DELETE /_replicator/id - nano.db.replication.disable', async () => { // mocks - const scope = nock(COUCH_URL) - .delete('/_replicator/rep1') - .query({ rev: '1-456' }) - .reply(200, response) + mockPool.intercept({ + method: 'delete', + path: '/_replicator/rep1?rev=1-456' + }).reply(200, response, JSON_HEADERS) // test DELETE /_replicator/id const p = await nano.db.replication.disable('rep1', '1-456') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle a 404 - DELETE /_replicator/id - nano.db.replication.disable', async () => { // mocks - const scope = nock(COUCH_URL) - .delete('/_replicator/rep1') - .query({ rev: '1-456' }) - .reply(404, errResponse) + mockPool.intercept({ + method: 'delete', + path: '/_replicator/rep1?rev=1-456' + }).reply(404, errResponse, JSON_HEADERS) // test DELETE /_replicator/id - await expect(nano.db.replication.disable('rep1', '1-456')).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.db.replication.disable('rep1', '1-456'), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should not to try to disable with invalid parameters - nano.db.replication.disable', async () => { - await expect(nano.db.replication.disable(undefined, '1-456')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replication.disable('', '1-456')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replication.disable('rep1')).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.replication.disable(undefined, '1-456'), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replication.disable('', '1-456'), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replication.disable('rep1'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.replication.disable', () => { return new Promise((resolve, reject) => { nano.db.replication.disable(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -66,14 +64,14 @@ test('should detect missing parameters (callback) - nano.db.replication.disable' test('should be able to delete a replication from db.replication.disable - DELETE /_replicator/id - db.replication.disable', async () => { // mocks - const scope = nock(COUCH_URL) - .delete('/_replicator/rep1') - .query({ rev: '1-456' }) - .reply(200, response) + mockPool.intercept({ + method: 'delete', + path: '/_replicator/rep1?rev=1-456' + }).reply(200, response, JSON_HEADERS) // test DELETE /_replicator/id const db = nano.db.use('db') const p = await db.replication.disable('rep1', '1-456') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/database.replication.enable.test.js b/test/database.replication.enable.test.js index e887a3fa..eead7933 100644 --- a/test/database.replication.enable.test.js +++ b/test/database.replication.enable.test.js @@ -10,54 +10,58 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') + const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { ok: true, id: 'abc', rev: '1-123' } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to send replication request with local database names - POST /_replicator - nano.db.replication.enable', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/_replicator', { source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicator', + body: JSON.stringify({ source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicator const p = await nano.db.replication.enable('source', 'target') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to send replication request with URLs - POST /_replicator - nano.db.replication.enable', async () => { // mocks const source = 'http://mydomain1.com/source' const target = 'https://mydomain2.com/target' - const scope = nock(COUCH_URL) - .post('/_replicator', { source, target }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicator', + body: JSON.stringify({ source, target }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicator const p = await nano.db.replication.enable(source, target) - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to send replication request with objects - POST /_replicator - nano.db.replication.enable', async () => { // mocks const source = { config: { url: 'http://mydomain1.com', db: 'source' } } const target = { config: { url: 'https://mydomain2.com', db: 'target' } } - const scope = nock(COUCH_URL) - .post('/_replicator', { source: 'http://mydomain1.com/source', target: 'https://mydomain2.com/target' }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicator', + body: JSON.stringify({ source: 'http://mydomain1.com/source', target: 'https://mydomain2.com/target' }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicator const p = await nano.db.replication.enable(source, target) - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to supply additional parameters - POST /_replicator - nano.db.replication.enable', async () => { @@ -65,27 +69,29 @@ test('should be able to supply additional parameters - POST /_replicator - nano. const source = 'http://mydomain1.com/source' const target = 'https://mydomain2.com/target' const opts = { filter: 'ddoc/func', continuous: true } - const scope = nock(COUCH_URL) - .post('/_replicator', Object.assign(opts, { source, target })) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicator', + body: JSON.stringify(Object.assign(opts, { source, target })) + }).reply(200, response, JSON_HEADERS) // test POST /_replicator const p = await nano.db.replication.enable(source, target, opts) - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt compact with invalid parameters - nano.db.replication.enable', async () => { - await expect(nano.db.replication.enable(undefined, 'target')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replication.enable()).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replication.enable('source')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replication.enable('source', '')).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.replication.enable(undefined, 'target'), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replication.enable(), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replication.enable('source'), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replication.enable('source', ''), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.replication.enable', () => { return new Promise((resolve, reject) => { nano.db.replication.enable(undefined, undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -93,13 +99,15 @@ test('should detect missing parameters (callback) - nano.db.replication.enable', test('should be able to send replication request db.replication.enable - POST /_replicator - db.replication.enable', async () => { // mocks - const scope = nock(COUCH_URL) - .post('/_replicator', { source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) - .reply(200, response) + mockPool.intercept({ + method: 'post', + path: '/_replicator', + body: JSON.stringify({ source: COUCH_URL + '/source', target: COUCH_URL + '/target' }) + }).reply(200, response, JSON_HEADERS) // test POST /_replicator const db = nano.db.use('source') const p = await db.replication.enable('target') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/database.replication.query.test.js b/test/database.replication.query.test.js index 26b8fedf..bbbc913d 100644 --- a/test/database.replication.query.test.js +++ b/test/database.replication.query.test.js @@ -10,15 +10,16 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const response = { _id: 'rep1', _rev: '2-05a9e090e2bb0977c06b870c870153c5', - source: 'http://localhost:5984/cities', - target: 'http://localhost:5984/cities2', + source: 'http://127.0.0.1:5984/cities', + target: 'http://127.0.0.1:5984/cities2', create_target: true, continuous: false, owner: 'admin', @@ -40,56 +41,51 @@ const errResponse = { reason: 'missing' } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to query a replication - GET /_replicator/id - nano.db.replication.query', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_replicator/rep1') - .reply(200, response) + mockPool + .intercept({ path: '/_replicator/rep1' }) + .reply(200, response, JSON_HEADERS) // test GET /_replicator/id const p = await nano.db.replication.query('rep1') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to query a replication with opts - GET /_replicator/id?confilicts=true - nano.db.replication.query', async () => { // mocks const opts = { conflicts: true } - const scope = nock(COUCH_URL) - .get('/_replicator/rep1') - .query(opts) - .reply(200, response) + mockPool.intercept({ + path: '/_replicator/rep1?conflicts=true' + }).reply(200, response, JSON_HEADERS) // test GET /_replicator/id const p = await nano.db.replication.query('rep1', opts) - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to query a replication and handle 404 - GET /_replicator/id - nano.db.replication.query', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_replicator/rep1') - .reply(404, errResponse) + mockPool.intercept({ + path: '/_replicator/rep1' + }).reply(404, errResponse, JSON_HEADERS) // test GET /_replicator/id - await expect(nano.db.replication.query('rep1')).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.db.replication.query('rep1'), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt info fetch with invalid parameters - nano.db.replication.query', async () => { - await expect(nano.db.replication.query('')).rejects.toThrowError('Invalid parameters') - await expect(nano.db.replication.query()).rejects.toThrowError('Invalid parameters') + await assert.rejects(nano.db.replication.query(''), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.replication.query(), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.replication.query', () => { return new Promise((resolve, reject) => { nano.db.replication.query(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -97,13 +93,13 @@ test('should detect missing parameters (callback) - nano.db.replication.query', test('should be able to query a replication from db.replication.quey - GET /_replicator/id - db.replication.query', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_replicator/rep1') - .reply(200, response) + mockPool.intercept({ + path: '/_replicator/rep1' + }).reply(200, response, JSON_HEADERS) // test GET /_replicator/id const db = nano.db.use('db') const p = await db.replication.query('rep1') - expect(p).toEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/design.atomic.test.js b/test/design.atomic.test.js index 8087edd5..bcc0d891 100644 --- a/test/design.atomic.test.js +++ b/test/design.atomic.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to use an update function - PUT /db/_design/ddoc/_update/updatename/docid - db.atomic', async () => { const updateFunction = function (doc, req) { @@ -29,15 +26,18 @@ test('should be able to use an update function - PUT /db/_design/ddoc/_update/up const response = updateFunction({})[1].json // mocks - const scope = nock(COUCH_URL) - .put('/db/_design/ddoc/_update/updatename/docid') - .reply(200, response) + mockPool + .intercept({ + method: 'put', + path: '/db/_design/ddoc/_update/updatename/docid' + }) + .reply(200, response, JSON_HEADERS) // test PUT /db/_design/ddoc/_update/updatename/docid const db = nano.db.use('db') const p = await db.atomic('ddoc', 'updatename', 'docid') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to use an update function with body - PUT /db/_design/ddoc/_update/updatename/docid - db.atomic', async () => { @@ -51,15 +51,19 @@ test('should be able to use an update function with body - PUT /db/_design/ddoc/ const response = updateFunction({})[1].json // mocks - const scope = nock(COUCH_URL) - .put('/db/_design/ddoc/_update/updatename/docid', body) - .reply(200, response) + mockPool + .intercept({ + method: 'put', + path: '/db/_design/ddoc/_update/updatename/docid', + body: JSON.stringify(body) + }) + .reply(200, response, JSON_HEADERS) // test PUT /db/_design/ddoc/_update/updatename/docid const db = nano.db.use('db') const p = await db.atomic('ddoc', 'updatename', 'docid', body) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.atomic', async () => { @@ -69,39 +73,43 @@ test('should be able to handle 404 - db.atomic', async () => { reason: 'missing' } const body = { a: 1, b: 2 } - const scope = nock(COUCH_URL) - .put('/db/_design/ddoc/_update/updatename/docid', body) - .reply(404, response) + mockPool + .intercept({ + method: 'put', + path: '/db/_design/ddoc/_update/updatename/docid', + body: JSON.stringify(body) + }) + .reply(404, response, JSON_HEADERS) // test PUT /db/_design/ddoc/_update/updatename/docid const db = nano.db.use('db') - await expect(db.atomic('ddoc', 'updatename', 'docid', body)).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.atomic('ddoc', 'updatename', 'docid', body), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.update', async () => { const db = nano.db.use('db') - await expect(db.atomic()).rejects.toThrow('Invalid parameters') - await expect(db.atomic('ddoc')).rejects.toThrow('Invalid parameters') - await expect(db.atomic('ddoc', 'updatename')).rejects.toThrow('Invalid parameters') - await expect(db.atomic('', 'updatename', 'docid')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.atomic(), { message: 'Invalid parameters' }) + await assert.rejects(db.atomic('ddoc'), { message: 'Invalid parameters' }) + await assert.rejects(db.atomic('ddoc', 'updatename'), { message: 'Invalid parameters' }) + await assert.rejects(db.atomic('', 'updatename', 'docid'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.update', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.atomic('', '', '', {}, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) }) -test('should detect missing parameters (callback no body) - db.update', () => { +test('should detect missing parameters (callback no body) - db.update', async () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.atomic('', '', '', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/design.createIndex.test.js b/test/design.createIndex.test.js index a26e1ab6..b0c7dfea 100644 --- a/test/design.createIndex.test.js +++ b/test/design.createIndex.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to create an index - POST /db/_index - db.createIndex', async () => { // mocks @@ -34,15 +31,19 @@ test('should be able to create an index - POST /db/_index - db.createIndex', asy id: '_design/a5f4711fc9448864a13c81dc71e660b524d7410c', name: 'foo-index' } - const scope = nock(COUCH_URL) - .post('/db/_index', indexDef) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_index', + body: JSON.stringify(indexDef) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_index const db = nano.db.use('db') const p = await db.createIndex(indexDef) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should handle 404 - POST /db/_index - db.createIndex', async () => { @@ -59,27 +60,31 @@ test('should handle 404 - POST /db/_index - db.createIndex', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .post('/db/_index', indexDef) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_index', + body: JSON.stringify(indexDef) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_index const db = nano.db.use('db') - await expect(db.createIndex(indexDef)).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.createIndex(indexDef), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing index - db.createIndex', async () => { const db = nano.db.use('db') - await expect(db.createIndex()).rejects.toThrow('Invalid parameters') - await expect(db.createIndex('myindex')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.createIndex(), { message: 'Invalid parameters' }) + await assert.rejects(db.createIndex('myindex'), { message: 'Invalid parameters' }) }) test('should detect missing index (callback) - db.createIndex', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.createIndex('', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/design.find.test.js b/test/design.find.test.js index 354f9060..1df757aa 100644 --- a/test/design.find.test.js +++ b/test/design.find.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to query an index - POST /db/_find - db.find', async () => { // mocks @@ -38,15 +35,19 @@ test('should be able to query an index - POST /db/_find - db.find', async () => { name: 'Susan', date: '2019-01-03', orderid: '8523' } ] } - const scope = nock(COUCH_URL) - .post('/db/_find', query) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_find', + body: JSON.stringify(query) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_find const db = nano.db.use('db') const p = await db.find(query) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should handle 404 - POST /db/_find - db.find', async () => { @@ -60,27 +61,31 @@ test('should handle 404 - POST /db/_find - db.find', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .post('/db/_find', query) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_find', + body: JSON.stringify(query) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_find const db = nano.db.use('db') - await expect(db.find(query)).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.find(query), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing query - db.find', async () => { const db = nano.db.use('db') - await expect(db.find()).rejects.toThrow('Invalid parameters') - await expect(db.find('susan')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.find(), { message: 'Invalid parameters' }) + await assert.rejects(db.find('susan'), { message: 'Invalid parameters' }) }) test('should detect missing query (callback) - db.find', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.find('', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/design.findAsStream.test.js b/test/design.findAsStream.test.js index cb1aca8d..3a317ce8 100644 --- a/test/design.findAsStream.test.js +++ b/test/design.findAsStream.test.js @@ -10,16 +10,13 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') -afterEach(() => { - nock.cleanAll() -}) - -test('should be able to query an index as a stream- POST /db/_find - db.findAsStream', () => { +test('should be able to query an index as a stream- POST /db/_find - db.findAsStream', async () => { // mocks const query = { selector: { @@ -38,22 +35,26 @@ test('should be able to query an index as a stream- POST /db/_find - db.findAsSt { name: 'Susan', date: '2019-01-03', orderid: '8523' } ] } - const scope = nock(COUCH_URL) - .post('/db/_find', query) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_find', + body: JSON.stringify(query) + }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test POST /db/_find const db = nano.db.use('db') const s = db.findAsStream(query) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/design.search.test.js b/test/design.search.test.js index 1cc22311..a7568866 100644 --- a/test/design.search.test.js +++ b/test/design.search.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to access a search index - POST /db/_design/ddoc/_search/searchname - db.search', async () => { // mocks @@ -29,15 +26,19 @@ test('should be able to access a search index - POST /db/_design/ddoc/_search/se ] } const params = { q: '*:*' } - const scope = nock(COUCH_URL) - .post('/db/_design/ddoc/_search/searchname', params) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_design/ddoc/_search/searchname', + body: JSON.stringify(params) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_design/ddoc/_search/searchnameGET /db const db = nano.db.use('db') const p = await db.search('ddoc', 'searchname', params) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.search', async () => { @@ -47,29 +48,33 @@ test('should be able to handle 404 - db.search', async () => { reason: 'missing' } const params = { q: '*:*' } - const scope = nock(COUCH_URL) - .post('/db/_design/ddoc/_search/searchname', params) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_design/ddoc/_search/searchname', + body: JSON.stringify(params) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_design/ddoc/_search/searchname const db = nano.db.use('db') - await expect(db.search('ddoc', 'searchname', params)).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.search('ddoc', 'searchname', params), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.search', async () => { const db = nano.db.use('db') - await expect(db.search()).rejects.toThrow('Invalid parameters') - await expect(db.search('susan')).rejects.toThrow('Invalid parameters') - await expect(db.search('susan', '')).rejects.toThrow('Invalid parameters') - await expect(db.search('', 'susan')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.search(), { message: 'Invalid parameters' }) + await assert.rejects(db.search('susan'), { message: 'Invalid parameters' }) + await assert.rejects(db.search('susan', ''), { message: 'Invalid parameters' }) + await assert.rejects(db.search('', 'susan'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.search', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.search('', '', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/design.searchAsStream.test.js b/test/design.searchAsStream.test.js index b2c4af20..0d1348f9 100644 --- a/test/design.searchAsStream.test.js +++ b/test/design.searchAsStream.test.js @@ -10,16 +10,13 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') -afterEach(() => { - nock.cleanAll() -}) - -test('should be able to access a search index as a stream - POST /db/_design/ddoc/_search/searchname - db.searchAsStream', () => { +test('should be able to access a search index as a stream - POST /db/_design/ddoc/_search/searchname - db.searchAsStream', async () => { // mocks const response = { total_rows: 100000, @@ -29,21 +26,25 @@ test('should be able to access a search index as a stream - POST /db/_design/ddo ] } const params = { q: '*:*' } - const scope = nock(COUCH_URL) - .post('/db/_design/ddoc/_search/searchname', params) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_design/ddoc/_search/searchname', + body: JSON.stringify(params) + }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') const s = db.searchAsStream('ddoc', 'searchname', params) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/design.show.test.js b/test/design.show.test.js index 92ad4c99..eca31e6f 100644 --- a/test/design.show.test.js +++ b/test/design.show.test.js @@ -10,29 +10,26 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to use a show function - GET /db/_design/ddoc/_show/showname/docid - db.show', async () => { const showFunction = function (doc, req) { return 'Hello, world!' } // mocks - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_show/showname/docid') - .reply(200, showFunction(), { 'Content-type': 'text/plain' }) + mockPool + .intercept({ path: '/db/_design/ddoc/_show/showname/docid' }) + .reply(200, showFunction(), { headers: { 'content-type': 'text/plain' } }) // test GET /db/_design/ddoc/_show/showname/docid const db = nano.db.use('db') const p = await db.show('ddoc', 'showname', 'docid') - expect(p).toStrictEqual(showFunction()) - expect(scope.isDone()).toBe(true) + assert.equal(p, showFunction()) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.show', async () => { @@ -41,29 +38,29 @@ test('should be able to handle 404 - db.show', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_show/showname/docid') - .reply(404, response) + mockPool + .intercept({ path: '/db/_design/ddoc/_show/showname/docid' }) + .reply(404, response, JSON_HEADERS) // test GET /db/_design/ddoc/_show/showname/docid const db = nano.db.use('db') - await expect(db.show('ddoc', 'showname', 'docid')).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.show('ddoc', 'showname', 'docid'), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.show', async () => { const db = nano.db.use('db') - await expect(db.show()).rejects.toThrow('Invalid parameters') - await expect(db.show('ddoc')).rejects.toThrow('Invalid parameters') - await expect(db.show('ddoc', 'showname')).rejects.toThrow('Invalid parameters') - await expect(db.show('', 'showname', 'docid')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.show(), { message: 'Invalid parameters' }) + await assert.rejects(db.show('ddoc'), { message: 'Invalid parameters' }) + await assert.rejects(db.show('ddoc', 'showname'), { message: 'Invalid parameters' }) + await assert.rejects(db.show('', 'showname', 'docid'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.show', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.show('', '', '', {}, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/design.view.test.js b/test/design.view.test.js index 0e8310eb..ceb702ef 100644 --- a/test/design.view.test.js +++ b/test/design.view.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to access a MapReduce view - GET /db/_design/ddoc/_view/viewname - db.view', async () => { // mocks @@ -26,15 +23,15 @@ test('should be able to access a MapReduce view - GET /db/_design/ddoc/_view/vie { key: null, value: 23515 } ] } - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_view/viewname') - .reply(200, response) + mockPool + .intercept({ path: '/db/_design/ddoc/_view/viewname' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_design/ddoc/_view/viewname const db = nano.db.use('db') const p = await db.view('ddoc', 'viewname') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to access a MapReduce view with opts - GET /db/_design/ddoc/_view/viewname - db.view', async () => { @@ -57,15 +54,15 @@ test('should be able to access a MapReduce view with opts - GET /db/_design/ddoc { key: 'BQ', value: 1 } ] } - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_view/viewname?group=true&startkey="BA"&endkey="BQ"') - .reply(200, response) + mockPool + .intercept({ path: '/db/_design/ddoc/_view/viewname?group=true&startkey="BA"&endkey="BQ"' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_design/ddoc/_view/viewname const db = nano.db.use('db') const p = await db.view('ddoc', 'viewname', { group: true, startkey: 'BA', endkey: 'BQ' }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to access a MapReduce view with keys - POST /db/_design/ddoc/_view/viewname - db.view', async () => { @@ -77,15 +74,19 @@ test('should be able to access a MapReduce view with keys - POST /db/_design/ddo { key: 'BB', value: 1 } ] } - const scope = nock(COUCH_URL) - .post('/db/_design/ddoc/_view/viewname', { keys }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_design/ddoc/_view/viewname', + body: JSON.stringify({ keys }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_design/ddoc/_view/viewname const db = nano.db.use('db') const p = await db.view('ddoc', 'viewname', { keys }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to access a MapReduce view with queries - POST /db/_design/ddoc/_view/viewname - db.view', async () => { @@ -122,15 +123,19 @@ test('should be able to access a MapReduce view with queries - POST /db/_design/ } ] } - const scope = nock(COUCH_URL) - .post('/db/_design/ddoc/_view/viewname', { queries: opts.queries }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_design/ddoc/_view/viewname', + body: JSON.stringify({ queries: opts.queries }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_design/ddoc/_view/viewname const db = nano.db.use('db') const p = await db.view('ddoc', 'viewname', opts) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.view', async () => { @@ -139,29 +144,31 @@ test('should be able to handle 404 - db.view', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_view/viewname?group=true&startkey="BA"&endkey="BQ"') - .reply(404, response) + mockPool + .intercept({ + path: '/db/_design/ddoc/_view/viewname?group=true&startkey="BA"&endkey="BQ"' + }) + .reply(404, response, JSON_HEADERS) // test GET /db/_design/ddoc/_view/viewname const db = nano.db.use('db') - await expect(db.view('ddoc', 'viewname', { group: true, startkey: 'BA', endkey: 'BQ' })).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.view('ddoc', 'viewname', { group: true, startkey: 'BA', endkey: 'BQ' }), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.view', async () => { const db = nano.db.use('db') - await expect(db.view()).rejects.toThrow('Invalid parameters') - await expect(db.view('susan')).rejects.toThrow('Invalid parameters') - await expect(db.view('susan', '')).rejects.toThrow('Invalid parameters') - await expect(db.view('', 'susan')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.view(), { message: 'Invalid parameters' }) + await assert.rejects(db.view('susan'), { message: 'Invalid parameters' }) + await assert.rejects(db.view('susan', ''), { message: 'Invalid parameters' }) + await assert.rejects(db.view('', 'susan'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.view', () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.view('', '', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/design.viewAsStream.test.js b/test/design.viewAsStream.test.js index df5c1abb..44ac2aa2 100644 --- a/test/design.viewAsStream.test.js +++ b/test/design.viewAsStream.test.js @@ -10,37 +10,34 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') -afterEach(() => { - nock.cleanAll() -}) - -test('should be able to access a MapReduce view as a stream - GET /db/_design/ddoc/_view/viewname - db.viewAsStream', () => { +test('should be able to access a MapReduce view as a stream - GET /db/_design/ddoc/_view/viewname - db.viewAsStream', async () => { // mocks const response = { rows: [ { key: null, value: 23515 } ] } - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_view/viewname') - .reply(200, response) + mockPool + .intercept({ path: '/db/_design/ddoc/_view/viewname' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') const s = db.viewAsStream('ddoc', 'viewname') - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/design.viewWithList.test.js b/test/design.viewWithList.test.js index 53c4a920..07d48bc4 100644 --- a/test/design.viewWithList.test.js +++ b/test/design.viewWithList.test.js @@ -10,25 +10,22 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to access a MapReduce view with a list - GET /db/_design/ddoc/_list/listname/viewname - db.viewWithList', async () => { // mocks const response = '1,2,3\n4,5,6\n7,8,9\n' - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_list/listname/viewname') - .reply(200, response, { 'Content-type': 'text/csv' }) + mockPool + .intercept({ path: '/db/_design/ddoc/_list/listname/viewname' }) + .reply(200, response, { headers: { 'content-type': 'text/csv' } }) // test GET /db/_design/ddoc/_list/listname/viewname const db = nano.db.use('db') const p = await db.viewWithList('ddoc', 'viewname', 'listname') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/design.viewWithListAsStream.test.js b/test/design.viewWithListAsStream.test.js index 927301ee..053b739d 100644 --- a/test/design.viewWithListAsStream.test.js +++ b/test/design.viewWithListAsStream.test.js @@ -10,37 +10,30 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to access a MapReduce view with a list as a stream - GET /db/_design/ddoc/_list/listname/viewname - db.viewWithListAsStream', async () => { // mocks - const response = { - rows: [ - { key: null, value: 23515 } - ] - } - const scope = nock(COUCH_URL) - .get('/db/_design/ddoc/_list/listname/viewname') - .reply(200, response) + const response = '1,2,3\n4,5,6\n7,8,9\n' + mockPool + .intercept({ path: '/db/_design/ddoc/_list/listname/viewname' }) + .reply(200, response, { headers: { 'content-type': 'text/csv' } }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') const s = db.viewWithListAsStream('ddoc', 'viewname', 'listname') - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/document.bulk.test.js b/test/document.bulk.test.js index d868beb5..237b395b 100644 --- a/test/document.bulk.test.js +++ b/test/document.bulk.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to insert documents in bulk - POST /db/_bulk_docs - db.bulk', async () => { // mocks @@ -27,15 +24,19 @@ test('should be able to insert documents in bulk - POST /db/_bulk_docs - db.bulk { ok: true, id: 'y', rev: '1-456' }, { ok: true, id: 'z', rev: '1-789' } ] - const scope = nock(COUCH_URL) - .post('/db/_bulk_docs', { docs }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_bulk_docs', + body: JSON.stringify({ docs }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_bulk_docs const db = nano.db.use('db') const p = await db.bulk({ docs }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle missing database - POST /db/_bulk_docs - db.bulk', async () => { @@ -45,12 +46,16 @@ test('should be able to handle missing database - POST /db/_bulk_docs - db.bulk' error: 'not_found', reason: 'Database does not exist.' } - const scope = nock(COUCH_URL) - .post('/db/_bulk_docs', { docs }) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_bulk_docs', + body: JSON.stringify({ docs }) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_bulk_docs const db = nano.db.use('db') - await expect(db.bulk({ docs })).rejects.toThrow('Database does not exist.') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.bulk({ docs }), { message: 'Database does not exist.' }) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/document.changesreader.test.js b/test/document.changesreader.test.js index 09fd2a72..3917d156 100644 --- a/test/document.changesreader.test.js +++ b/test/document.changesreader.test.js @@ -10,89 +10,94 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const DBNAME = 'db' -afterEach(() => { - nock.cleanAll() -}) - test('should be able to follow changes feed - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + const changesResponse = { results: [], last_seq: '1-0', pending: 0 } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=60000' + }) + .reply(200, changesResponse, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start() - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { // after our initial call with since=now, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') db.changesReader.stop() + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) test('should respect the fastChanges flag - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit: 100, include_docs: false, seq_interval: 100 }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + const changesResponse = { results: [], last_seq: '1-0', pending: 0 } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=60000&seq_interval=100' + }) + .reply(200, changesResponse, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ fastChanges: true }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { // after our initial call with since=now, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') db.changesReader.stop() + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) test('should respect the selector parameter - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL, { selector: { name: 'fred' } }) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit: 100, include_docs: false, filter: '_selector' }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + const changesResponse = { results: [], last_seq: '1-0', pending: 0 } + const selector = { name: 'fred' } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&filter=_selector&include_docs=false&limit=100&since=now&timeout=60000', + body: JSON.stringify({ selector }) + }) + .reply(200, changesResponse, JSON_HEADERS) const db = nano.db.use(DBNAME) - const cr = db.changesReader.start({ selector: { name: 'fred' } }) + const cr = db.changesReader.start({ selector }) return new Promise((resolve, reject) => { cr.on('seq', function (seq) { // after our initial call with since=now, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') db.changesReader.stop() + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) test('should respect the selector parameter - db.changesReader.spool', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL, { selector: { name: 'fred' } }) - .query({ since: 'now', seq_interval: 100, include_docs: false, filter: '_selector' }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) + const changesResponse = { results: [], last_seq: '1-0', pending: 0 } + const selector = { name: 'fred' } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?filter=_selector&include_docs=false&seq_interval=100&since=now', + body: JSON.stringify({ selector }) + }) + .reply(200, changesResponse, JSON_HEADERS) const db = nano.db.use(DBNAME) - const cr = db.changesReader.spool({ since: 'now', selector: { name: 'fred' } }) - return new Promise((resolve, reject) => { + const cr = db.changesReader.spool({ since: 'now', selector }) + await new Promise((resolve, reject) => { cr.on('end', function (data) { resolve() }) @@ -100,87 +105,97 @@ test('should respect the selector parameter - db.changesReader.spool', async () }) test('should emit change and batch events - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` - const changes = [{ seq: null, id: '1', changes: ['1-1'] }, + const changes = [ + { seq: null, id: '1', changes: ['1-1'] }, { seq: null, id: '2', changes: ['1-1'] }, { seq: null, id: '3', changes: ['1-1'] }, { seq: null, id: '4', changes: ['1-1'] }, - { seq: null, id: '5', changes: ['1-1'] }] - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: changes, last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + { seq: null, id: '5', changes: ['1-1'] } + ] + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=60000' + }) + .reply(200, { results: changes, last_seq: '1-0', pending: 0 }, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.start() let i = 0 - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('change', function (c) { - expect(c).toStrictEqual(changes[i++]) + assert.equal(c, changes[i++]) }).on('batch', function (b) { - expect(b).toStrictEqual(changes) + assert.deepEqual(b, changes) }).on('seq', function (seq) { // after our initial call with since=now, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') db.changesReader.stop() resolve() }) }) }) -it('should keep polling the changes feed - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` +test('should keep polling the changes feed - db.changesReader.start', async () => { const change = { seq: null, id: 'a', changes: ['1-1'] } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(200, { results: [change], last_seq: '2-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=1000' + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(200, { results: [change], last_seq: '2-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ timeout: 1000 }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('change', function (c) { // ensure we get a change on the third poll - expect(c).toStrictEqual(change) + assert.deepEqual(c, change) db.changesReader.stop() resolve() }) }) -}, 10000) +}) -it('should keep polling the changes feed (wait: true) - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` +test('should keep polling the changes feed (wait: true) - db.changesReader.start', async () => { const change = { seq: null, id: 'a', changes: ['1-1'] } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(200, { results: [change], last_seq: '2-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=1000' + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(200, { results: [change], last_seq: '2-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ timeout: 1000, wait: true }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('change', function (c) { // ensure we get a change on the third poll - expect(c).toStrictEqual(change) + assert.deepEqual(c, change) db.changesReader.stop() resolve() }) @@ -188,69 +203,69 @@ it('should keep polling the changes feed (wait: true) - db.changesReader.start', db.changesReader.resume() }) }) -}, 10000) +}) test('spooling changes - db.changesReader.spool', async () => { - const changeURL = `/${DBNAME}/_changes` const fs = require('fs') const reply = fs.readFileSync('./test/changes.json') const replyObj = JSON.parse(reply) - nock(COUCH_URL) - .post(changeURL) - .query({ since: '0', include_docs: false, seq_interval: 100 }) - .reply(200, reply) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?include_docs=false&seq_interval=100&since=0' + }) + .reply(200, reply, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.spool({ since: 0 }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('batch', function (batch) { - expect(JSON.stringify(batch)).toBe(JSON.stringify(replyObj.results)) + assert.equal(JSON.stringify(batch), JSON.stringify(replyObj.results)) }).on('end', (lastSeq) => { - expect(lastSeq).toBe(replyObj.last_seq) + assert.equal(lastSeq, replyObj.last_seq) resolve() }) }) }) test('spooling changes - numeric seq - db.changesReader.spool', async () => { - const changeURL = `/${DBNAME}/_changes` const fs = require('fs') const reply = fs.readFileSync('./test/changes_numeric.json') const replyObj = JSON.parse(reply) - nock(COUCH_URL) - .post(changeURL) - .query({ since: 0, include_docs: false, seq_interval: 100 }) - .reply(200, reply) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?include_docs=false&seq_interval=100&since=0' + }) + .reply(200, reply, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.spool({ since: 0 }) return new Promise((resolve, reject) => { cr.on('batch', function (batch) { - expect(JSON.stringify(batch)).toBe(JSON.stringify(replyObj.results)) + assert.equal(JSON.stringify(batch), JSON.stringify(replyObj.results)) }).on('end', (lastSeq) => { - expect(lastSeq).toBe(replyObj.last_seq) + assert.equal(lastSeq, replyObj.last_seq) resolve() }) }) }) test('should handle the batchSize parameter - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` const limit = 44 - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${limit}&since=now&timeout=60000` + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ batchSize: limit }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { // after our initial call with since=now, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') db.changesReader.stop() resolve() }) @@ -258,22 +273,21 @@ test('should handle the batchSize parameter - db.changesReader.start', async () }) test('should respect the since parameter db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` const limit = 44 const since = 'thedawnoftime' - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since, limit, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${limit}&since=${since}&timeout=60000` + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ batchSize: limit, since }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { // after our initial call with since=thedawnoftime, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') db.changesReader.stop() resolve() }) @@ -281,22 +295,21 @@ test('should respect the since parameter db.changesReader.start', async () => { }) test('should stop on no changes - db.changesReader.get', async () => { - const changeURL = `/${DBNAME}/_changes` const since = 'thedawnoftime' const batchSize = 45 - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since, limit: batchSize, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=${since}&timeout=60000` + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.get({ batchSize, since }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { // after our initial call with since=now, we should get a reply with last_seq=0-1 - expect(seq).toBe('1-0') + assert.equal(seq, '1-0') }).on('end', function () { resolve() }) @@ -304,7 +317,6 @@ test('should stop on no changes - db.changesReader.get', async () => { }) test('stop after multiple batches - small batch stop - db.changesReader.get', async () => { - const changeURL = `/${DBNAME}/_changes` const since = 'now' const batchSize = 45 const batch1 = [] @@ -315,37 +327,50 @@ test('stop after multiple batches - small batch stop - db.changesReader.get', as for (let i = 0; i < 5; i++) { batch2.push({ seq: (45 + i + 1) + '-0', id: 'b' + i, changes: ['1-1'] }) } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since, limit: batchSize, include_docs: false }) - .reply(200, { results: batch1, last_seq: '45-0', pending: 2 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: '45-0', limit: batchSize, include_docs: false }) - .reply(200, { results: batch2, last_seq: '50-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: '50-0', limit: batchSize, include_docs: false }) - .reply(200, { results: [], last_seq: '50-0', pending: 0 }) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=${since}&timeout=60000` + }) + .reply(200, { results: batch1, last_seq: '45-0', pending: 2 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=45-0&timeout=60000` + }) + .reply(200, { results: batch2, last_seq: '50-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=50-0&timeout=60000` + }) + .reply(200, { results: [], last_seq: '50-0', pending: 0 }, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.get({ batchSize, since }) let batchCount = 0 - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { switch (batchCount) { - case 0: expect(seq).toBe('45-0'); break - case 1: expect(seq).toBe('50-0'); break - case 2: expect(seq).toBe('50-0'); break + case 0: + assert.equal(seq, '45-0') + break + case 1: + assert.equal(seq, '50-0') + break + case 2: + assert.equal(seq, '50-0') + break } batchCount++ }).on('end', function (lastSeq) { - expect(lastSeq).toBe('50-0') + assert.equal(lastSeq, '50-0') resolve() }) }) }) test('stop after multiple batches - zero stop - db.changesReader.get', async () => { - const changeURL = `/${DBNAME}/_changes` const since = 'now' const batchSize = 45 const batch1 = [] @@ -353,30 +378,38 @@ test('stop after multiple batches - zero stop - db.changesReader.get', async () for (let i = 0; i < batchSize; i++) { batch1.push({ seq: null, id: 'a' + i, changes: ['1-1'] }) } - for (let i = 0; i < 5; i++) { + for (let i = 0; i < batchSize; i++) { batch2.push({ seq: null, id: 'b' + i, changes: ['1-1'] }) } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since, limit: batchSize, include_docs: false }) - .reply(200, { results: batch1, last_seq: '45-0', pending: 2 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: '45-0', limit: batchSize, include_docs: false }) - .reply(200, { results: batch2, last_seq: '90-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: '90-0', limit: batchSize, include_docs: false }) - .reply(200, { results: [], last_seq: '90-0', pending: 0 }) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=${since}&timeout=60000` + }) + .reply(200, { results: batch1, last_seq: '45-0', pending: 2 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=45-0&timeout=60000` + }) + .reply(200, { results: batch2, last_seq: '90-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: `/db/_changes?feed=longpoll&include_docs=false&limit=${batchSize}&since=90-0&timeout=60000` + }) + .reply(200, { results: [], last_seq: '90-0', pending: 0 }, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.get({ batchSize, since }) let batchCount = 0 - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('seq', function (seq) { if (batchCount === 0) { - expect(seq).toBe('45-0') + assert.equal(seq, '45-0') batchCount++ } else { - expect(seq).toBe('90-0') + assert.equal(seq, '90-0') } }).on('end', function () { resolve() @@ -385,145 +418,165 @@ test('stop after multiple batches - zero stop - db.changesReader.get', async () }) test('on bad credentials - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit: 100, include_docs: false }) - .reply(401) + const response = { error: 'unauthorized', reason: 'You are not authorized to access this db.' } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=60000' + }) + .reply(401, response, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start() - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('error', function (err) { - expect(err.statusCode).toBe(401) + assert.equal(err.statusCode, 401) resolve() }) }) }) test('on bad since value - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'badtoken', limit: 100, include_docs: false }) - .reply(400, { error: 'bad_request', reason: 'Malformed sequence supplied in \'since\' parameter.' }) + const response = { error: 'bad_request', reason: 'Malformed sequence supplied in \'since\' parameter.' } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=badtoken&timeout=60000' + }) + .reply(400, response, JSON_HEADERS) const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ since: 'badtoken' }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('error', function (err) { - expect(err.statusCode).toBe(400) + assert.equal(err.statusCode, 400) resolve() }) }) }) test('should survive a HTTP 500 response - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` const change = { seq: null, id: 'a', changes: ['1-1'] } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(500) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(200, { results: [change], last_seq: '2-0', pending: 0 }) - .post(changeURL) - .delay(2000) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=1000' + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) .reply(500) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(200, { results: [change], last_seq: '2-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ timeout: 1000 }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('change', function (c) { // ensure we get a change on the third poll - expect(c).toStrictEqual(change) + assert.deepEqual(c, change) db.changesReader.stop() resolve() }).on('error', function (err) { - expect(err.statusCode).toBe(500) + assert.equal(err.statusCode, 500) }) }) -}, 10000) +}) test('should survive HTTP 429 response - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` const change = { seq: null, id: 'a', changes: ['1-1'] } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(429, { error: 'too_many_requests', reason: 'You\'ve exceeded your current limit of x requests per second for x class. Please try later.', class: 'x', rate: 1 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: '1-0', limit: 100, include_docs: false }) - .reply(200, { results: [change], last_seq: '2-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + const response429 = { error: 'too_many_requests', reason: 'You\'ve exceeded your current limit of x requests per second for x class. Please try later.', class: 'x', rate: 1 } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=1000' + }) + .reply(200, { results: [], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(429, response429, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=1-0&timeout=1000' + }) + .reply(200, { results: [change], last_seq: '2-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ timeout: 1000 }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('change', function (c) { // ensure we get a change on the third poll - expect(c).toStrictEqual(change) + assert.deepEqual(c, change) db.changesReader.stop() resolve() }).on('error', function (err) { - expect(err.statusCode).toBe(429) + assert.equal(err.statusCode, 429) }) }) -}, 10000) +}) test('should survive malformed JSON - db.changesReader.start', async () => { - const changeURL = `/${DBNAME}/_changes` const change = { seq: null, id: 'a', changes: ['1-1'] } - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: 'now', limit: 100, include_docs: false }) - .reply(200, '{ results: [], last_seq: "1-0", pending: 0') // missing bracket } - malformed JSON - .post(changeURL) - .query({ feed: 'longpoll', timeout: 1000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [change], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .delay(2000) - .reply(500) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=1000' + }) + .reply(200, '{ results: [], last_seq: "1-0", pending: 0', JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=1000' + }) + .reply(200, { results: [change], last_seq: '1-0', pending: 0 }, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start({ timeout: 1000 }) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { cr.on('change', function (c) { - expect(c).toStrictEqual(change) + assert.deepEqual(c, change) db.changesReader.stop() resolve() }).on('error', function (err) { if (err) { // shouldn't get here - expect(true).toBe(false) + assert(true, false) } }) }) -}, 10000) +}) test('should cancel HTTP connection as soon as stop is called', async () => { - const changeURL = `/${DBNAME}/_changes` - nock(COUCH_URL) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: 'now', limit: 100, include_docs: false }) - .reply(200, { results: [], last_seq: '1-0', pending: 0 }) - .post(changeURL) - .query({ feed: 'longpoll', timeout: 60000, since: '1-0', limit: 100, include_docs: false }) - .delay(60000) - .reply(500) + const response = { results: [], last_seq: '1-0', pending: 0 } + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=60000' + }) + .reply(200, response, JSON_HEADERS) + mockPool + .intercept({ + method: 'post', + path: '/db/_changes?feed=longpoll&include_docs=false&limit=100&since=now&timeout=60000' + }) + .reply(200, response, JSON_HEADERS) + const db = nano.db.use(DBNAME) const cr = db.changesReader.start() await new Promise((resolve, reject) => { cr.on('seq', function (seq) { - setTimeout(function () { - // give the next http connection a chance to be established - db.changesReader.stop() - }, 200) + db.changesReader.stop() }) cr.on('end', function () { diff --git a/test/document.destroy.test.js b/test/document.destroy.test.js index 45b8f48c..c5f41af5 100644 --- a/test/document.destroy.test.js +++ b/test/document.destroy.test.js @@ -10,27 +10,27 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to destroy a document - DELETE /db/id - db.destroy', async () => { // mocks const response = { ok: true, id: 'id', rev: '2-456' } - const scope = nock(COUCH_URL) - .delete('/db/id?rev=1-123') - .reply(200, response) + mockPool + .intercept({ + method: 'delete', + path: '/db/id?rev=1-123' + }) + .reply(200, response, JSON_HEADERS) // test DELETE /db/id const db = nano.db.use('db') const p = await db.destroy('id', '1-123') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 409 conflicts - DELETE /db/id - db.destroy', async () => { @@ -39,26 +39,29 @@ test('should be able to handle 409 conflicts - DELETE /db/id - db.destroy', asyn error: 'conflict', reason: 'Document update conflict.' } - const scope = nock(COUCH_URL) - .delete('/db/id?rev=1-123') - .reply(409, response) + mockPool + .intercept({ + method: 'delete', + path: '/db/id?rev=1-123' + }) + .reply(409, response, JSON_HEADERS) // test DELETE /db/id const db = nano.db.use('db') - await expect(db.destroy('id', '1-123')).rejects.toThrow('Document update conflict.') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.destroy('id', '1-123'), { message: 'Document update conflict.' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.destroy', async () => { const db = nano.db.use('db') - await expect(db.destroy(undefined, '1-123')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.destroy(undefined, '1-123'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.destroy', () => { - return new Promise((resolve, reject) => { +test('should detect missing parameters (callback) - db.destroy', async () => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') db.destroy(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/document.fetch.test.js b/test/document.fetch.test.js index 02ae7c06..9bcd6d80 100644 --- a/test/document.fetch.test.js +++ b/test/document.fetch.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' -const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) +const nano = Nano({ url: COUCH_URL }) test('should be able to fetch a list of documents - POST /db/_all_docs - db.fetch', async () => { // mocks @@ -67,15 +64,19 @@ test('should be able to fetch a list of documents - POST /db/_all_docs - db.fetc } ] } - const scope = nock(COUCH_URL) - .post('/db/_all_docs?include_docs=true', { keys }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_all_docs?include_docs=true', + body: JSON.stringify({ keys }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_all_docs const db = nano.db.use('db') const p = await db.fetch({ keys }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch a list of documents with opts - POST /db/_all_docs - db.fetch', async () => { @@ -126,15 +127,19 @@ test('should be able to fetch a list of documents with opts - POST /db/_all_docs } ] } - const scope = nock(COUCH_URL) - .post('/db/_all_docs?include_docs=true&descending=true', { keys }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_all_docs?include_docs=true&descending=true', + body: JSON.stringify({ keys }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_all_docs const db = nano.db.use('db') const p = await db.fetch({ keys }, { descending: true }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - POST /db/_all_docs - db.fetch', async () => { @@ -144,30 +149,34 @@ test('should be able to handle 404 - POST /db/_all_docs - db.fetch', async () => error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .post('/db/_all_docs?include_docs=true', { keys }) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_all_docs?include_docs=true', + body: JSON.stringify({ keys }) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_all_docs const db = nano.db.use('db') - await expect(db.fetch({ keys })).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.fetch({ keys }), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect invalid parameters - db.fetch', async () => { const db = nano.db.use('db') - await expect(db.fetch()).rejects.toThrow('Invalid parameters') - await expect(db.fetch({})).rejects.toThrow('Invalid parameters') - await expect(db.fetch({ keys: {} })).rejects.toThrow('Invalid parameters') - await expect(db.fetch({ keys: '123' })).rejects.toThrow('Invalid parameters') - await expect(db.fetch({ keys: [] })).rejects.toThrow('Invalid parameters') + await assert.rejects(db.fetch(), { message: 'Invalid parameters' }) + await assert.rejects(db.fetch({}), { message: 'Invalid parameters' }) + await assert.rejects(db.fetch({ keys: {} }), { message: 'Invalid parameters' }) + await assert.rejects(db.fetch({ keys: '123' }), { message: 'Invalid parameters' }) + await assert.rejects(db.fetch({ keys: [] }), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.fetch', () => { +test('should detect missing parameters (callback) - db.fetch', async () => { return new Promise((resolve, reject) => { const db = nano.db.use('db') db.fetch(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/document.fetchRevs.test.js b/test/document.fetchRevs.test.js index 1d6bb729..b33ce3ab 100644 --- a/test/document.fetchRevs.test.js +++ b/test/document.fetchRevs.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to fetch a list of document revisions - POST /db/_all_docs - db.fetchRevs', async () => { // mocks @@ -49,15 +46,19 @@ test('should be able to fetch a list of document revisions - POST /db/_all_docs } ] } - const scope = nock(COUCH_URL) - .post('/db/_all_docs', { keys }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_all_docs', + body: JSON.stringify({ keys }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_all_docs const db = nano.db.use('db') const p = await db.fetchRevs({ keys }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch a list of document revisions with opts - POST /db/_all_docs - db.fetchRevs', async () => { @@ -90,15 +91,19 @@ test('should be able to fetch a list of document revisions with opts - POST /db } ] } - const scope = nock(COUCH_URL) - .post('/db/_all_docs?descending=true', { keys }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_all_docs?descending=true', + body: JSON.stringify({ keys }) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_all_docs const db = nano.db.use('db') const p = await db.fetchRevs({ keys }, { descending: true }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - POST /db/_all_docs - db.fetchRevs', async () => { @@ -108,30 +113,34 @@ test('should be able to handle 404 - POST /db/_all_docs - db.fetchRevs', async ( error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .post('/db/_all_docs', { keys }) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_all_docs', + body: JSON.stringify({ keys }) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_all_docs const db = nano.db.use('db') - await expect(db.fetchRevs({ keys })).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.fetchRevs({ keys }), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.fetchRevs', async () => { const db = nano.db.use('db') - await expect(db.fetchRevs()).rejects.toThrow('Invalid parameters') - await expect(db.fetchRevs({})).rejects.toThrow('Invalid parameters') - await expect(db.fetchRevs({ keys: {} })).rejects.toThrow('Invalid parameters') - await expect(db.fetchRevs({ keys: '123' })).rejects.toThrow('Invalid parameters') - await expect(db.fetchRevs({ keys: [] })).rejects.toThrow('Invalid parameters') + await assert.rejects(db.fetchRevs(), { message: 'Invalid parameters' }) + await assert.rejects(db.fetchRevs({}), { message: 'Invalid parameters' }) + await assert.rejects(db.fetchRevs({ keys: {} }), { message: 'Invalid parameters' }) + await assert.rejects(db.fetchRevs({ keys: '123' }), { message: 'Invalid parameters' }) + await assert.rejects(db.fetchRevs({ keys: [] }), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.fetchRevs', () => { - return new Promise((resolve, reject) => { +test('should detect missing parameters (callback) - db.fetchRevs', async () => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') db.fetchRevs(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/document.get.test.js b/test/document.get.test.js index 93443cb9..17d119e9 100644 --- a/test/document.get.test.js +++ b/test/document.get.test.js @@ -10,55 +10,52 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to get a document - GET /db/id - db.get', async () => { // mocks const response = { _id: 'id', rev: '1-123', a: 1, b: 'two', c: true } - const scope = nock(COUCH_URL) - .get('/db/id') - .reply(200, response) + mockPool + .intercept({ path: '/db/id' }) + .reply(200, response, JSON_HEADERS) // test GET /db/id const db = nano.db.use('db') const p = await db.get('id') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to get a document from a partition - GET /db/pkey:id - db.get', async () => { // mocks const response = { _id: 'partkey:id', rev: '1-123', a: 1, b: 'two', c: true } - const scope = nock(COUCH_URL) - .get('/db/partkey%3Aid') - .reply(200, response) + mockPool + .intercept({ path: '/db/partkey%3Aid' }) + .reply(200, response, JSON_HEADERS) // test GET /db/pkey:id const db = nano.db.use('db') const p = await db.get('partkey:id') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to get a document with options - GET /db/id?conflicts=true - db.get', async () => { // mocks const response = { _id: 'id', rev: '1-123', a: 1, b: 'two', c: true } - const scope = nock(COUCH_URL) - .get('/db/id?conflicts=true') - .reply(200, response) + mockPool + .intercept({ path: '/db/id?conflicts=true' }) + .reply(200, response, JSON_HEADERS) // test GET /db/id?x=y const db = nano.db.use('db') const p = await db.get('id', { conflicts: true }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - GET /db/id - db.get', async () => { @@ -67,26 +64,26 @@ test('should be able to handle 404 - GET /db/id - db.get', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .get('/db/id') - .reply(404, response) + mockPool + .intercept({ path: '/db/id' }) + .reply(404, response, JSON_HEADERS) // test GET /db/id const db = nano.db.use('db') - await expect(db.get('id')).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.get('id'), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing doc id - db.get', async () => { const db = nano.db.use('db') - await expect(db.get()).rejects.toThrow('Invalid parameters') + await assert.rejects(db.get(), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.get', () => { - return new Promise((resolve, reject) => { +test('should detect missing parameters (callback) - db.get', async () => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') db.get(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) @@ -95,13 +92,13 @@ test('should detect missing parameters (callback) - db.get', () => { test('check request can fetch local documents - db.get', async () => { // mocks const response = { _id: '_local/id', _rev: '1-123', a: 1 } - const scope = nock(COUCH_URL) - .get('/db/_local/id') - .reply(200, response) + mockPool + .intercept({ path: '/db/_local/id' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_local/id const db = nano.db.use('db') const p = await db.get('_local/id') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/document.head.test.js b/test/document.head.test.js index 40eb1cb0..d0dad424 100644 --- a/test/document.head.test.js +++ b/test/document.head.test.js @@ -10,43 +10,54 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to head a document - HEAD /db/id - db.head', async () => { // mocks - const scope = nock(COUCH_URL) - .head('/db/id') - .reply(200, '', { ETag: '1-123' }) + const headers = { + 'content-type': 'application/json', + etag: '1-123' + } + mockPool + .intercept({ + method: 'head', + path: '/db/id' + }) + .reply(200, '', { headers }) // test HEAD /db const db = nano.db.use('db') const p = await db.head('id') // headers get lowercased - expect(p.etag).toBe('1-123') - expect(scope.isDone()).toBe(true) + assert.equal(p.etag, '1-123') + mockAgent.assertNoPendingInterceptors() }) -test('should be able to head a document with callback - HEAD /db/id - db.head', () => { +test('should be able to head a document with callback - HEAD /db/id - db.head', async () => { // mocks - const scope = nock(COUCH_URL) - .head('/db/id') - .reply(200, '', { ETag: '1-123' }) + const headers = { + 'content-type': 'application/json', + etag: '1-123' + } + mockPool + .intercept({ + method: 'head', + path: '/db/id' + }) + .reply(200, '', { headers }) // test HEAD /db - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') db.head('id', (err, data, headers) => { // headers get lowercased - expect(err).toBeNull() - expect(headers.etag).toBe('1-123') - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.equal(headers.etag, '1-123') + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -54,26 +65,29 @@ test('should be able to head a document with callback - HEAD /db/id - db.head', test('should be able to head a missing document - HEAD /db/id - db.head', async () => { // mocks - const scope = nock(COUCH_URL) - .head('/db/id') - .reply(404, '') + mockPool + .intercept({ + method: 'head', + path: '/db/id' + }) + .reply(404, '', JSON_HEADERS) // test HEAD /db const db = nano.db.use('db') - await expect(db.head('id')).rejects.toThrow('couch returned 404') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.head('id'), { message: 'couch returned 404' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.head', async () => { const db = nano.db.use('db') - await expect(db.head()).rejects.toThrow('Invalid parameters') + await assert.rejects(db.head(), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.head', () => { - return new Promise((resolve, reject) => { +test('should detect missing parameters (callback) - db.head', async () => { + await new Promise((resolve, reject) => { const db = nano.db.use('db') db.head(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/document.insert.test.js b/test/document.insert.test.js index c4532d70..6895a2fe 100644 --- a/test/document.insert.test.js +++ b/test/document.insert.test.js @@ -10,91 +10,105 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to insert document - POST /db - db.insert', async () => { // mocks const doc = { a: 1, b: 2 } const response = { ok: true, id: '8s8g8h8h9', rev: '1-123' } - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') const p = await db.insert(doc) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert document with opts - POST /db?batch=ok - db.insert', async () => { // mocks const doc = { a: 1, b: 2 } const response = { ok: true, id: '8s8g8h8h9', rev: '1-123' } - const scope = nock(COUCH_URL) - .post('/db?batch=ok', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db?batch=ok', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') const p = await db.insert(doc, { batch: 'ok' }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert document with known id - PUT /db/id - db.insert', async () => { // mocks const doc = { a: 1, b: 2 } const response = { ok: true, id: 'myid', rev: '1-123' } - - const scope = nock(COUCH_URL) - .put('/db/myid', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'put', + path: '/db/myid', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test PUT /db const db = nano.db.use('db') const p = await db.insert(doc, 'myid') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert document with id in object - POST /db - db.insert', async () => { // mocks const doc = { _id: 'myid', a: 1, b: 2 } const response = { ok: true, id: 'myid', rev: '1-123' } - - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') const p = await db.insert(doc) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to update document with id/rev in object - POST /db - db.insert', async () => { // mocks const doc = { _id: 'myid', _rev: '1-123', a: 2, b: 2 } const response = { ok: true, id: 'myid', rev: '2-456' } - - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') const p = await db.insert(doc) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 409 conflicts - POST /db - db.insert', async () => { @@ -104,14 +118,18 @@ test('should be able to handle 409 conflicts - POST /db - db.insert', async () = error: 'conflict', reason: 'Document update conflict.' } - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(409, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(409, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') - await expect(db.insert(doc)).rejects.toThrow('Document update conflict.') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.insert(doc), { message: 'Document update conflict.' }) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle missing database - POST /db - db.insert', async () => { @@ -121,44 +139,54 @@ test('should be able to handle missing database - POST /db - db.insert', async ( error: 'not_found', reason: 'Database does not exist.' } - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(404, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') - await expect(db.insert(doc)).rejects.toThrow('Database does not exist.') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.insert(doc), { message: 'Database does not exist.' }) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert document with _local id - PUT /db/_local/id - db.insert', async () => { // mocks const doc = { a: 1, b: 2 } const response = { ok: true, id: '_local/myid', rev: '1-123' } - - const scope = nock(COUCH_URL) - .put('/db/_local/myid', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'put', + path: '/db/_local/myid', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test PUT /db const db = nano.db.use('db') const p = await db.insert(doc, '_local/myid') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert document with local id in object - POST /db - db.insert', async () => { // mocks const doc = { _id: '_local/myid', a: 1, b: 2 } const response = { ok: true, id: '_local/myid', rev: '1-123' } - - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const db = nano.db.use('db') const p = await db.insert(doc) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/document.list.test.js b/test/document.list.test.js index 53fc2450..175d4606 100644 --- a/test/document.list.test.js +++ b/test/document.list.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to get a list of documents - GET /db/_all_docs - db.list', async () => { // mocks @@ -48,15 +45,15 @@ test('should be able to get a list of documents - GET /db/_all_docs - db.list', } ] } - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs const db = nano.db.use('db') const p = await db.list() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to get a list of documents with opts - GET /db/_all_docs - db.list', async () => { @@ -80,15 +77,15 @@ test('should be able to get a list of documents with opts - GET /db/_all_docs - } ] } - const scope = nock(COUCH_URL) - .get('/db/_all_docs?include_docs=true&limit=1') - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?include_docs=true&limit=1' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs const db = nano.db.use('db') const p = await db.list({ include_docs: true, limit: 1 }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - GET /db/_all_docs - db.list', async () => { @@ -97,12 +94,12 @@ test('should be able to handle 404 - GET /db/_all_docs - db.list', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .reply(404, response) + mockPool + .intercept({ path: '/db/_all_docs' }) + .reply(404, response, JSON_HEADERS) // test GET /db/_all_docs const db = nano.db.use('db') - await expect(db.list()).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.list(), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/document.listAsStream.test.js b/test/document.listAsStream.test.js index cdeac804..e3590f64 100644 --- a/test/document.listAsStream.test.js +++ b/test/document.listAsStream.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should get a streamed list of documents - GET /db/_all_docs - db.listAsStream', async () => { // mocks @@ -48,28 +45,28 @@ test('should get a streamed list of documents - GET /db/_all_docs - db.listAsStr } ] } - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_all_docs const db = nano.db.use('db') const s = db.listAsStream() - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) -test('should get a streamed list of documents with opts- GET /db/_all_docs - db.listAsStream', () => { +test('should get a streamed list of documents with opts- GET /db/_all_docs - db.listAsStream', async () => { // mocks const response = { total_rows: 23516, @@ -90,22 +87,22 @@ test('should get a streamed list of documents with opts- GET /db/_all_docs - db. } ] } - const scope = nock(COUCH_URL) - .get('/db/_all_docs?limit=1&include_docs=true') - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?limit=1&include_docs=true' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_all_docs const db = nano.db.use('db') const s = db.listAsStream({ limit: 1, include_docs: true }) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/mock.js b/test/mock.js new file mode 100644 index 00000000..d793f950 --- /dev/null +++ b/test/mock.js @@ -0,0 +1,14 @@ +const COUCH_URL = 'http://127.0.0.1:5984' +const JSON_HEADERS = { headers: { 'content-type': 'application/json' } } +const { MockAgent, setGlobalDispatcher } = require('undici') +const mockAgent = new MockAgent() +mockAgent.disableNetConnect() +const mockPool = mockAgent.get(COUCH_URL) +setGlobalDispatcher(mockAgent) + +module.exports = { + COUCH_URL, + JSON_HEADERS, + mockAgent, + mockPool +} diff --git a/test/multipart.get.test.js b/test/multipart.get.test.js index d00d52de..3f7a10d5 100644 --- a/test/multipart.get.test.js +++ b/test/multipart.get.test.js @@ -10,10 +10,12 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') + const multipartResponse = ''.concat( '--e89b3e29388aef23453450d10e5aaed0', 'Content-Type: application/json', @@ -32,34 +34,40 @@ const multipartResponse = ''.concat( '', '--e89b3e29388aef23453450d10e5aaed0--') -afterEach(() => { - nock.cleanAll() -}) - test('should be able to fetch a document with attachments - multipart GET /db - db.multipart.get', async () => { // mocks - const scope = nock(COUCH_URL, { reqheaders: { accept: 'multipart/related' } }) - .get('/db/docid?attachments=true') - .reply(200, multipartResponse, { 'content-type': 'multipart/related; boundary="e89b3e29388aef23453450d10e5aaed0"' }) + mockPool + .intercept({ + path: '/db/docid?attachments=true', + headers: { + accept: 'multipart/related' + } + }) + .reply(200, multipartResponse, { headers: { 'content-type': 'multipart/related; boundary="e89b3e29388aef23453450d10e5aaed0"' } }) // test GET /db/id?attachments=true const db = nano.db.use('db') const p = await db.multipart.get('docid') - expect(p.toString()).toStrictEqual(multipartResponse) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, multipartResponse) + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch a document with attachments with opts - multipart GET /db - db.multipart.get', async () => { // mocks - const scope = nock(COUCH_URL, { reqheaders: { accept: 'multipart/related' } }) - .get('/db/docid?attachments=true&conflicts=true') - .reply(200, multipartResponse, { 'content-type': 'multipart/related; boundary="e89b3e29388aef23453450d10e5aaed0"' }) + mockPool + .intercept({ + path: '/db/docid?attachments=true&conflicts=true', + headers: { + accept: 'multipart/related' + } + }) + .reply(200, multipartResponse, { headers: { 'content-type': 'multipart/related; boundary="e89b3e29388aef23453450d10e5aaed0"' } }) // test GET /db/id?attachments=true&x=y const db = nano.db.use('db') const p = await db.multipart.get('docid', { conflicts: true }) - expect(p.toString()).toStrictEqual(multipartResponse) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, multipartResponse) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.multipart.get', async () => { @@ -68,28 +76,33 @@ test('should be able to handle 404 - db.multipart.get', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL, { reqheaders: { accept: 'multipart/related' } }) - .get('/db/docid?attachments=true') - .reply(404, response) + mockPool + .intercept({ + path: '/db/docid?attachments=true', + headers: { + accept: 'multipart/related' + } + }) + .reply(404, response, JSON_HEADERS) // test GET /db const db = nano.db.use('db') - await expect(db.multipart.get('docid')).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.multipart.get('docid'), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing docName - db.multipart.get', async () => { const db = nano.db.use('db') - await expect(db.multipart.get()).rejects.toThrow('Invalid parameters') - await expect(db.multipart.get('')).rejects.toThrow('Invalid parameters') - await expect(db.multipart.get(undefined, { conflicts: true })).rejects.toThrow('Invalid parameters') + await assert.rejects(db.multipart.get(), { message: 'Invalid parameters' }) + await assert.rejects(db.multipart.get(''), { message: 'Invalid parameters' }) + await assert.rejects(db.multipart.get(undefined, { conflicts: true }), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.multipart.get', () => { +test('should detect missing parameters (callback) - db.multipart.get', async () => { const db = nano.db.use('db') return new Promise((resolve, reject) => { db.multipart.get(undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/multipart.insert.test.js b/test/multipart.insert.test.js index 4f84462f..2971e595 100644 --- a/test/multipart.insert.test.js +++ b/test/multipart.insert.test.js @@ -10,10 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') const image1 = Buffer.from(''.concat( 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAsV', 'BMVEUAAAD////////////////////////5ur3rEBn////////////////wDBL/', @@ -46,37 +47,49 @@ const doc = { } } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to insert a document with attachments #1 - multipart PUT /db/id - db.multipart.insert', async () => { // mocks const response = { ok: true, id: '8s8g8h8h9', rev: '1-123' } - const scope = nock(COUCH_URL) - .matchHeader('content-type', h => h.includes('multipart/related')) - .put('/db/docid') - .reply(200, response) + mockPool + .intercept({ + method: 'put', + path: '/db/docid', + headers: { + 'content-type': /^multipart\/related; .*/ + }, + body: (value) => { + return true + } + }) + .reply(200, response, JSON_HEADERS) // test PUT /db/id const db = nano.db.use('db') const p = await db.multipart.insert(doc, images, 'docid') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to insert a document with attachments #2 - multipart PUT /db/id - db.multipart.insert', async () => { const response = { ok: true, id: '8s8g8h8h9', rev: '1-123' } - const scope = nock(COUCH_URL) - .matchHeader('content-type', h => h.includes('multipart/related')) - .put('/db/docid') - .reply(200, response) + mockPool + .intercept({ + method: 'put', + path: '/db/docid', + headers: { + 'content-type': /^multipart\/related; .*/ + }, + body: (value) => { + return true + } + }) + .reply(200, response, JSON_HEADERS) // test PUT /db/id const db = nano.db.use('db') const p = await db.multipart.insert(doc, images, { docName: 'docid' }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.multipart.insert', async () => { @@ -85,29 +98,37 @@ test('should be able to handle 404 - db.multipart.insert', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .matchHeader('content-type', h => h.includes('multipart/related')) - .put('/db/docid') - .reply(404, response) + mockPool + .intercept({ + method: 'put', + path: '/db/docid', + headers: { + 'content-type': /^multipart\/related; .*/ + }, + body: (value) => { + return true + } + }) + .reply(404, response, JSON_HEADERS) // test PUT /db/id const db = nano.db.use('db') - await expect(db.multipart.insert(doc, images, { docName: 'docid' })).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.multipart.insert(doc, images, { docName: 'docid' }), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing docName - db.multipart.insert', async () => { const db = nano.db.use('db') - await expect(db.multipart.insert()).rejects.toThrow('Invalid parameters') - await expect(db.multipart.insert({ a: 1 }, [{}])).rejects.toThrow('Invalid parameters') - await expect(db.multipart.insert({ a: 1 }, [{}], {})).rejects.toThrow('Invalid parameters') + await assert.rejects(db.multipart.insert(), { message: 'Invalid parameters' }) + await assert.rejects(db.multipart.insert({ a: 1 }, [{}]), { message: 'Invalid parameters' }) + await assert.rejects(db.multipart.insert({ a: 1 }, [{}], {}), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.multipart.insert', () => { +test('should detect missing parameters (callback) - db.multipart.insert', async () => { const db = nano.db.use('db') - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.multipart.insert(undefined, undefined, undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/multipart.test.js b/test/multipart.test.js index f1173f85..32d08705 100644 --- a/test/multipart.test.js +++ b/test/multipart.test.js @@ -1,3 +1,5 @@ +const test = require('node:test') +const assert = require('node:assert/strict') const MultiPartFactory = require('../lib/multipart.js') const textAttachment = { name: 'test.txt', data: 'Hello\r\nWorld!', content_type: 'text/plain' } const anotherTextAttachment = { name: 'test2.txt', data: 'the quick brown fox', content_type: 'text/plain' } @@ -7,50 +9,51 @@ test('should return different boundary each time', async () => { const mf2 = new MultiPartFactory([]) const mf3 = new MultiPartFactory([]) - expect(typeof mf1.boundary).toBe('string') - expect(typeof mf2.boundary).toBe('string') - expect(typeof mf3.boundary).toBe('string') - expect(mf1.boundary.length).toBe(16) - expect(mf2.boundary.length).toBe(16) - expect(mf3.boundary.length).toBe(16) - expect(mf1).not.toEqual(mf2) - expect(mf1).not.toEqual(mf3) - expect(mf2).not.toEqual(mf3) + assert.equal(typeof mf1.boundary, 'string') + assert.equal(typeof mf2.boundary, 'string') + assert.equal(typeof mf3.boundary, 'string') + assert.equal(mf1.boundary.length, 16) + assert.equal(mf2.boundary.length, 16) + assert.equal(mf3.boundary.length, 16) + assert.notEqual(mf1, mf2) + assert.notEqual(mf1, mf3) + assert.notEqual(mf2, mf3) }) test('should return boundary in header', async () => { const mf1 = new MultiPartFactory([]) const boundary = mf1.boundary const header = mf1.header - expect(header).toEqual(`multipart/related; boundary=${boundary}`) + assert.equal(header, `multipart/related; boundary=${boundary}`) }) test('should handle single attachments', async () => { const mf1 = new MultiPartFactory([textAttachment]) - expect(typeof mf1.data).toEqual('object') - expect(Buffer.isBuffer(mf1.data)).toEqual(true) + + assert.equal(typeof mf1.data, 'object') + assert.equal(Buffer.isBuffer(mf1.data), true) const lines = mf1.data.toString().split('\r\n') - expect(lines).toContain(`--${mf1.boundary}`) - expect(lines).toContain('content-type: text/plain') - expect(lines).toContain('content-length: 13') - expect(lines).toContain('') - expect(lines).toContain('Hello') - expect(lines).toContain('World!') - expect(lines).toContain(`--${mf1.boundary}--`) + assert.equal(lines.includes(`--${mf1.boundary}`), true) + assert.equal(lines.includes('content-type: text/plain'), true) + assert.equal(lines.includes('content-length: 13'), true) + assert.equal(lines.includes(''), true) + assert.equal(lines.includes('Hello'), true) + assert.equal(lines.includes('World!'), true) + assert.equal(lines.includes(`--${mf1.boundary}--`), true) }) test('should handle two attachments', async () => { const mf1 = new MultiPartFactory([textAttachment, anotherTextAttachment]) - expect(typeof mf1.data).toEqual('object') - expect(Buffer.isBuffer(mf1.data)).toEqual(true) + assert.equal(typeof mf1.data, 'object') + assert.equal(Buffer.isBuffer(mf1.data), true) const lines = mf1.data.toString().split('\r\n') - expect(lines).toContain(`--${mf1.boundary}`) - expect(lines).toContain('content-type: text/plain') - expect(lines).toContain('content-length: 13') - expect(lines).toContain('') - expect(lines).toContain('Hello') - expect(lines).toContain('World!') - expect(lines).toContain('content-length: 19') - expect(lines).toContain('the quick brown fox') - expect(lines).toContain(`--${mf1.boundary}--`) + assert.equal(lines.includes(`--${mf1.boundary}`), true) + assert.equal(lines.includes('content-type: text/plain'), true) + assert.equal(lines.includes('content-length: 13'), true) + assert.equal(lines.includes(''), true) + assert.equal(lines.includes('Hello'), true) + assert.equal(lines.includes('World!'), true) + assert.equal(lines.includes('content-length: 19'), true) + assert.equal(lines.includes('the quick brown fox'), true) + assert.equal(lines.includes(`--${mf1.boundary}`), true) }) diff --git a/test/nano.agent.test.js b/test/nano.agent.test.js deleted file mode 100644 index 88cd1e22..00000000 --- a/test/nano.agent.test.js +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const nock = require('nock') -const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' -const http = require('http') -const httpAgent = new http.Agent() - -afterEach(() => { - nock.cleanAll() -}) - -test('should be able to log output with a user-supplied http agent', async () => { - // setup Nano with custom logger - const logs = [] - const nano = Nano({ - url: COUCH_URL, - log: (data) => { - logs.push(data) - }, - requestDefaults: { - agent: httpAgent - } - }) - - // mocks - const response = { _id: 'id', rev: '1-123', a: 1, b: 'two', c: true } - const scope = nock(COUCH_URL) - .get('/db/id') - .reply(200, response) - - // test GET /db/id - const db = nano.db.use('db') - const p = await db.get('id') - expect(p).toStrictEqual(response) - expect(logs.length).toBe(2) - expect(scope.isDone()).toBe(true) -}) diff --git a/test/nano.auth.test.js b/test/nano.auth.test.js index 4997f2f3..817b232b 100644 --- a/test/nano.auth.test.js +++ b/test/nano.auth.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' -const nano = Nano({ url: COUCH_URL, jar: true }) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) +const nano = Nano({ url: COUCH_URL }) test('should be able to authenticate - POST /_session - nano.auth', async () => { // mocks @@ -26,15 +23,34 @@ test('should be able to authenticate - POST /_session - nano.auth', async () => const response = { ok: true, name: 'admin', roles: ['_admin', 'admin'] } const c = 'AuthSession=YWRtaW46NUU0MTFBMDE6stHsxYnlDy4mYxwZEcnXHn4fm5w' const cookie = `${c}; Version=1; Expires=Mon, 10-Feb-2050 09:03:21 GMT; Max-Age=600; Path=/; HttpOnly` - const scope = nock(COUCH_URL) - .post('/_session', 'name=u&password=p', { 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' }) - .reply(200, response, { 'Set-Cookie': cookie }) - .get('/_all_dbs') - .reply(200, ['a']) + mockPool + .intercept({ + method: 'post', + path: '/_session', + body: 'name=u&password=p', + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' + } + }) + .reply(200, response, { + headers: { + 'content-type': 'application/json', + 'Set-Cookie': cookie + } + }) + mockPool + .intercept({ + path: '/_all_dbs', + headers: { + cookie: c + } + }) + .reply(200, ['a'], JSON_HEADERS) // test POST /_session const p = await nano.auth(username, password) - expect(p).toStrictEqual(response) - await nano.db.list() - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + const q = await nano.db.list() + assert.deepEqual(q, ['a']) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.config.test.js b/test/nano.config.test.js index 16c02b5d..80218aa1 100644 --- a/test/nano.config.test.js +++ b/test/nano.config.test.js @@ -11,46 +11,47 @@ // the License. const Nano = require('..') -const assert = require('assert') +const test = require('node:test') +const assert = require('node:assert/strict') test('should be able to supply HTTP url - nano.config', () => { - const HTTP_URL = 'http://localhost:5984' + const HTTP_URL = 'http://127.0.0.1:5984' const nano = Nano(HTTP_URL) - expect(nano.config.url).toBe(HTTP_URL) + assert.equal(nano.config.url, HTTP_URL) }) test('should be able to supply URL with database name - nano.config', () => { - const HTTP_URL = 'http://localhost:5984/db' + const HTTP_URL = 'http://127.0.0.1:5984/db' const nano = Nano(HTTP_URL) - expect(nano.config.url).toBe('http://localhost:5984') - expect(nano.config.db).toBe('db') + assert.equal(nano.config.url, 'http://127.0.0.1:5984') + assert.equal(nano.config.db, 'db') }) test('should be able to supply HTTPS url - nano.config', () => { const HTTPS_URL = 'https://mydomain.com' const nano = Nano(HTTPS_URL) - expect(nano.config.url).toBe(HTTPS_URL) + assert.equal(nano.config.url, HTTPS_URL) }) test('should be able to supply HTTP url with cookie jar - nano.config', () => { - const HTTP_URL = 'http://localhost:5984' + const HTTP_URL = 'http://127.0.0.1:5984' const nano = Nano({ url: HTTP_URL, jar: true }) - expect(nano.config.url).toBe(HTTP_URL) - expect(nano.config.jar).toBe(true) + assert.equal(nano.config.url, HTTP_URL) + assert.equal(nano.config.jar, true) }) test('should be able to supply HTTPS url with auth credentials - nano.config', () => { const HTTPS_URL = 'https://myusername:mypassword@mydomain.com' const nano = Nano(HTTPS_URL) - expect(nano.config.url).toBe(HTTPS_URL) + assert.equal(nano.config.url, HTTPS_URL) }) test('should be able to supply requestDefaults - nano.config', () => { const HTTPS_URL = 'https://myusername:mypassword@mydomain.com' const defaults = { proxy: 'http://localproxy.com' } const nano = Nano({ url: HTTPS_URL, requestDefaults: defaults }) - expect(nano.config.url).toBe(HTTPS_URL) - expect(nano.config.requestDefaults).toBe(defaults) + assert.equal(nano.config.url, HTTPS_URL) + assert.equal(nano.config.requestDefaults, defaults) }) test('should be able to supply logging function - nano.config', () => { @@ -59,16 +60,16 @@ test('should be able to supply logging function - nano.config', () => { console.log(id, args) } const nano = Nano({ url: HTTPS_URL, log: logger }) - expect(nano.config.url).toBe(HTTPS_URL) - expect(typeof nano.config.log).toBe('function') + assert.equal(nano.config.url, HTTPS_URL) + assert.equal(typeof nano.config.log, 'function') }) test('should be able to handle missing URL - nano.config', () => { try { Nano() } catch (e) { - expect(e instanceof assert.AssertionError) - expect(e.message).toBe('You must specify the endpoint url when invoking this module') + assert(e instanceof assert.AssertionError) + assert.equal(e.message, 'You must specify the endpoint url when invoking this module') } }) @@ -77,8 +78,8 @@ test('should be able to handle invalid URL #1 - nano.config', () => { try { Nano(INVALID_URL) } catch (e) { - expect(e instanceof assert.AssertionError) - expect(e.message).toBe('url is not valid') + assert(e instanceof assert.AssertionError) + assert.equal(e.message, 'url is not valid') } }) @@ -87,16 +88,16 @@ test('should be able to handle invalid URL #2 - nano.config', () => { try { Nano({ url: INVALID_URL }) } catch (e) { - expect(e instanceof assert.AssertionError) - expect(e.message).toBe('url is not valid') + assert(e instanceof assert.AssertionError) + assert.equal(e.message, 'url is not valid') } }) test('exercise the parseUrl feature for proxies etc - nano.config', () => { - const HTTP_URL = 'http://localhost:5984/prefix' + const HTTP_URL = 'http://127.0.0.1:5984/prefix' const nano = Nano({ url: HTTP_URL, parseUrl: false }) - expect(nano.config.url).toBe(HTTP_URL) + assert.equal(nano.config.url, HTTP_URL) }) diff --git a/test/nano.customheaders.test.js b/test/nano.customheaders.test.js index d6f0c720..38131f84 100644 --- a/test/nano.customheaders.test.js +++ b/test/nano.customheaders.test.js @@ -10,18 +10,17 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const CUSTOM_HEADER = 'thequickbrownfox' const nano = Nano({ url: COUCH_URL, - requestDefaults: { - headers: { - customheader: CUSTOM_HEADER - } + headers: { + customheader: CUSTOM_HEADER } }) -const nock = require('nock') const response = { db_name: 'db', purge_seq: '0-8KhNZEiqhyjKAgBm5Rxs', @@ -49,21 +48,19 @@ const response = { instance_start_time: '0' } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to fetch the database info - GET /db - nano.db.get', async () => { // mocks - const scope = nock(COUCH_URL) - .matchHeader('customheader', CUSTOM_HEADER) - .get('/db') - .reply(200, response) + mockPool + .intercept({ + path: '/db', + headers: { + customheader: CUSTOM_HEADER + } + }) + .reply(200, response, JSON_HEADERS) // test GET /db const p = await nano.db.get('db') - expect(typeof p).toBe('object') - expect(p.doc_count).toBe(0) - expect(p.db_name).toBe('db') - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.info.test.js b/test/nano.info.test.js index 6cb87173..1e97dff3 100644 --- a/test/nano.info.test.js +++ b/test/nano.info.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('../lib/nano') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to get info - GET / - nano.info', async () => { // mocks @@ -30,12 +27,12 @@ test('should be able to get info - GET / - nano.info', async () => { features: ['access-ready', 'partitioned', 'pluggable-storage-engines', 'reshard', 'scheduler'], vendor: { name: 'The Apache Software Foundation' } } - const scope = nock(COUCH_URL) - .get('/') - .reply(200, response) + mockPool + .intercept({ path: '/' }) + .reply(200, response, JSON_HEADERS) // test GET /_session const p = await nano.info() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.logger.test.js b/test/nano.logger.test.js index 0c212e59..1db53c79 100644 --- a/test/nano.logger.test.js +++ b/test/nano.logger.test.js @@ -10,13 +10,10 @@ // License for the specific language governing permissions and limitations under // the License. -const nock = require('nock') +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' - -afterEach(() => { - nock.cleanAll() -}) test('should be able to log output with user-defined function', async () => { // setup Nano with custom logger @@ -30,14 +27,14 @@ test('should be able to log output with user-defined function', async () => { // mocks const response = { _id: 'id', rev: '1-123', a: 1, b: 'two', c: true } - const scope = nock(COUCH_URL) - .get('/db/id') - .reply(200, response) + mockPool + .intercept({ path: '/db/id' }) + .reply(200, response, JSON_HEADERS) // test GET /db/id const db = nano.db.use('db') const p = await db.get('id') - expect(p).toStrictEqual(response) - expect(logs.length).toBe(2) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + assert.equal(logs.length, 2) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.request.test.js b/test/nano.request.test.js index eebf2b35..6b920549 100644 --- a/test/nano.request.test.js +++ b/test/nano.request.test.js @@ -10,21 +10,18 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:59804' -const nano = Nano({ url: COUCH_URL, cookie: true }) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) +const nano = Nano({ url: COUCH_URL }) test('check request can do GET requests - nano.request', async () => { // mocks const response = { ok: true } - const scope = nock(COUCH_URL) - .get('/db?a=1&b=2') - .reply(200, response) + mockPool + .intercept({ path: '/db?a=1&b=2' }) + .reply(200, response, JSON_HEADERS) // test GET /db?a=1&b=2 const req = { @@ -33,17 +30,21 @@ test('check request can do GET requests - nano.request', async () => { qs: { a: 1, b: 2 } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request can do POST requests - nano.request', async () => { // mocks const response = { ok: true } const doc = { _id: '_design/myddoc', a: true } - const scope = nock(COUCH_URL) - .post('/db', doc) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const req = { @@ -52,16 +53,21 @@ test('check request can do POST requests - nano.request', async () => { body: doc } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request can do PUT requests - nano.request', async () => { // mocks const response = { ok: true } - const scope = nock(COUCH_URL) - .put('/db/1', { _id: '1', a: true }) - .reply(200, response) + const doc = { _id: '1', a: true } + mockPool + .intercept({ + method: 'put', + path: '/db/1', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test PUT /db const req = { @@ -71,17 +77,19 @@ test('check request can do PUT requests - nano.request', async () => { body: { _id: '1', a: true } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request can do DELETE requests - nano.request', async () => { // mocks const response = { ok: true } - const scope = nock(COUCH_URL) - .delete('/db/mydoc') - .query({ rev: '1-123' }) - .reply(200, response) + mockPool + .intercept({ + method: 'delete', + path: '/db/mydoc?rev=1-123' + }) + .reply(200, response, JSON_HEADERS) // test DELETE /db const req = { @@ -89,19 +97,25 @@ test('check request can do DELETE requests - nano.request', async () => { db: 'db', path: 'mydoc', qs: { rev: '1-123' } - } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request can do HEAD requests - nano.request', async () => { // mocks const response = '' - const scope = nock(COUCH_URL) - .head('/db/mydoc') - .reply(200, '') + const headers = { + 'content-type': 'text/plain', + myheader: '2442' + } + mockPool + .intercept({ + method: 'head', + path: '/db/mydoc' + }) + .reply(200, response, { headers }) // test HEAD /db/mydoc const req = { @@ -110,16 +124,16 @@ test('check request can do HEAD requests - nano.request', async () => { path: 'mydoc' } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) -test('check request can do GET requests with callback - nano.request', () => { +test('check request can do GET requests with callback - nano.request', async () => { // mocks const response = { ok: true } - const scope = nock(COUCH_URL) - .get('/db?a=1&b=2') - .reply(200, response) + mockPool + .intercept({ path: '/db?a=1&b=2' }) + .reply(200, response, JSON_HEADERS) // test GET /db?a=1&b=2 const req = { @@ -127,25 +141,25 @@ test('check request can do GET requests with callback - nano.request', () => { db: 'db', qs: { a: 1, b: 2 } } - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { nano.request(req, (err, data) => { - expect(err).toBe(null) - expect(data).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.deepEqual(data, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) }) -test('check request can do failed GET requests with callback - nano.request', () => { +test('check request can do failed GET requests with callback - nano.request', async () => { // mocks const response = { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .get('/db/a') - .reply(404, response) + mockPool + .intercept({ path: '/db/a' }) + .reply(404, response, JSON_HEADERS) // test GET /db/a const req = { @@ -153,10 +167,10 @@ test('check request can do failed GET requests with callback - nano.request', () db: 'db', path: 'a' } - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { nano.request(req, (err, data) => { - expect(err).not.toBe(null) - expect(scope.isDone()).toBe(true) + assert.notEqual(err, null) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -166,10 +180,9 @@ test('check request formats keys properly - nano.request', async () => { // mocks const response = { ok: true } const arr = ['a', 'b', 'c'] - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .query({ keys: JSON.stringify(arr) }) - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?keys=["a","b","c"]' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs?keys=[] const req = { @@ -179,18 +192,17 @@ test('check request formats keys properly - nano.request', async () => { qs: { keys: arr } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request formats startkey properly - nano.request', async () => { // mocks const response = { ok: true } const val = 'x' - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .query({ startkey: JSON.stringify(val) }) - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?startkey="x"' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs?startkey= const req = { @@ -200,18 +212,17 @@ test('check request formats startkey properly - nano.request', async () => { qs: { startkey: val } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request formats start_key properly - nano.request', async () => { // mocks const response = { ok: true } const val = 'x' - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .query({ start_key: JSON.stringify(val) }) - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?start_key="x"' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs?start_key= const req = { @@ -221,18 +232,17 @@ test('check request formats start_key properly - nano.request', async () => { qs: { start_key: val } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request formats endkey properly - nano.request', async () => { // mocks const response = { ok: true } const val = 'x' - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .query({ endkey: JSON.stringify(val) }) - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?endkey="x"' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs?endkey= const req = { @@ -242,18 +252,17 @@ test('check request formats endkey properly - nano.request', async () => { qs: { endkey: val } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request formats end_key properly - nano.request', async () => { // mocks const response = { ok: true } const val = 'x' - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .query({ end_key: JSON.stringify(val) }) - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?end_key="x"' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs?end_key= const req = { @@ -263,18 +272,17 @@ test('check request formats end_key properly - nano.request', async () => { qs: { end_key: val } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request formats key properly - nano.request', async () => { // mocks const response = { ok: true } const val = 'x' - const scope = nock(COUCH_URL) - .get('/db/_all_docs') - .query({ key: JSON.stringify(val) }) - .reply(200, response) + mockPool + .intercept({ path: '/db/_all_docs?key="x"' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_all_docs?key= const req = { @@ -284,15 +292,15 @@ test('check request formats key properly - nano.request', async () => { qs: { key: val } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request can do 500s - nano.request', async () => { // mocks const errorMessage = 'Internal server error' - const scope = nock(COUCH_URL) - .get('/db?a=1&b=2') + mockPool + .intercept({ path: '/db?a=1&b=2' }) .reply(500, errorMessage) // test GET /db?a=1&b=2 @@ -301,15 +309,15 @@ test('check request can do 500s - nano.request', async () => { db: 'db', qs: { a: 1, b: 2 } } - await expect(nano.request(req)).rejects.toThrow(errorMessage) - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.request(req), { message: 'couch returned 500' }) + mockAgent.assertNoPendingInterceptors() }) -test('check request can do 500s with callback - nano.request', () => { +test('check request can do 500s with callback - nano.request', async () => { // mocks const errorMessage = 'Internal server error' - const scope = nock(COUCH_URL) - .get('/db?a=1&b=2') + mockPool + .intercept({ path: '/db?a=1&b=2' }) .reply(500, errorMessage) // test GET /db?a=1&b=2 @@ -319,10 +327,10 @@ test('check request can do 500s with callback - nano.request', () => { qs: { a: 1, b: 2 } } - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { nano.request(req, (err, data) => { - expect(err).not.toBe(null) - expect(scope.isDone()).toBe(true) + assert.notEqual(err, null) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -343,17 +351,17 @@ test('check request handle empty parameter list - nano.request', async () => { name: 'The Apache Software Foundation' } } - const scope = nock(COUCH_URL) - .get('/') - .reply(200, response) + mockPool + .intercept({ path: '/' }) + .reply(200, response, JSON_HEADERS) // test GET / const p = await nano.request() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) -test('check request handle empty parameter list (callback) - nano.request', () => { +test('check request handle empty parameter list (callback) - nano.request', async () => { // mocks const response = { couchdb: 'Welcome', @@ -368,16 +376,16 @@ test('check request handle empty parameter list (callback) - nano.request', () = name: 'The Apache Software Foundation' } } - const scope = nock(COUCH_URL) - .get('/') - .reply(200, response) + mockPool + .intercept({ path: '/' }) + .reply(200, response, JSON_HEADERS) // test GET / - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { nano.request((err, data) => { - expect(err).toBeNull() - expect(data).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.deepEqual(data, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -395,14 +403,14 @@ test('check request handles single string parameter - nano.request', async () => active: 6727596 } } - const scope = nock(COUCH_URL) - .get('/db') - .reply(200, response) + mockPool + .intercept({ path: '/db' }) + .reply(200, response, JSON_HEADERS) // test GET / const p = await nano.request('db') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request handles cookies - nano.request', async () => { @@ -410,9 +418,21 @@ test('check request handles cookies - nano.request', async () => { const username = 'u' const password = 'p' const response = { ok: true, name: 'admin', roles: ['_admin', 'admin'] } - const scope = nock(COUCH_URL) - .post('/_session', 'name=u&password=p', { 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' }) - .reply(200, response, { 'Set-Cookie': 'AuthSession=YWRtaW46NUU0MTFBMDE6stHsxYnlDy4mYxwZEcnXHn4fm5w; Version=1; Expires=Mon, 10-Feb-2050 09:03:21 GMT; Max-Age=600; Path=/; HttpOnly' }) + mockPool + .intercept({ + method: 'post', + path: '/_session', + body: 'name=u&password=p', + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' + } + }) + .reply(200, response, { + headers: { + 'content-type': 'application/json', + 'Set-Cookie': 'AuthSession=YWRtaW46NUU0MTFBMDE6stHsxYnlDy4mYxwZEcnXHn4fm5w; Version=1; Expires=Mon, 10-Feb-2050 09:03:21 GMT; Max-Age=600; Path=/; HttpOnly' + } + }) // test GET /_uuids const req = { @@ -421,20 +441,19 @@ test('check request handles cookies - nano.request', async () => { form: { name: username, password - }, - jar: true + } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request can do GET a doc - nano.request', async () => { // mocks const response = { _id: 'docname/design', _rev: '1-123', ok: true } - const scope = nock(COUCH_URL) - .get('/db/_design/docname?a=1&b=2') - .reply(200, response) + mockPool + .intercept({ path: '/db/_design/docname?a=1&b=2' }) + .reply(200, response, JSON_HEADERS) // test GET /db?a=1&b=2 const req = { @@ -444,8 +463,8 @@ test('check request can do GET a doc - nano.request', async () => { qs: { a: 1, b: 2 } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request doesn\'t mangle bodies containing functions - nano.request', async () => { @@ -455,14 +474,18 @@ test('check request doesn\'t mangle bodies containing functions - nano.request', a: 1, views: { bytime: { - map: function () { emit(doc.ts, true) } + map: function () { emit(doc.ts, true) }.toString() } } } const response = { id: 'jfjfjf', rev: '1-123', ok: true } - const scope = nock(COUCH_URL) - .post('/db', { a: 1, views: { bytime: { map: 'function () {\n emit(doc.ts, true);\n }' } } }) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db', + body: JSON.stringify(doc) + }) + .reply(200, response, JSON_HEADERS) // test POST /db const req = { @@ -471,16 +494,21 @@ test('check request doesn\'t mangle bodies containing functions - nano.request', body: doc } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request sends user-agent header - nano.request', async () => { // mocks const response = { ok: true } - const scope = nock(COUCH_URL, { reqheaders: { 'user-agent': /^nano/ } }) - .get('/db?a=1&b=2') - .reply(200, response) + mockPool + .intercept({ + path: '/db?a=1&b=2', + headers: { + 'user-agent': /^nano/ + } + }) + .reply(200, response, JSON_HEADERS) // test GET /db?a=1&b=2 const req = { @@ -489,16 +517,21 @@ test('check request sends user-agent header - nano.request', async () => { qs: { a: 1, b: 2 } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('check request sends headers for gzipped responses - nano.request', async () => { // mocks const response = { ok: true } - const scope = nock(COUCH_URL, { reqheaders: { 'accept-encoding': /gzip/ } }) - .get('/db?a=1&b=2') - .reply(200, response) + mockPool + .intercept({ + path: '/db?a=1&b=2', + headers: { + 'accept-encoding': /gzip/ + } + }) + .reply(200, response, JSON_HEADERS) // test GET /db?a=1&b=2 const req = { @@ -507,6 +540,6 @@ test('check request sends headers for gzipped responses - nano.request', async ( qs: { a: 1, b: 2 } } const p = await nano.request(req) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.session.test.js b/test/nano.session.test.js index 7c3d1ee2..71908343 100644 --- a/test/nano.session.test.js +++ b/test/nano.session.test.js @@ -10,24 +10,21 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to check your session - GET /_session - nano.auth', async () => { // mocks const response = { ok: true, userCtx: { name: null, roles: [] }, info: { authentication_db: '_users', authentication_handlers: ['cookie', 'default'] } } - const scope = nock(COUCH_URL) - .get('/_session') - .reply(200, response) + mockPool + .intercept({ path: '/_session' }) + .reply(200, response, JSON_HEADERS) // test GET /_session const p = await nano.session() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.timeout.test.js b/test/nano.timeout.test.js deleted file mode 100644 index 8c5eaebf..00000000 --- a/test/nano.timeout.test.js +++ /dev/null @@ -1,64 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const Nano = require('..') -const COUCH_URL = 'http://localhost:59804' -const nano = Nano({ - url: COUCH_URL, - requestDefaults: { - timeout: 500 - } -}) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) - -test('check requests timeout - nano.request', async () => { - // mocks - const response = { ok: true } - nock(COUCH_URL) - .get('/db?a=1&b=2') - .delay(1000) - .reply(200, response) - - // test GET /db?a=1&b=2 - const req = { - method: 'get', - db: 'db', - qs: { a: 1, b: 2 } - } - await expect(nano.request(req)).rejects.toThrow('error happened in your connection. Reason: timeout of 500ms exceeded') -}) - -test('check request timeout (callback) - nano.request', () => { - // mocks - const response = { ok: true } - nock(COUCH_URL) - .get('/db?a=1&b=2') - .delay(1000) - .reply(200, response) - - // test GET /db?a=1&b=2 - const req = { - method: 'get', - db: 'db', - qs: { a: 1, b: 2 } - } - return new Promise((resolve, reject) => { - nano.request(req, (err, data) => { - expect(err).not.toBeNull() - resolve() - }) - }) -}) diff --git a/test/nano.updates.test.js b/test/nano.updates.test.js index eca355b9..7058fa48 100644 --- a/test/nano.updates.test.js +++ b/test/nano.updates.test.js @@ -10,10 +10,12 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') + const response = { results: [ { @@ -39,41 +41,37 @@ const errResponse = { reason: 'Database does not exist.' } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to fetch db updates - GET /_db_updates - nano.updates', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_db_updates') - .reply(200, response) + mockPool + .intercept({ path: '/_db_updates' }) + .reply(200, response, JSON_HEADERS) // test GET /_db_updates const p = await nano.updates() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch db updates with options - GET /_db_updates - nano.updates', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_db_updates?timeout=10000') - .reply(200, response) + mockPool + .intercept({ path: '/_db_updates?timeout=10000' }) + .reply(200, response, JSON_HEADERS) // test GET /_db_updates const p = await nano.updates({ timeout: 10000 }) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should handle 404 - GET /_db_updates - nano.updates', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/_db_updates') - .reply(404, errResponse) + mockPool + .intercept({ path: '/_db_updates' }) + .reply(404, errResponse, JSON_HEADERS) // test GET /_db_updates - await expect(nano.db.updates()).rejects.toThrow('Database does not exist.') - expect(scope.isDone()).toBe(true) + await assert.rejects(nano.db.updates(), { message: 'Database does not exist.' }) + mockAgent.assertNoPendingInterceptors() }) diff --git a/test/nano.use.test.js b/test/nano.use.test.js index ba730447..d867bbd7 100644 --- a/test/nano.use.test.js +++ b/test/nano.use.test.js @@ -10,22 +10,23 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' -const nano = Nano(COUCH_URL) +const nano = Nano('http://myurl.com') test('should be able to use a database - nano.db.use', () => { const db = nano.db.use('db1') - expect(typeof db).toBe('object') - expect(typeof db.get).toBe('function') - expect(typeof db.replication).toBe('object') - expect(db.config.db).toBe('db1') + assert.equal(typeof db, 'object') + assert.equal(typeof db.get, 'function') + assert.equal(typeof db.replication, 'object') + assert.equal(db.config.db, 'db1') }) test('should be able to use a database - nano.use', () => { const db = nano.use('db2') - expect(typeof db).toBe('object') - expect(typeof db.get).toBe('function') - expect(typeof db.replication).toBe('object') - expect(db.config.db).toBe('db2') + assert.equal(typeof db, 'object') + assert.equal(typeof db.get, 'function') + assert.equal(typeof db.replication, 'object') + assert.equal(db.config.db, 'db2') }) diff --git a/test/nano.uuids.test.js b/test/nano.uuids.test.js index f2ad76e2..01f14c92 100644 --- a/test/nano.uuids.test.js +++ b/test/nano.uuids.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to fetch uuids - GET /_uuids - nano.uuids', async () => { // mocks @@ -26,14 +23,14 @@ test('should be able to fetch uuids - GET /_uuids - nano.uuids', async () => { 'c42ddf1272c7d05b2dc45b696200145f' ] } - const scope = nock(COUCH_URL) - .get('/_uuids?count=1') - .reply(200, response) + mockPool + .intercept({ path: '/_uuids?count=1' }) + .reply(200, response, JSON_HEADERS) // test GET /_uuids const p = await nano.uuids() - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch more uuids - GET /_uuids?count=3 - nano.uuids', async () => { @@ -45,33 +42,33 @@ test('should be able to fetch more uuids - GET /_uuids?count=3 - nano.uuids', as 'c42ddf1272c7d05b2dc45b69620028cf' ] } - const scope = nock(COUCH_URL) - .get('/_uuids?count=3') - .reply(200, response) + mockPool + .intercept({ path: '/_uuids?count=3' }) + .reply(200, response, JSON_HEADERS) // test GET /_uuids const p = await nano.uuids(3) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) -test('should be able to fetch uuids callback - GET /_uuids - nano.uuids', () => { +test('should be able to fetch uuids callback - GET /_uuids - nano.uuids', async () => { // mocks const response = { uuids: [ 'c42ddf1272c7d05b2dc45b696200145f' ] } - const scope = nock(COUCH_URL) - .get('/_uuids?count=1') - .reply(200, response) + mockPool + .intercept({ path: '/_uuids?count=1' }) + .reply(200, response, JSON_HEADERS) // test GET /_uuids - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { nano.uuids((err, data) => { - expect(err).toBe(null) - expect(data).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.deepEqual(data, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/notnocked.test.js b/test/notnocked.test.js index 3bf64e65..f017d2f5 100644 --- a/test/notnocked.test.js +++ b/test/notnocked.test.js @@ -10,8 +10,10 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') const Nano = require('..') -const COUCH_URL = 'http://admin:admin@localhost:5984' +const COUCH_URL = 'http://admin:admin@127.0.0.1:5984' const nano = Nano(COUCH_URL) const dbName = 'notnocked' + new Date().getTime() let db @@ -20,7 +22,7 @@ const emit = (k, v) => { } test('should be able to create a database string', () => { - expect(typeof dbName).toBe('string') + assert(typeof dbName, 'string') }) // this section only runs if the TRAVIS environment variable is set. @@ -48,15 +50,15 @@ if (process.env.TRAVIS) { test('should be able to get database info - nano.db.bulk', async () => { const info = await db.info(dbName) - expect(info.doc_count).toBe(7) + assert.equal(info.doc_count, 7) }) test('should be able to delete a document', async () => { const doc = await db.get('dummy') await db.destroy('dummy', doc._rev) const info = await db.info(dbName) - expect(info.doc_count).toBe(6) - expect(info.doc_del_count).toBe(1) + assert.equal(info.doc_count, 6) + assert.equal(info.doc_del_count, 1) }) test('should be able to update a document', async () => { @@ -64,13 +66,13 @@ if (process.env.TRAVIS) { doc.newfield = true await db.insert(doc) const info = await db.info(dbName) - expect(info.doc_count).toBe(6) + assert.equal(info.doc_count, 6) }) test('should be able to list documents in a database', async () => { const data = await db.list({ limit: 1, descending: true }) - expect(data.rows.length).toBe(1) - expect(data.rows[0].id).toBe('snowbell') + assert.equal(data.rows.length, 1) + assert.equal(data.rows[0].id, 'snowbell') }) test('should be able to create a view', async () => { @@ -102,7 +104,7 @@ if (process.env.TRAVIS) { { id: 'crookshanks', key: 2004, value: 'Crookshanks' } ] } - expect(response).toStrictEqual(data) + assert.deepEqual(response, data) }) test('should be able to destroy a database - nano.db.destroy', async () => { diff --git a/test/partition.find.test.js b/test/partition.find.test.js index 806f9479..d5e96ac5 100644 --- a/test/partition.find.test.js +++ b/test/partition.find.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to query a partitioned index - POST /db/_partition/partition/_find - db.partitionedFind', async () => { // mocks @@ -38,15 +35,19 @@ test('should be able to query a partitioned index - POST /db/_partition/partitio { name: 'Susan', date: '2019-01-03', orderid: '8523' } ] } - const scope = nock(COUCH_URL) - .post('/db/_partition/partition/_find', query) - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_partition/partition/_find', + body: JSON.stringify(query) + }) + .reply(200, response, JSON_HEADERS) // test POST /db/_partition/partition/_find const db = nano.db.use('db') const p = await db.partitionedFind('partition', query) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should handle 404 - POST /db/_partition/partition/_find - db.partitionedFind', async () => { @@ -60,27 +61,31 @@ test('should handle 404 - POST /db/_partition/partition/_find - db.partitionedFi error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .post('/db/_partition/partition/_find', query) - .reply(404, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_partition/partition/_find', + body: JSON.stringify(query) + }) + .reply(404, response, JSON_HEADERS) // test POST /db/_partition/partition/_find const db = nano.db.use('db') - await expect(db.partitionedFind('partition', query)).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.partitionedFind('partition', query), { message: 'missing' }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing query - db.partitionedFind', async () => { const db = nano.db.use('db') - await expect(db.partitionedFind()).rejects.toThrow('Invalid parameters') - await expect(db.partitionedFind('partition', 'susan')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.partitionedFind(), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedFind('partition', 'susan'), { message: 'Invalid parameters' }) }) test('should detect missing query (callback) - db.partitionedFind', async () => { const db = nano.db.use('db') - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionedFind(undefined, '', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/partition.findAsStream.test.js b/test/partition.findAsStream.test.js index 9e53c908..4df17487 100644 --- a/test/partition.findAsStream.test.js +++ b/test/partition.findAsStream.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should get a queried streamed list of documents from a partition- POST /db/_partition/partition/_find - db.partitionedFindAsStream', async () => { // mocks @@ -38,22 +35,26 @@ test('should get a queried streamed list of documents from a partition- POST /db { name: 'Susan', date: '2019-01-03', orderid: '8523' } ] } - const scope = nock(COUCH_URL) - .post('/db/_partition/partition/_find') - .reply(200, response) + mockPool + .intercept({ + method: 'post', + path: '/db/_partition/partition/_find', + body: JSON.stringify(query) + }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test /db/_partition/partition/_find const db = nano.db.use('db') const s = db.partitionedFindAsStream('partition', query) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/partition.info.test.js b/test/partition.info.test.js index 2d9e8f5c..7a4feb65 100644 --- a/test/partition.info.test.js +++ b/test/partition.info.test.js @@ -10,11 +10,13 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) const db = nano.db.use('db') -const nock = require('nock') + const response = { db_name: 'db', sizes: { @@ -26,34 +28,30 @@ const response = { doc_del_count: 0 } -afterEach(() => { - nock.cleanAll() -}) - test('should be able to fetch partition info info - GET /db/_partition/partition - db.partitionInfo', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/partition') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/partition const p = await db.partitionInfo('partition') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to fetch partition info info (callback) - GET /db/_partition/partition - db.partitionInfo', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/partition') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/partition - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionInfo('partition', (err, data) => { - expect(err).toBeNull() - expect(data).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.deepEqual(data, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -61,27 +59,28 @@ test('should be able to fetch partition info info (callback) - GET /db/_partitio test('should handle missing database - PUT /db - nano.db.create', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/partition') - .reply(404, { - error: 'not_found', - reason: 'Database does not exist.' - }) + const response = { + error: 'not_found', + reason: 'Database does not exist.' + } + mockPool + .intercept({ path: '/db/_partition/partition' }) + .reply(404, response, JSON_HEADERS) // test GET /db/_partition/partition - await expect(db.partitionInfo('partition')).rejects.toThrow('Database does not exist') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.partitionInfo('partition'), { message: response.reason }) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt info fetch with missing parameters - nano.db.get', async () => { - await expect(db.partitionInfo()).rejects.toThrowError('Invalid parameters') - await expect(db.partitionInfo('')).rejects.toThrowError('Invalid parameters') + await assert.rejects(db.partitionInfo(), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionInfo(''), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - nano.db.get', async () => { - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionInfo(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/partition.list.test.js b/test/partition.list.test.js index 6e970715..05b55082 100644 --- a/test/partition.list.test.js +++ b/test/partition.list.test.js @@ -10,11 +10,13 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) const db = nano.db.use('db') -const nock = require('nock') + const response = { total_rows: 1215, offset: 0, @@ -57,20 +59,16 @@ const response = { ] } -afterEach(() => { - nock.cleanAll() -}) - test('should be list documents form a partition - GET /db/_partition/_all_docs - db.partitionedList', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_all_docs') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_all_docs' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/_all_docs const p = await db.partitionedList('partition') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be list documents form a partition with opts - GET /db/_partition/_all_docs - db.partitionedList', async () => { @@ -94,28 +92,28 @@ test('should be list documents form a partition with opts - GET /db/_partition/_ } ] } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_all_docs?limit=1&include_docs=true') - .reply(200, optsResponse) + mockPool + .intercept({ path: '/db/_partition/partition/_all_docs?limit=1&include_docs=true' }) + .reply(200, optsResponse, JSON_HEADERS) // test GET /db/_partition/_all_docs const p = await db.partitionedList('partition', { limit: 1, include_docs: true }) - expect(p).toStrictEqual(optsResponse) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, optsResponse) + mockAgent.assertNoPendingInterceptors() }) test('should be able to list partition docs (callback) - GET /db/_partition/_all_docs - db.partitionedList', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_all_docs') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_all_docs' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/_all_docs - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionedList('partition', (err, data) => { - expect(err).toBeNull() - expect(data).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.deepEqual(data, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -123,16 +121,16 @@ test('should be able to list partition docs (callback) - GET /db/_partition/_all test('should escape unusual characters - GET /db/_partition/a+b/_all_docs - db.partitionedList', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/a%2Bb/_all_docs') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/a%2Bb/_all_docs' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/_all_docs - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionedList('a+b', (err, data) => { - expect(err).toBeNull() - expect(data).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.equal(err, null) + assert.deepEqual(data, response) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -140,27 +138,28 @@ test('should escape unusual characters - GET /db/_partition/a+b/_all_docs - db.p test('should handle missing database - GET /db/_partition/_all_docs - db.partitionedList', async () => { // mocks - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_all_docs') - .reply(404, { - error: 'not_found', - reason: 'Database does not exist.' - }) + const errResponse = { + error: 'not_found', + reason: 'Database does not exist.' + } + mockPool + .intercept({ path: '/db/_partition/partition/_all_docs' }) + .reply(404, errResponse, JSON_HEADERS) // test GET /db/_partition/_all_docs - await expect(db.partitionedList('partition')).rejects.toThrow('Database does not exist') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.partitionedList('partition'), { message: errResponse.reason }) + mockAgent.assertNoPendingInterceptors() }) test('should not attempt info fetch with missing parameters - db.partitionedList', async () => { - await expect(db.partitionedList()).rejects.toThrowError('Invalid parameters') - await expect(db.partitionedList('')).rejects.toThrowError('Invalid parameters') + await assert.rejects(db.partitionedList(), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedList(''), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.partitionedList', async () => { - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionedList(undefined, (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/partition.listAsStream.test.js b/test/partition.listAsStream.test.js index b45c5be5..9313fa18 100644 --- a/test/partition.listAsStream.test.js +++ b/test/partition.listAsStream.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should get a streamed list of documents from a partition- GET /db/_partition/partition/_all_docs - db.partitionedListAsStream', async () => { // mocks @@ -48,22 +45,22 @@ test('should get a streamed list of documents from a partition- GET /db/_partiti } ] } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_all_docs') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_all_docs' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_partition/_all_docs const db = nano.db.use('db') const s = db.partitionedListAsStream('partition') - expect(typeof s).toBe('object') + assert(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) @@ -90,22 +87,22 @@ test('should get a streamed list of documents from a partition with opts- GET /d } ] } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_all_docs?limit=1&include_docs=true') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_all_docs?limit=1&include_docs=true' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_partition/_all_docs const db = nano.db.use('db') const s = db.partitionedListAsStream('partition', { limit: 1, include_docs: true }) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/partition.search.test.js b/test/partition.search.test.js index a54ed368..ed8efbf8 100644 --- a/test/partition.search.test.js +++ b/test/partition.search.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to access a partitioned search index - GET /db/_partition/partition/_design/ddoc/_search/searchname - db.partitionedSearch', async () => { // mocks @@ -29,15 +26,15 @@ test('should be able to access a partitioned search index - GET /db/_partition/p ] } const params = { q: '*:*' } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_search/searchname?q=*:*') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_search/searchname?q=*:*' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/partition/_design/ddoc/_search/searchname const db = nano.db.use('db') const p = await db.partitionedSearch('partition', 'ddoc', 'searchname', params) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.partitionedSearch', async () => { @@ -47,31 +44,31 @@ test('should be able to handle 404 - db.partitionedSearch', async () => { reason: 'missing' } const params = { q: '*:*' } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_search/searchname?q=*:*') - .reply(404, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_search/searchname?q=*:*' }) + .reply(404, response, JSON_HEADERS) // test GET /db/_partition/partition/_design/ddoc/_search/searchname const db = nano.db.use('db') - await expect(db.partitionedSearch('partition', 'ddoc', 'searchname', params)).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.partitionedSearch('partition', 'ddoc', 'searchname', params), { message: response.reason }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.partitionedSearch', async () => { const db = nano.db.use('db') - await expect(db.partitionedSearch()).rejects.toThrow('Invalid parameters') - await expect(db.partitionedSearch('partition', 'susan')).rejects.toThrow('Invalid parameters') - await expect(db.partitionedSearch('partition', 'susan', '')).rejects.toThrow('Invalid parameters') - await expect(db.partitionedSearch('partition', '', 'susan')).rejects.toThrow('Invalid parameters') - await expect(db.partitionedSearch('partition', 'susan', '', undefined)).rejects.toThrow('Invalid parameters') - await expect(db.partitionedSearch('partition', '', 'susan')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.partitionedSearch(), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedSearch('partition', 'susan'), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedSearch('partition', 'susan', ''), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedSearch('partition', '', 'susan'), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedSearch('partition', 'susan', '', undefined), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedSearch('partition', '', 'susan'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.partitionedSearch', async () => { const db = nano.db.use('db') - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionedSearch('', '', '', '', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/partition.searchAsStream.test.js b/test/partition.searchAsStream.test.js index ec90bc05..f53a724b 100644 --- a/test/partition.searchAsStream.test.js +++ b/test/partition.searchAsStream.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should get a searched streamed list of documents from a partition- GET /db/_partition/partition/_design/ddoc/_search/searchname - db.partitionedSearchAsStream', async () => { // mocks @@ -29,22 +26,22 @@ test('should get a searched streamed list of documents from a partition- GET /db ] } const params = { q: '*:*' } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_search/searchname?q=*:*') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_search/searchname?q=*:*' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_partition/partition/_design/ddoc/_search/searchname const db = nano.db.use('db') const s = db.partitionedSearchAsStream('partition', 'ddoc', 'searchname', params) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) diff --git a/test/partition.view.test.js b/test/partition.view.test.js index 4b532fd7..9a5cf9e6 100644 --- a/test/partition.view.test.js +++ b/test/partition.view.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should be able to access a partitioned view index - GET /db/_partition/partition/_design/ddoc/_view/viewname - db.partitionedView', async () => { // mocks @@ -26,15 +23,15 @@ test('should be able to access a partitioned view index - GET /db/_partition/par { key: null, value: 23515 } ] } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_view/viewname') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_view/viewname' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/partition/_design/ddoc/_view/viewname const db = nano.db.use('db') const p = await db.partitionedView('partition', 'ddoc', 'viewname') - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to access a partitioned view index with opts - GET /db/_partition/partition/_design/ddoc/_view/viewname - db.partitionedView', async () => { @@ -50,15 +47,15 @@ test('should be able to access a partitioned view index with opts - GET /db/_par endkey: 'b', limit: 1 } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_view/viewname?reduce=false&startkey=%22a%22&endkey=%22b%22&limit=1') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_view/viewname?reduce=false&startkey=%22a%22&endkey=%22b%22&limit=1' }) + .reply(200, response, JSON_HEADERS) // test GET /db/_partition/partition/_design/ddoc/_view/viewname const db = nano.db.use('db') const p = await db.partitionedView('partition', 'ddoc', 'viewname', params) - expect(p).toStrictEqual(response) - expect(scope.isDone()).toBe(true) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should be able to handle 404 - db.partitionedView', async () => { @@ -67,31 +64,31 @@ test('should be able to handle 404 - db.partitionedView', async () => { error: 'not_found', reason: 'missing' } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_view/viewname') - .reply(404, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_view/viewname' }) + .reply(404, response, JSON_HEADERS) // test GET /db/_partition/partition/_design/ddoc/_view/viewname const db = nano.db.use('db') - await expect(db.partitionedView('partition', 'ddoc', 'viewname')).rejects.toThrow('missing') - expect(scope.isDone()).toBe(true) + await assert.rejects(db.partitionedView('partition', 'ddoc', 'viewname'), { message: response.reason }) + mockAgent.assertNoPendingInterceptors() }) test('should detect missing parameters - db.partitionedView', async () => { const db = nano.db.use('db') - await expect(db.partitionedView()).rejects.toThrow('Invalid parameters') - await expect(db.partitionedView('partition', 'susan')).rejects.toThrow('Invalid parameters') - await expect(db.partitionedView('partition', 'susan', '')).rejects.toThrow('Invalid parameters') - await expect(db.partitionedView('partition', '', 'susan')).rejects.toThrow('Invalid parameters') - await expect(db.partitionedView('partition', 'susan', '', undefined)).rejects.toThrow('Invalid parameters') - await expect(db.partitionedView('partition', '', 'susan')).rejects.toThrow('Invalid parameters') + await assert.rejects(db.partitionedView(), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedView('partition', 'susan'), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedView('partition', 'susan', ''), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedView('partition', '', 'susan'), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedView('partition', 'susan', '', undefined), { message: 'Invalid parameters' }) + await assert.rejects(db.partitionedView('partition', '', 'susan'), { message: 'Invalid parameters' }) }) test('should detect missing parameters (callback) - db.partitionedView', async () => { const db = nano.db.use('db') - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { db.partitionedView('', '', '', '', (err, data) => { - expect(err).not.toBeNull() + assert.notEqual(err, null) resolve() }) }) diff --git a/test/partition.viewAsStream.test.js b/test/partition.viewAsStream.test.js index 97663dbe..1b15805b 100644 --- a/test/partition.viewAsStream.test.js +++ b/test/partition.viewAsStream.test.js @@ -10,14 +10,11 @@ // License for the specific language governing permissions and limitations under // the License. +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') const Nano = require('..') -const COUCH_URL = 'http://localhost:5984' const nano = Nano(COUCH_URL) -const nock = require('nock') - -afterEach(() => { - nock.cleanAll() -}) test('should get a streamed list of documents from a view from partition - GET /db/_partition/partition/_design/ddoc/_view/viewname - db.partitionedViewAsStream', async () => { // mocks @@ -32,22 +29,22 @@ test('should get a streamed list of documents from a view from partition - GET endkey: 'b', limit: 1 } - const scope = nock(COUCH_URL) - .get('/db/_partition/partition/_design/ddoc/_view/viewname?reduce=false&startkey=%22a%22&endkey=%22b%22&limit=1') - .reply(200, response) + mockPool + .intercept({ path: '/db/_partition/partition/_design/ddoc/_view/viewname?reduce=false&startkey=%22a%22&endkey=%22b%22&limit=1' }) + .reply(200, response, JSON_HEADERS) - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { // test GET /db/_partition/partition/_design/ddoc/_view/viewnameGET /db/_all_docs const db = nano.db.use('db') const s = db.partitionedViewAsStream('partition', 'ddoc', 'viewname', params) - expect(typeof s).toBe('object') + assert.equal(typeof s, 'object') let buffer = '' s.on('data', (chunk) => { buffer += chunk.toString() }) s.on('end', () => { - expect(buffer).toBe(JSON.stringify(response)) - expect(scope.isDone()).toBe(true) + assert.equal(buffer, JSON.stringify(response)) + mockAgent.assertNoPendingInterceptors() resolve() }) }) From fffb593c49fa4531c5eff46a7c10cba758c57e4e Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 12 Dec 2022 14:03:45 +0000 Subject: [PATCH 02/40] fix cookie renewal bug --- lib/cookiejar.js | 45 +++++++++++++++++++++++++++++++++ lib/nano.js | 3 +-- test/nano.auth.test.js | 57 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 lib/cookiejar.js diff --git a/lib/cookiejar.js b/lib/cookiejar.js new file mode 100644 index 00000000..270a6690 --- /dev/null +++ b/lib/cookiejar.js @@ -0,0 +1,45 @@ +const tough = require('tough-cookie') +const cookieJar = new tough.CookieJar() + +// this is a monkey-patch of toughcookie's cookiejar, as it doesn't handle +// the refreshing of cookies from CouchDB properly +// see https://github.com/salesforce/tough-cookie/issues/154 +cookieJar.cloudantPatch = true +// Replace the store's updateCookie function with one that applies a patch to newCookie +const originalUpdateCookieFn = cookieJar.store.updateCookie +cookieJar.store.updateCookie = function (oldCookie, newCookie, cb) { + // Add current time as an update timestamp to the newCookie + newCookie.cloudantPatchUpdateTime = new Date() + // Replace the cookie's expiryTime function with one that uses cloudantPatchUpdateTime + // in place of creation time to check the expiry. + const originalExpiryTimeFn = newCookie.expiryTime + newCookie.expiryTime = function (now) { + // The original expiryTime check is relative to a time in this order: + // 1. supplied now argument + // 2. this.creation (original cookie creation time) + // 3. current time + // This patch replaces 2 with an expiry check relative to the cloudantPatchUpdateTime if set instead of + // the creation time by passing it as the now argument. + return originalExpiryTimeFn.call( + newCookie, + newCookie.cloudantPatchUpdateTime || now + ) + } + // Finally delegate back to the original update function or the fallback put (which is set by Cookie + // when an update function is not present on the store). Since we always set an update function for our + // patch we need to also provide that fallback. + if (originalUpdateCookieFn) { + originalUpdateCookieFn.call( + cookieJar.store, + oldCookie, + newCookie, + cb + ) + } else { + cookieJar.store.putCookie(newCookie, cb) + } +} +module.exports = { + tough, + cookieJar +} diff --git a/lib/nano.js b/lib/nano.js index 1608cbdb..7fc46c67 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -14,8 +14,7 @@ const { URL } = require('url') const { Readable } = require('node:stream') const assert = require('assert') -const tough = require('tough-cookie') -const cookieJar = new tough.CookieJar() +const { tough, cookieJar } = require('./cookiejar.js') const stream = require('stream') const pkg = require('../package.json') const undici = require('undici') diff --git a/test/nano.auth.test.js b/test/nano.auth.test.js index 817b232b..8a24acb4 100644 --- a/test/nano.auth.test.js +++ b/test/nano.auth.test.js @@ -54,3 +54,60 @@ test('should be able to authenticate - POST /_session - nano.auth', async () => assert.deepEqual(q, ['a']) mockAgent.assertNoPendingInterceptors() }) + +test('should be able to handle cookie refresh - POST /_session - nano.auth', async () => { + // mocks + const username = 'u' + const password = 'p' + const response = { ok: true, name: 'admin', roles: ['_admin', 'admin'] } + const c1 = 'AuthSession=YWRtaW46NUU0MTFBMDE6stHsxYnlDy4mYxwZEcnXHn4fm5w' + const cookie1 = `${c1}; Version=1; Expires=Mon, 10-Feb-2050 09:03:21 GMT; Max-Age=600; Path=/; HttpOnly` + const c2 = 'AuthSession=DE6stHsxYnlDy4YWRtaW46NUU0MTFBMmYxwZEcnXHn4fm5w' + const cookie2 = `${c2}; Version=1; Expires=Mon, 10-Feb-2050 09:05:21 GMT; Max-Age=600; Path=/; HttpOnly` + mockPool + .intercept({ + method: 'post', + path: '/_session', + body: 'name=u&password=p', + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' + } + }) + .reply(200, response, { + headers: { + 'content-type': 'application/json', + 'Set-Cookie': cookie1 + } + }) + mockPool + .intercept({ + path: '/_all_dbs', + headers: { + cookie: c1 + } + }) + .reply(200, ['a'], { + headers: { + 'content-type': 'application/json', + 'Set-Cookie': cookie2 + } + }) + mockPool + .intercept({ + path: '/_all_dbs', + headers: { + cookie: c2 + } + }) + .reply(200, ['a'], JSON_HEADERS) + + // test POST /_session + const p1 = await nano.auth(username, password) + assert.deepEqual(p1, response) + const p2 = await nano.db.list() + assert.deepEqual(p2, ['a']) + const p3 = await nano.db.list() + assert.deepEqual(p3, ['a']) + mockAgent.assertNoPendingInterceptors() +}) + From 5cbf072ce37248d7b17dadfc0777375a1be5f1b7 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 13 Dec 2022 09:03:03 +0000 Subject: [PATCH 03/40] removed unwanted request/axios code --- lib/nano.js | 224 +++++++++++++++-------------------------- test/nano.auth.test.js | 1 - 2 files changed, 81 insertions(+), 144 deletions(-) diff --git a/lib/nano.js b/lib/nano.js index 7fc46c67..aa7845fc 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -147,15 +147,6 @@ module.exports = exports = function dbScope (cfg) { statusCode }, response.headers) if (!response.status) { - // if (axios.isCancel(response)) { - // if (resolve) { - // resolve('canceled') - // } - // if (callback) { - // callback(null, 'canceled', responseHeaders) - // } - // return - // } response.statusText = response.cause.toString() log({ err: 'socket', body, headers: responseHeaders }) if (reject) { @@ -173,12 +164,6 @@ module.exports = exports = function dbScope (cfg) { delete responseHeaders.server delete responseHeaders['content-length'] - /* if (opts.dontParse) { - parsed = body - } else { - try { parsed = JSON.parse(body) } catch (err) { parsed = body } - } */ - if (statusCode >= 200 && statusCode < 400) { log({ err: null, body, headers: responseHeaders }) const ct = response.headers.get('content-type') @@ -253,13 +238,8 @@ module.exports = exports = function dbScope (cfg) { const streamResponseHandler = function (response, req, stream) { const statusCode = response.status || (response.response && response.response.status) || 500 - if (response.isAxiosError && response.response) { - response = response.response - } const message = response.statusText - scrubRequest(req) - const responseHeaders = Object.assign({ uri: req.url, statusCode @@ -287,120 +267,111 @@ module.exports = exports = function dbScope (cfg) { callback = opts opts = { path: '' } } - if (typeof opts === 'string') { opts = { path: opts } } - if (!opts) { opts = { path: '' } callback = null } - const qs = Object.assign({}, opts.qs) + // the building blocks of the request + let body, uri + // construct headers object to be passed in the request const headers = { // 'content-type': 'application/json', accept: 'application/json', 'user-agent': `${pkg.name}/${pkg.version} (Node.js ${process.version})`, 'Accept-Encoding': 'deflate, gzip' } - - const req = Object.assign({ - method: (opts.method || 'GET'), - headers, - uri: cfg.plainURL - }, { - headers: Object.assign(headers, cfg.headers ? cfg.headers : {}) - }) + Object.assign(headers, cfg.headers ? cfg.headers : {}) if (!headers['content-type']) { headers['content-type'] = 'application/json' } - // https://github.com/mikeal/request#requestjar - // const isJar = opts.jar || cfg.jar || (cfg.requestDefaults && cfg.requestDefaults.jar) + // prevent bugs where people set encoding when piping + if (opts.encoding !== undefined) { + // req.encoding = opts.encoding + delete headers['content-type'] + delete headers.accept + } - if (opts.signal) { - req.signal = opts.signal + if (opts.contentType) { + headers['content-type'] = opts.contentType + delete headers.accept } - // if (isJar) { - // req.jar = cookieJar - // req.withCredentials = true - // } + if (opts.accept) { + headers.accept = opts.accept + } - // http://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing - if (opts.db) { - req.uri = urlResolveFix(req.uri, encodeURIComponent(opts.db)) + // http://guide.couchdb.org/draft/security.html#cookies + if (cfg.cookie) { + headers['X-CouchDB-WWW-Authenticate'] = 'Cookie' + headers.cookie = cfg.cookie } + // form submission + if (opts.form) { + headers['content-type'] = + 'application/x-www-form-urlencoded; charset=utf-8' + body = new URLSearchParams(opts.form) + } + + // multipart requests if (opts.multipart) { // generate the multipart/related body, header and boundary to // upload multiple binary attachments in one request const mp = new MultiPartFactory(opts.multipart) - opts.contentType = mp.header - req.body = mp.data + headers['content-type'] = mp.header + body = mp.data } - req.headers = Object.assign(req.headers, opts.headers, cfg.defaultHeaders) + // construct the URL + const method = opts.method ? opts.method.toLowerCase() : 'get' + uri = cfg.plainURL + if (opts.db) { + uri = urlResolveFix(uri, encodeURIComponent(opts.db)) + } + // http://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing if (opts.path) { - if (!req.uri.endsWith('/')) { - req.uri += '/' + if (!uri.endsWith('/')) { + uri += '/' } - req.uri += opts.path + uri += opts.path } else if (opts.doc) { if (!/^_design|_local/.test(opts.doc)) { // http://wiki.apache.org/couchdb/HTTP_Document_API#Naming.2FAddressing - req.uri += '/' + encodeURIComponent(opts.doc) + uri += '/' + encodeURIComponent(opts.doc) } else { // http://wiki.apache.org/couchdb/HTTP_Document_API#Document_IDs - req.uri += '/' + opts.doc + uri += '/' + opts.doc } // http://wiki.apache.org/couchdb/HTTP_Document_API#Attachments if (opts.att) { - req.uri += '/' + opts.att + uri += '/' + opts.att } } - // prevent bugs where people set encoding when piping - if (opts.encoding !== undefined) { - req.encoding = opts.encoding - delete req.headers['content-type'] - delete req.headers.accept - } - - if (opts.contentType) { - req.headers['content-type'] = opts.contentType - delete req.headers.accept - } - - if (opts.accept) { - req.headers.accept = opts.accept - } - - // http://guide.couchdb.org/draft/security.html#cookies - if (cfg.cookie) { - req.headers['X-CouchDB-WWW-Authenticate'] = 'Cookie' - req.headers.cookie = cfg.cookie - } - // http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options - if (typeof opts.qs === 'object' && !isEmpty(opts.qs)) { + const qs = Object.assign({}, opts.qs) + if (typeof qs === 'object' && !isEmpty(qs)) { ['startkey', 'endkey', 'key', 'keys', 'start_key', 'end_key'].forEach(function (key) { - if (key in opts.qs) { - qs[key] = JSON.stringify(opts.qs[key]) + if (key in qs) { + qs[key] = JSON.stringify(qs[key]) } }) - req.qs = qs } + // HTTP request body if (opts.body) { if (Buffer.isBuffer(opts.body) || opts.dontStringify) { - req.body = opts.body + body = opts.body } else { - req.body = JSON.stringify(opts.body, function (key, value) { + body = JSON.stringify(opts.body, function (key, value) { // don't encode functions if (typeof (value) === 'function') { return value.toString() @@ -411,61 +382,28 @@ module.exports = exports = function dbScope (cfg) { } } - if (opts.form) { - req.headers['content-type'] = - 'application/x-www-form-urlencoded; charset=utf-8' - req.body = new URLSearchParams(opts.form) - } - - // ask request to render query string arrays as repeated values e.g. - // ?drilldown=["author","Dickens"]&drilldown=["publisher","Penguin"] - req.qsStringifyOptions = { arrayFormat: 'repeat' } - - // cfg.cookies = cookieJar.getCookiesSync(cfg.url) - - // This where the HTTP request is made. - // Nano used to use the now-deprecated "request" library but now we're going to - // use axios, so let's modify the "req" object to suit axios - req.url = req.uri - delete req.uri - req.method = req.method.toLowerCase() - req.params = req.qs - req.serializedParams = new URLSearchParams(req.params) - req.data = req.body - delete req.body - req.maxRedirects = 0 - if (opts.stream) { - req.responseType = 'stream' - } else if (opts.dontParse) { - req.responseType = 'arraybuffer' - } - // scrub and log const scrubbedReq = { - method: req.method, - headers: JSON.parse(JSON.stringify(req.headers)), - url: req.url + method, + headers: JSON.parse(JSON.stringify(headers)), + url: uri } scrubRequest(scrubbedReq, true) log(scrubbedReq) - // add http agents - // req.httpAgent = cfg.requestDefaults.agent || defaultHttpAgent - // req.httpsAgent = cfg.requestDefaults.agent || defaultHttpsAgent - // req.httpAgent.jar = req.httpAgent.jar ? req.httpAgent.jar : cookieJar - // req.httpsAgent.jar = req.httpsAgent.jar ? req.httpsAgent.jar : cookieJar - // insert basic auth headers, if present - Object.assign(req.headers, cfg.headers) + Object.assign(headers, cfg.headers) + // build the options we send to undici.fetch const fetchOptions = { - method: req.method, - headers: req.headers, + url: uri, + method, + headers, credentials: 'include', - body: req.method !== 'get' && req.data ? req.data : undefined, + body: method !== 'get' && body ? body : undefined, redirect: 'error', keepalive: true, - signal: req.signal + signal: opts.signal } // add custom agent if present @@ -474,9 +412,10 @@ module.exports = exports = function dbScope (cfg) { } // add querystring params - const queryString = req.serializedParams.toString() + const searchParams = new URLSearchParams(qs) + const queryString = searchParams.toString() if (queryString.length > 0) { - req.url += '?' + queryString + fetchOptions.url += '?' + queryString } // if the body is readable stream @@ -486,7 +425,7 @@ module.exports = exports = function dbScope (cfg) { } // add any cookies for this domain - const cookie = cookieJar.getCookieStringSync(req.url) + const cookie = cookieJar.getCookieStringSync(uri) if (cookie) { fetchOptions.headers.cookie = cookie } @@ -495,32 +434,31 @@ module.exports = exports = function dbScope (cfg) { if (opts.stream) { // return the Request object for streaming const outStream = new stream.PassThrough() - fetch(req.url, fetchOptions) - .then(async (response) => { - const readableWebStream = response.body - const readableNodeStream = Readable.fromWeb(readableWebStream) - if (response.status > 300) { - streamResponseHandler(response, req, outStream) - } else { - readableNodeStream.pipe(outStream) - } - }).catch(e => { - streamResponseHandler(e, req, outStream) - }) + undici.fetch(fetchOptions.url, fetchOptions).then((response) => { + const readableWebStream = response.body + const readableNodeStream = Readable.fromWeb(readableWebStream) + if (response.status > 300) { + streamResponseHandler(response, fetchOptions, outStream) + } else { + readableNodeStream.pipe(outStream) + } + }).catch((e) => { + streamResponseHandler(e, fetchOptions, outStream) + }) return outStream } else { if (typeof callback === 'function') { - fetch(req.url, fetchOptions).then((response) => { - responseHandler(response, req, opts, null, null, callback) + undici.fetch(fetchOptions.url, fetchOptions).then((response) => { + responseHandler(response, fetchOptions, opts, null, null, callback) }).catch((e) => { - responseHandler(e, req, opts, null, null, callback) + responseHandler(e, fetchOptions, opts, null, null, callback) }) } else { return new Promise((resolve, reject) => { - fetch(req.url, fetchOptions).then((response) => { - responseHandler(response, req, opts, resolve, reject) + undici.fetch(fetchOptions.url, fetchOptions).then((response) => { + responseHandler(response, fetchOptions, opts, resolve, reject) }).catch((e) => { - responseHandler(e, req, opts, resolve, reject) + responseHandler(e, fetchOptions, opts, resolve, reject) }) }) } diff --git a/test/nano.auth.test.js b/test/nano.auth.test.js index 8a24acb4..28971b16 100644 --- a/test/nano.auth.test.js +++ b/test/nano.auth.test.js @@ -110,4 +110,3 @@ test('should be able to handle cookie refresh - POST /_session - nano.auth', asy assert.deepEqual(p3, ['a']) mockAgent.assertNoPendingInterceptors() }) - From 529f5069afe63ae96425f234c8dd2f1dfc5463a3 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 13 Dec 2022 13:55:48 +0000 Subject: [PATCH 04/40] tidy up --- .travis.yml | 3 +-- README.md | 1 - lib/changesreader.js | 6 +++--- lib/nano.js | 31 +++++++++++++------------------ package-lock.json | 14 +++++++------- package.json | 2 +- 6 files changed, 25 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index a92acf6e..deeef4fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ dist: focal language: "node_js" node_js: - - "14" - - "16" - "18" + - "19" services: - docker os: diff --git a/README.md b/README.md index 49b9c219..1c29471a 100644 --- a/README.md +++ b/README.md @@ -1334,7 +1334,6 @@ npm run test [2]: https://github.com/apache/couchdb-nano/issues [4]: https://github.com/apache/couchdb-nano/blob/main/cfg/couch.example.js [8]: https://webchat.freenode.net?channels=%23couchdb-dev -[axios]: https://github.com/axios/axios https://freenode.org/ diff --git a/lib/changesreader.js b/lib/changesreader.js index 5093b4c0..98ca422f 100644 --- a/lib/changesreader.js +++ b/lib/changesreader.js @@ -279,6 +279,9 @@ class ChangesReader { const lin = liner() const cp = changeProcessor(self.ee, self.batchSize) self.request(req) + .on(EVENT_ERROR, (e) => { + self.ee.emit(EVENT_ERROR, e) + }) .pipe(lin) .pipe(cp) .on('finish', (lastSeq) => { @@ -287,9 +290,6 @@ class ChangesReader { self.ee.emit('end', cp.lastSeq) }, 10) }) - .on(EVENT_ERROR, (e) => { - self.ee.emit(EVENT_ERROR, e) - }) return self.ee } diff --git a/lib/nano.js b/lib/nano.js index aa7845fc..103b9197 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -10,17 +10,17 @@ // License for the specific language governing permissions and limitations under // the License. -// const { HttpsCookieAgent, HttpCookieAgent } = require('http-cookie-agent/http') const { URL } = require('url') -const { Readable } = require('node:stream') const assert = require('assert') -const { tough, cookieJar } = require('./cookiejar.js') const stream = require('stream') -const pkg = require('../package.json') +const Readable = stream.Readable const undici = require('undici') -const SCRUBBED_STR = 'XXXXXX' const ChangesReader = require('./changesreader.js') +const { tough, cookieJar } = require('./cookiejar.js') const MultiPartFactory = require('./multipart.js') +const pkg = require('../package.json') + +const SCRUBBED_STR = 'XXXXXX' function isEmpty (val) { return val == null || !(Object.keys(val) || val).length @@ -65,10 +65,7 @@ module.exports = exports = function dbScope (cfg) { assert.ok(/^https?:/.test(cfg.url), 'url is not valid') cfg = Object.assign({}, cfg) - serverScope.config = cfg - // cfg.requestDefaults = cfg.requestDefaults || {} - const dummyLogger = () => {} const log = typeof cfg.log === 'function' ? cfg.log : dummyLogger const parseUrl = 'parseUrl' in cfg ? cfg.parseUrl : true @@ -115,13 +112,6 @@ module.exports = exports = function dbScope (cfg) { if (req.headers.cookie) { req.headers.cookie = 'XXXXXXX' } - if (req.auth) { - if (!cloned) { - req.auth = JSON.parse(JSON.stringify(req.auth)) // clone just auth if not already cloned - } - req.auth.username = SCRUBBED_STR - req.auth.password = SCRUBBED_STR - } if (req.headers.Authorization) { req.headers.Authorization = 'XXXXXXX' } @@ -165,7 +155,8 @@ module.exports = exports = function dbScope (cfg) { delete responseHeaders['content-length'] if (statusCode >= 200 && statusCode < 400) { - log({ err: null, body, headers: responseHeaders }) + + // collect response const ct = response.headers.get('content-type') let retval = '' if (ct === 'application/json') { @@ -180,6 +171,10 @@ module.exports = exports = function dbScope (cfg) { const ab = await response.arrayBuffer() retval = Buffer.from(ab) } + + // log + log({ err: null, retval, headers: responseHeaders }) + // promisey if (resolve) { resolve(retval) @@ -402,8 +397,8 @@ module.exports = exports = function dbScope (cfg) { credentials: 'include', body: method !== 'get' && body ? body : undefined, redirect: 'error', - keepalive: true, - signal: opts.signal + signal: opts.signal, + bodyTimeout: 0 } // add custom agent if present diff --git a/package-lock.json b/package-lock.json index 4c8cc28e..db8229cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "tough-cookie": "^4.1.2", - "undici": "^5.13.0" + "undici": "^5.14.0" }, "devDependencies": {}, "engines": { @@ -74,9 +74,9 @@ } }, "node_modules/undici": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.13.0.tgz", - "integrity": "sha512-UDZKtwb2k7KRsK4SdXWG7ErXiL7yTGgLWvk2AXO1JMjgjh404nFo6tWSCM2xMpJwMPx3J8i/vfqEh1zOqvj82Q==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", "dependencies": { "busboy": "^1.6.0" }, @@ -148,9 +148,9 @@ } }, "undici": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.13.0.tgz", - "integrity": "sha512-UDZKtwb2k7KRsK4SdXWG7ErXiL7yTGgLWvk2AXO1JMjgjh404nFo6tWSCM2xMpJwMPx3J8i/vfqEh1zOqvj82Q==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index 61d00b0f..8f3fd8f3 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ ], "dependencies": { "tough-cookie": "^4.1.2", - "undici": "^5.13.0" + "undici": "^5.14.0" }, "devDependencies": { }, From b91594c0c303caaab464240c7ff11f88e11bbbdd Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Dec 2022 11:55:26 +0000 Subject: [PATCH 05/40] remove tough-cookie and its patch --- lib/cookie.js | 130 +++++++++++++ lib/cookiejar.js | 45 ----- lib/nano.js | 11 +- package-lock.json | 100 ---------- package.json | 1 - test/cookie.test.js | 433 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 569 insertions(+), 151 deletions(-) create mode 100644 lib/cookie.js delete mode 100644 lib/cookiejar.js create mode 100644 test/cookie.test.js diff --git a/lib/cookie.js b/lib/cookie.js new file mode 100644 index 00000000..2d11c2ec --- /dev/null +++ b/lib/cookie.js @@ -0,0 +1,130 @@ +const { URL } = require('url') + +// a simple cookie jar +class CookieJar { + // create new empty cookie jar + constructor () { + this.jar = [] + } + + // remove expired cookies + clean () { + const now = new Date().getTime() + for (let i = 0; i < this.jar.length; i++) { + const c = this.jar[i] + if (c.ts < now) { + this.jar.splice(i, 1) + i-- + } + } + } + + // add a cookie to the jar + add (cookie, url) { + // see if we have this cookie already + const oldCookieIndex = this.findByName(url, cookie.name) + + // if we do, update it + if (oldCookieIndex >= 0) { + // update existing cookie + this.jar[oldCookieIndex].value = cookie.value + this.jar[oldCookieIndex].expires = cookie.expires + this.jar[oldCookieIndex].ts = new Date(cookie.expires).getTime() + } else { + // otherwise, just add it + this.jar.push(cookie) + } + } + + // locate a cookie by name & url + findByName (url, name) { + this.clean() + const now = new Date().getTime() + const parsedURL = new URL(url) + for (let i = 0; i < this.jar.length; i++) { + const c = this.jar[i] + if (c.origin === parsedURL.origin && + c.name === name && + c.ts >= now) { + return i + } + } + return -1 + } + + // get a list of cookies to send for a supplied URL + getCookieString (url) { + let i + // clean up deceased cookies + this.clean() + + // find cookies that match the url + const now = new Date().getTime() + const parsedURL = new URL(url) + const retval = [] + for (i = 0; i < this.jar.length; i++) { + const c = this.jar[i] + // if match domain name, protocol and timestamp + if ((c.origin === parsedURL.origin || + (c.domain && parsedURL.hostname.endsWith(c.domain))) && + c.protocol === parsedURL.protocol && + c.ts >= now) { + // if cookie has httponly flag and this is not http, ignore + if (c.httponly && parsedURL.protocol !== 'http:') { + continue + } + + // if cookie has a path and it doesn't match incoming url, ignore + if (c.path && !parsedURL.pathname.startsWith(c.path)) { + continue + } + + // if cookie has a secure flag and the transport isn't secure, ignore + if (c.secure && parsedURL.protocol !== 'https:') { + continue + } + + // add to list of returned cookies + retval.push(c.value) + } + } + // if we've got cookies to return + if (retval.length > 0) { + // join them with semi-colons + return retval.join('; ') + } else { + // otherwise a blank string + return '' + } + } + + // parse a 'set-cookie' header of the form: + // AuthSession=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY; Version=1; Expires=Tue, 13-Dec-2022 13:54:19 GMT; Max-Age=60; Path=/; HttpOnly + parse (h, url) { + const parsedURL = new URL(url) + + // split components by ; and remove whitespace + const bits = h.split(';').map(s => s.trim()) + + // extract the cookie's value from the start of the string + const cookieValue = bits.shift() + + // start a cookie object + const cookie = { + name: cookieValue.split('=')[0], // the first part of the value + origin: parsedURL.origin, + pathname: parsedURL.pathname, + protocol: parsedURL.protocol + } + bits.forEach((e) => { + const lr = e.split('=') + cookie[lr[0].toLowerCase()] = lr[1] || true + }) + // calculate expiry timestamp + cookie.ts = new Date(cookie.expires).getTime() + cookie.value = cookieValue + this.add(cookie, url) + } +} + +module.exports = CookieJar diff --git a/lib/cookiejar.js b/lib/cookiejar.js deleted file mode 100644 index 270a6690..00000000 --- a/lib/cookiejar.js +++ /dev/null @@ -1,45 +0,0 @@ -const tough = require('tough-cookie') -const cookieJar = new tough.CookieJar() - -// this is a monkey-patch of toughcookie's cookiejar, as it doesn't handle -// the refreshing of cookies from CouchDB properly -// see https://github.com/salesforce/tough-cookie/issues/154 -cookieJar.cloudantPatch = true -// Replace the store's updateCookie function with one that applies a patch to newCookie -const originalUpdateCookieFn = cookieJar.store.updateCookie -cookieJar.store.updateCookie = function (oldCookie, newCookie, cb) { - // Add current time as an update timestamp to the newCookie - newCookie.cloudantPatchUpdateTime = new Date() - // Replace the cookie's expiryTime function with one that uses cloudantPatchUpdateTime - // in place of creation time to check the expiry. - const originalExpiryTimeFn = newCookie.expiryTime - newCookie.expiryTime = function (now) { - // The original expiryTime check is relative to a time in this order: - // 1. supplied now argument - // 2. this.creation (original cookie creation time) - // 3. current time - // This patch replaces 2 with an expiry check relative to the cloudantPatchUpdateTime if set instead of - // the creation time by passing it as the now argument. - return originalExpiryTimeFn.call( - newCookie, - newCookie.cloudantPatchUpdateTime || now - ) - } - // Finally delegate back to the original update function or the fallback put (which is set by Cookie - // when an update function is not present on the store). Since we always set an update function for our - // patch we need to also provide that fallback. - if (originalUpdateCookieFn) { - originalUpdateCookieFn.call( - cookieJar.store, - oldCookie, - newCookie, - cb - ) - } else { - cookieJar.store.putCookie(newCookie, cb) - } -} -module.exports = { - tough, - cookieJar -} diff --git a/lib/nano.js b/lib/nano.js index 103b9197..cc4f1494 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -16,7 +16,7 @@ const stream = require('stream') const Readable = stream.Readable const undici = require('undici') const ChangesReader = require('./changesreader.js') -const { tough, cookieJar } = require('./cookiejar.js') +const CookieJar = require('./cookie.js') const MultiPartFactory = require('./multipart.js') const pkg = require('../package.json') @@ -83,6 +83,9 @@ module.exports = exports = function dbScope (cfg) { cfg.agent = new undici.Agent(cfg.agentOptions) } + // create cookieJar for this Nano + cfg.cookieJar = new CookieJar() + function maybeExtractDatabaseComponent () { if (!parseUrl) { return @@ -126,8 +129,7 @@ module.exports = exports = function dbScope (cfg) { if (response.headers) { const h = response.headers.get('set-cookie') if (h) { - const cookie = tough.Cookie.parse(h) - cookieJar.setCookieSync(cookie, req.url) + cfg.cookieJar.parse(h, req.url) } } @@ -155,7 +157,6 @@ module.exports = exports = function dbScope (cfg) { delete responseHeaders['content-length'] if (statusCode >= 200 && statusCode < 400) { - // collect response const ct = response.headers.get('content-type') let retval = '' @@ -420,7 +421,7 @@ module.exports = exports = function dbScope (cfg) { } // add any cookies for this domain - const cookie = cookieJar.getCookieStringSync(uri) + const cookie = cfg.cookieJar.getCookieString(uri) if (cookie) { fetchOptions.headers.cookie = cookie } diff --git a/package-lock.json b/package-lock.json index db8229cd..0978f1f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "11.0.0", "license": "Apache-2.0", "dependencies": { - "tough-cookie": "^4.1.2", "undici": "^5.14.0" }, "devDependencies": {}, @@ -28,29 +27,6 @@ "node": ">=10.16.0" } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "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==", - "engines": { - "node": ">=6" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -59,20 +35,6 @@ "node": ">=10.0.0" } }, - "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/undici": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", @@ -83,23 +45,6 @@ "engines": { "node": ">=12.18" } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } } }, "dependencies": { @@ -111,42 +56,11 @@ "streamsearch": "^1.1.0" } }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, "streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, - "tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, "undici": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", @@ -154,20 +68,6 @@ "requires": { "busboy": "^1.6.0" } - }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } } } } diff --git a/package.json b/package.json index 8f3fd8f3..9013ae0e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "database" ], "dependencies": { - "tough-cookie": "^4.1.2", "undici": "^5.14.0" }, "devDependencies": { diff --git a/test/cookie.test.js b/test/cookie.test.js new file mode 100644 index 00000000..b28368dc --- /dev/null +++ b/test/cookie.test.js @@ -0,0 +1,433 @@ +// Licensed under the Apache License, Version 2.0 (the 'License'); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +const test = require('node:test') +const assert = require('node:assert/strict') + +const CookieJar = require('../lib/cookie.js') + +test('should parse cookies correctly', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v = `${n}=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc = `${v}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const url = 'http://mydomain.com/_session' + cj.parse(sc, url) + assert.equal(cj.jar.length, 1) + const cookie = { + name: 'AuthSession', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: v + } + assert.deepEqual(cj.jar[0], cookie) +}) + +test('should handle multiple cookies', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v1 = 'YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY' + const v2 = 'YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY' + const v3 = 'YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY' + const sc1 = `${n}1=${v1}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const sc2 = `${n}2=${v2}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const sc3 = `${n}3=${v3}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const url = 'http://mydomain.com/_session' + cj.parse(sc1, url) + cj.parse(sc2, url) + cj.parse(sc3, url) + assert.equal(cj.jar.length, 3) + let cookie = { + name: 'AuthSession1', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession1=${v1}` + } + assert.deepEqual(cj.jar[0], cookie) + cookie = { + name: 'AuthSession2', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession2=${v2}` + } + assert.deepEqual(cj.jar[1], cookie) + cookie = { + name: 'AuthSession3', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession3=${v3}` + } + assert.deepEqual(cj.jar[2], cookie) +}) + +test('should handle multiple domains', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v1 = 'gzQ0Y6TuB66MczYWRtaW46NjM5ODvkZ7axEJq6Fz0gOdhKY' + const v2 = 'YWRtaWzQ0Y6T46NjM5ODguB66MczvkZ7axEJq6Fz0gOdhKY' + const v3 = '46NjM5ODgYWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY' + const v4 = 'Y6TuB66MczvkZ7axY6TuBxzvkZ7ax46NjM5ODgYWRtaW46NjM5ODgzQ0EJq6Fz0gOdhKY' + const sc1 = `${n}1=${v1}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const sc2 = `${n}2=${v2}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const sc3 = `${n}3=${v3}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const sc4 = `${n}4=${v4}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + const url1 = 'http://mydomain1.com/_session' + const url2 = 'http://mydomain2.com/_session' + const url3 = 'http://mydomain3.com/_session' + cj.parse(sc1, url1) + cj.parse(sc2, url2) + cj.parse(sc3, url3) + cj.parse(sc4, url3) + assert.equal(cj.jar.length, 4) + let cookie = { + name: 'AuthSession1', + origin: 'http://mydomain1.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession1=${v1}` + } + assert.deepEqual(cj.jar[0], cookie) + assert.deepEqual(cj.getCookieString(url1), cookie.value) + cookie = { + name: 'AuthSession2', + origin: 'http://mydomain2.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession2=${v2}` + } + assert.deepEqual(cj.jar[1], cookie) + assert.deepEqual(cj.getCookieString(url2), cookie.value) + const cookie1 = { + name: 'AuthSession3', + origin: 'http://mydomain3.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession3=${v3}` + } + assert.deepEqual(cj.jar[2], cookie1) + const cookie2 = { + name: 'AuthSession4', + origin: 'http://mydomain3.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: `AuthSession4=${v4}` + } + assert.deepEqual(cj.jar[3], cookie2) + // multiple cookies - 2 cookies for url3 + assert.equal(cj.getCookieString(url3), `${cookie1.value}; ${cookie2.value}`) + + // check we don't get a cookie for a subdomain + assert.equal(cj.getCookieString('http://sub.mydomain3.com'), '') +}) + +const sleep = async (ms) => { + return new Promise((resolve, reject) => { + setTimeout(resolve, ms) + }) +} + +test('should expire cookies correctly', async () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 5 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v = `${n}=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc = `${v}; Version=1; Expires=${expiryStr}; Max-Age=5; Path=/; HttpOnly` + const url = 'http://mydomain.com/_session' + cj.parse(sc, url) + assert.equal(cj.jar.length, 1) + assert.notEqual(cj.getCookieString(url).length, 0) + await sleep(5000) + assert.equal(cj.getCookieString(url).length, 0) + assert.equal(cj.getCookieString(url).length, 0) +}) + +test('should respect path', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v1 = `${n}1=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc1 = `${v1}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/my/path; HttpOnly` + const v2 = `${n}2=YczvkZ7axEJq6Fz0gOdhKYWRtaW46NjM5ODgzQ0Y6TuB66M` + const sc2 = `${v2}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly` + + const url = 'http://mydomain.com/_session' + cj.parse(sc1, url) + cj.parse(sc2, url) + assert.equal(cj.jar.length, 2) + const cookie1 = { + name: 'AuthSession1', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/my/path', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: v1 + } + assert.deepEqual(cj.jar[0], cookie1) + const cookie2 = { + name: 'AuthSession2', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr).getTime(), + value: v2 + } + assert.deepEqual(cj.jar[1], cookie2) + + // one cookies for path=/ + let cs = cj.getCookieString('http://mydomain.com/') + assert.equal(cs, `${cookie2.value}`) + // two cookies for path=/my/path + cs = cj.getCookieString('http://mydomain.com/my/path') + assert.equal(cs, `${cookie1.value}; ${cookie2.value}`) + // two cookies for path=/my/path/extra + cs = cj.getCookieString('http://mydomain.com/my/path/extra') + assert.equal(cs, `${cookie1.value}; ${cookie2.value}`) + // zero cookies for different domain + cs = cj.getCookieString('http://myotherdomain.com/my/path/extra') + assert.equal(cs, '') +}) + +test('should renew cookies', () => { + const cj = new CookieJar() + const n = 'AuthSession' + const expiry1 = new Date().getTime() + 1000 * 60 + const expiryStr1 = new Date(expiry1).toGMTString() + + const v1 = `${n}=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc1 = `${v1}; Version=1; Expires=${expiryStr1}; Max-Age=60; Path=/; HttpOnly` + + const expiry2 = new Date().getTime() + 1000 * 120 + const expiryStr2 = new Date(expiry2).toGMTString() + const v2 = `${n}=gOdhKYWRtaW46NjM5ODgzQ0Y6TuB66MYczvkZ7axEJq6Fz0` + const sc2 = `${v2}; Version=1; Expires=${expiryStr2}; Max-Age=60; Path=/; HttpOnly` + + const url = 'http://mydomain.com/_session' + + // parse first cookie string + cj.parse(sc1, url) + assert.equal(cj.jar.length, 1) + const cookie1 = { + name: 'AuthSession', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr1, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr1).getTime(), + value: v1 + } + assert.deepEqual(cj.jar[0], cookie1) + + // then refresh the cookie + cj.parse(sc2, url) + const cookie2 = { + name: 'AuthSession', + origin: 'http://mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr2, + 'max-age': '60', + path: '/', + httponly: true, + ts: new Date(expiryStr2).getTime(), + value: v2 + } + + // ensure it updates the same cookie + assert.equal(cj.jar.length, 1) + assert.deepEqual(cj.jar[0], cookie2) +}) + +test('should send cookies to authorised subdomains', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v = `${n}=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc = `${v}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly; Domain=.mydomain.com` + const url = 'http://test.mydomain.com/_session' + cj.parse(sc, url) + assert.equal(cj.jar.length, 1) + const cookie = { + name: 'AuthSession', + origin: 'http://test.mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + domain: '.mydomain.com', + ts: new Date(expiryStr).getTime(), + value: v + } + assert.deepEqual(cj.jar[0], cookie) + + // check we get a cookie for the same domain + let cs = cj.getCookieString('http://test.mydomain.com/my/path/extra') + assert.equal(cs, `${cookie.value}`) + + // check we get a cookie for the different domain + cs = cj.getCookieString('http://different.mydomain.com/my/path/extra') + assert.equal(cs, `${cookie.value}`) + cs = cj.getCookieString('http://sub.different.mydomain.com/my/path/extra') + assert.equal(cs, `${cookie.value}`) + + // check we get no cookies for the different domain + cs = cj.getCookieString('http://mydomain1.com/my/path/extra') + assert.equal(cs, '') +}) + +test('should not send http-only cookies to https', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v = `${n}=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc = `${v}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; HttpOnly; Domain=.mydomain.com` + const url = 'http://test.mydomain.com/_session' + cj.parse(sc, url) + assert.equal(cj.jar.length, 1) + const cookie = { + name: 'AuthSession', + origin: 'http://test.mydomain.com', + pathname: '/_session', + protocol: 'http:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + httponly: true, + domain: '.mydomain.com', + ts: new Date(expiryStr).getTime(), + value: v + } + assert.deepEqual(cj.jar[0], cookie) + + // check we get a cookie for the same domain (http) + let cs = cj.getCookieString('http://test.mydomain.com/my/path/extra') + assert.equal(cs, `${cookie.value}`) + + // but not https + cs = cj.getCookieString('https://test.mydomain.com/my/path/extra') + assert.equal(cs, '') +}) + +test('should not send secure-only cookies to http', () => { + const cj = new CookieJar() + const expiry = new Date().getTime() + 1000 * 60 + const expiryStr = new Date(expiry).toGMTString() + const n = 'AuthSession' + const v = `${n}=YWRtaW46NjM5ODgzQ0Y6TuB66MczvkZ7axEJq6Fz0gOdhKY` + const sc = `${v}; Version=1; Expires=${expiryStr}; Max-Age=60; Path=/; Secure; Domain=.mydomain.com` + const url = 'https://test.mydomain.com/_session' + cj.parse(sc, url) + assert.equal(cj.jar.length, 1) + const cookie = { + name: 'AuthSession', + origin: 'https://test.mydomain.com', + pathname: '/_session', + protocol: 'https:', + version: '1', + expires: expiryStr, + 'max-age': '60', + path: '/', + secure: true, + domain: '.mydomain.com', + ts: new Date(expiryStr).getTime(), + value: v + } + assert.deepEqual(cj.jar[0], cookie) + + // check we get a cookie for the same domain (http) + let cs = cj.getCookieString('https://test.mydomain.com/my/path/extra') + assert.equal(cs, `${cookie.value}`) + + // but not http + cs = cj.getCookieString('http://test.mydomain.com/my/path/extra') + assert.equal(cs, '') +}) From cb06484ab6130d2c38cb1d91aeaeac42d9f56c64 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Dec 2022 12:40:47 +0000 Subject: [PATCH 06/40] log headers object instead of map --- lib/nano.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nano.js b/lib/nano.js index cc4f1494..be1cd1f8 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -137,7 +137,7 @@ module.exports = exports = function dbScope (cfg) { const responseHeaders = Object.assign({ uri: scrubURL(req.url), statusCode - }, response.headers) + }, Object.fromEntries(response.headers)) if (!response.status) { response.statusText = response.cause.toString() log({ err: 'socket', body, headers: responseHeaders }) @@ -239,7 +239,7 @@ module.exports = exports = function dbScope (cfg) { const responseHeaders = Object.assign({ uri: req.url, statusCode - }, response.headers) + }, Object.fromEntries(response.headers)) const error = new Error(message) error.scope = 'couch' From ae36ca683aa24ed69884b57e9f3cc4d10a491f5e Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Dec 2022 13:43:47 +0000 Subject: [PATCH 07/40] http/https bug fix --- lib/cookie.js | 9 ++++----- test/cookie.test.js | 8 ++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/cookie.js b/lib/cookie.js index 2d11c2ec..d18a4ce6 100644 --- a/lib/cookie.js +++ b/lib/cookie.js @@ -64,13 +64,12 @@ class CookieJar { const retval = [] for (i = 0; i < this.jar.length; i++) { const c = this.jar[i] - // if match domain name, protocol and timestamp + // if match domain name and timestamp if ((c.origin === parsedURL.origin || - (c.domain && parsedURL.hostname.endsWith(c.domain))) && - c.protocol === parsedURL.protocol && + (c.domain && parsedURL.hostname.endsWith(c.domain))) && c.ts >= now) { - // if cookie has httponly flag and this is not http, ignore - if (c.httponly && parsedURL.protocol !== 'http:') { + // if cookie has httponly flag and this is not http(s), ignore + if (c.httponly && !['http:', 'https:'].includes(parsedURL.protocol)) { continue } diff --git a/test/cookie.test.js b/test/cookie.test.js index b28368dc..32ba0629 100644 --- a/test/cookie.test.js +++ b/test/cookie.test.js @@ -362,7 +362,7 @@ test('should send cookies to authorised subdomains', () => { assert.equal(cs, '') }) -test('should not send http-only cookies to https', () => { +test('should not send http-only cookies to different protocol', () => { const cj = new CookieJar() const expiry = new Date().getTime() + 1000 * 60 const expiryStr = new Date(expiry).toGMTString() @@ -392,8 +392,12 @@ test('should not send http-only cookies to https', () => { let cs = cj.getCookieString('http://test.mydomain.com/my/path/extra') assert.equal(cs, `${cookie.value}`) - // but not https + // check we get a cookie for the same domain (https) cs = cj.getCookieString('https://test.mydomain.com/my/path/extra') + assert.equal(cs, `${cookie.value}`) + + // but not some other protocol + cs = cj.getCookieString('ws://test.mydomain.com/my/path/extra') assert.equal(cs, '') }) From 1ad4561b22b7369f1da75c28007d3adc54f74bbb Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Dec 2022 14:03:48 +0000 Subject: [PATCH 08/40] added typescript parsing --- package-lock.json | 38 ++++++++++++++++++++++++++++++++++++-- package.json | 6 ++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0978f1f0..d14c9493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,11 +11,20 @@ "dependencies": { "undici": "^5.14.0" }, - "devDependencies": {}, + "devDependencies": { + "@types/node": "^18.11.15", + "typescript": "^4.9.4" + }, "engines": { - "node": ">=18" + "node": ">=12.18" } }, + "node_modules/@types/node": { + "version": "18.11.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", + "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", + "dev": true + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -35,6 +44,19 @@ "node": ">=10.0.0" } }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/undici": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", @@ -48,6 +70,12 @@ } }, "dependencies": { + "@types/node": { + "version": "18.11.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", + "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", + "dev": true + }, "busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -61,6 +89,12 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true + }, "undici": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", diff --git a/package.json b/package.json index 9013ae0e..38b7db64 100644 --- a/package.json +++ b/package.json @@ -20,14 +20,16 @@ "undici": "^5.14.0" }, "devDependencies": { + "@types/node": "^18.11.15", + "typescript": "^4.9.4" }, "scripts": { - "test": "node --test ./test/*.test.js" + "test": "tsc lib/nano.d.ts && node --test ./test/*.test.js" }, "main": "./lib/nano.js", "types": "./lib/nano.d.ts", "engines": { - "node": ">=18" + "node": ">=12.18" }, "pre-commit": [ "test" From fbed7ab6ba1d297704e9c386a27bd8f626d215a6 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Dec 2022 14:28:34 +0000 Subject: [PATCH 09/40] bug fixes for node16.8 --- .travis.yml | 1 + lib/nano.js | 6 +++--- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index deeef4fe..3bfd4e58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ dist: focal language: "node_js" node_js: + - "16.8.1" - "18" - "19" services: diff --git a/lib/nano.js b/lib/nano.js index be1cd1f8..8c2e5989 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -137,7 +137,7 @@ module.exports = exports = function dbScope (cfg) { const responseHeaders = Object.assign({ uri: scrubURL(req.url), statusCode - }, Object.fromEntries(response.headers)) + }, response.headers ? Object.fromEntries(response.headers) : {}) if (!response.status) { response.statusText = response.cause.toString() log({ err: 'socket', body, headers: responseHeaders }) @@ -239,7 +239,7 @@ module.exports = exports = function dbScope (cfg) { const responseHeaders = Object.assign({ uri: req.url, statusCode - }, Object.fromEntries(response.headers)) + }, response.headers ? Object.fromEntries(response.headers): {}) const error = new Error(message) error.scope = 'couch' @@ -432,7 +432,7 @@ module.exports = exports = function dbScope (cfg) { const outStream = new stream.PassThrough() undici.fetch(fetchOptions.url, fetchOptions).then((response) => { const readableWebStream = response.body - const readableNodeStream = Readable.fromWeb(readableWebStream) + const readableNodeStream = Readable.fromWeb ? Readable.fromWeb(readableWebStream) : Readable.from(readableWebStream) if (response.status > 300) { streamResponseHandler(response, fetchOptions, outStream) } else { diff --git a/package-lock.json b/package-lock.json index d14c9493..241e8eff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "typescript": "^4.9.4" }, "engines": { - "node": ">=12.18" + "node": ">=16.8" } }, "node_modules/@types/node": { diff --git a/package.json b/package.json index 38b7db64..f5c823c9 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "main": "./lib/nano.js", "types": "./lib/nano.d.ts", "engines": { - "node": ">=12.18" + "node": ">=16.8" }, "pre-commit": [ "test" From 6d800c350fbc1ec3669b26a7faa40b103f58d0cf Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Dec 2022 16:00:27 +0000 Subject: [PATCH 10/40] custom agent and agentOptions with tests --- README.md | 7 +++++++ lib/nano.js | 20 ++++++++++++++------ test/nano.agent.test.js | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 test/nano.agent.test.js diff --git a/README.md b/README.md index 1c29471a..8a170d92 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,13 @@ const nano = Nano({ url: 'http://127.0.0.1:5984', agentOptions }) The meanings of the agentOptions attributes is described [here](https://undici.nodejs.org/#/docs/api/Agent?id=new-undiciagentoptions), [here](https://undici.nodejs.org/#/docs/api/Pool?id=parameter-pooloptions) and [here](https://undici.nodejs.org/#/docs/api/Client?id=parameter-clientoptions) +You may also supply a pre-existing `undici.Agent` e.g. + +```js +const agent = new undici.Agent({bodyTimeout: 30000 }) +const nano = Nano({ url: 'http://127.0.0.1:5984', agentOptions: agent }) +`` + > Note `requestDefaults` is no longer supported. ## Custom headers diff --git a/lib/nano.js b/lib/nano.js index 8c2e5989..79bce3e1 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -15,6 +15,7 @@ const assert = require('assert') const stream = require('stream') const Readable = stream.Readable const undici = require('undici') +const fetch = global.fetch || undici.fetch const ChangesReader = require('./changesreader.js') const CookieJar = require('./cookie.js') const MultiPartFactory = require('./multipart.js') @@ -79,8 +80,15 @@ module.exports = exports = function dbScope (cfg) { } // look for agentOptions - if (cfg.agentOptions && typeof cfg.agentOptions === 'object') { - cfg.agent = new undici.Agent(cfg.agentOptions) + if (cfg.agentOptions) { + // if we've been passed a undici.Agent or undici.MockAgent, + // basically anything inherited from undici.Dispatcher, we + // can use it + if (cfg.agentOptions instanceof undici.Dispatcher) { + cfg.agent = cfg.agentOptions + } else if (typeof cfg.agentOptions === 'object') { + cfg.agent = new undici.Agent(cfg.agentOptions) + } } // create cookieJar for this Nano @@ -239,7 +247,7 @@ module.exports = exports = function dbScope (cfg) { const responseHeaders = Object.assign({ uri: req.url, statusCode - }, response.headers ? Object.fromEntries(response.headers): {}) + }, response.headers ? Object.fromEntries(response.headers) : {}) const error = new Error(message) error.scope = 'couch' @@ -430,7 +438,7 @@ module.exports = exports = function dbScope (cfg) { if (opts.stream) { // return the Request object for streaming const outStream = new stream.PassThrough() - undici.fetch(fetchOptions.url, fetchOptions).then((response) => { + fetch(fetchOptions.url, fetchOptions).then((response) => { const readableWebStream = response.body const readableNodeStream = Readable.fromWeb ? Readable.fromWeb(readableWebStream) : Readable.from(readableWebStream) if (response.status > 300) { @@ -444,14 +452,14 @@ module.exports = exports = function dbScope (cfg) { return outStream } else { if (typeof callback === 'function') { - undici.fetch(fetchOptions.url, fetchOptions).then((response) => { + fetch(fetchOptions.url, fetchOptions).then((response) => { responseHandler(response, fetchOptions, opts, null, null, callback) }).catch((e) => { responseHandler(e, fetchOptions, opts, null, null, callback) }) } else { return new Promise((resolve, reject) => { - undici.fetch(fetchOptions.url, fetchOptions).then((response) => { + fetch(fetchOptions.url, fetchOptions).then((response) => { responseHandler(response, fetchOptions, opts, resolve, reject) }).catch((e) => { responseHandler(e, fetchOptions, opts, resolve, reject) diff --git a/test/nano.agent.test.js b/test/nano.agent.test.js new file mode 100644 index 00000000..4397af0c --- /dev/null +++ b/test/nano.agent.test.js @@ -0,0 +1,18 @@ +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent } = require('./mock.js') +const Nano = require('../lib/nano') +const undici = require('undici') + +test('should be able to supply a custom agent parameters', async () => { + const agentOptions = { + bodyTimeout: 10000 + } + const nano = Nano({ url: COUCH_URL, agentOptions }) + assert(nano.config.agent instanceof undici.Agent) +}) + +test('should be able to supply a custom agent', async () => { + const nano = Nano({ url: COUCH_URL, agentOptions: mockAgent }) + assert.equal(nano.config.agent, mockAgent) +}) From 2b5e5af7977fdd6d268d800da0f8591b9f6c1c3e Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 15 Dec 2022 09:49:35 +0000 Subject: [PATCH 11/40] tidy up --- lib/nano.d.ts | 11 ++++++++--- lib/nano.js | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/nano.d.ts b/lib/nano.d.ts index d40d3077..4dbd3a54 100644 --- a/lib/nano.d.ts +++ b/lib/nano.d.ts @@ -19,6 +19,8 @@ /// import { EventEmitter } from "events"; +import { ConnectionOptions } from "tls"; +import undici from "undici"; /** nano entry function */ declare function nano( @@ -27,8 +29,11 @@ declare function nano( declare namespace nano { /** AgentOptionsConnect options */ - interface AgentOptionsConnect { - timeout?: number + interface AgentOptionsConnect extends ConnectionOptions { + socketPath: string, + maxCachedSessions: number, + timeout?: number, + servername: string } /** AgentOptions options */ interface AgentOptions { @@ -57,7 +62,7 @@ declare namespace nano { /** HTTP Agent options * @see README: {@link https://www.npmjs.com/package/nano#pool-size-and-open-sockets} */ - agent?: AgentOptions; + agentOptions?: AgentOptions | typeof undici.Agent | typeof undici.MockAgent | typeof undici.Dispatcher; /** Logging function * @see README: {@link https://www.npmjs.com/package/nano#logging} */ diff --git a/lib/nano.js b/lib/nano.js index 79bce3e1..28364117 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -15,7 +15,7 @@ const assert = require('assert') const stream = require('stream') const Readable = stream.Readable const undici = require('undici') -const fetch = global.fetch || undici.fetch +const fetcher = fetch || global.fetch || undici.fetch const ChangesReader = require('./changesreader.js') const CookieJar = require('./cookie.js') const MultiPartFactory = require('./multipart.js') @@ -438,7 +438,7 @@ module.exports = exports = function dbScope (cfg) { if (opts.stream) { // return the Request object for streaming const outStream = new stream.PassThrough() - fetch(fetchOptions.url, fetchOptions).then((response) => { + fetcher(fetchOptions.url, fetchOptions).then((response) => { const readableWebStream = response.body const readableNodeStream = Readable.fromWeb ? Readable.fromWeb(readableWebStream) : Readable.from(readableWebStream) if (response.status > 300) { @@ -452,14 +452,14 @@ module.exports = exports = function dbScope (cfg) { return outStream } else { if (typeof callback === 'function') { - fetch(fetchOptions.url, fetchOptions).then((response) => { + fetcher(fetchOptions.url, fetchOptions).then((response) => { responseHandler(response, fetchOptions, opts, null, null, callback) }).catch((e) => { responseHandler(e, fetchOptions, opts, null, null, callback) }) } else { return new Promise((resolve, reject) => { - fetch(fetchOptions.url, fetchOptions).then((response) => { + fetcher(fetchOptions.url, fetchOptions).then((response) => { responseHandler(response, fetchOptions, opts, resolve, reject) }).catch((e) => { responseHandler(e, fetchOptions, opts, resolve, reject) From a8a0825ad8c8ec27448337c9860e0136fe1e2ccf Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Fri, 16 Dec 2022 13:44:36 +0000 Subject: [PATCH 12/40] show warning when requestDefaults is supplied --- lib/nano.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/nano.js b/lib/nano.js index 28364117..77a6a48d 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -91,6 +91,11 @@ module.exports = exports = function dbScope (cfg) { } } + // warn using still using requestDefaults + if (cfg.requestDefaults) { + console.error('WARNING: requestDefaults is no longer supported. See agentOptions.') + } + // create cookieJar for this Nano cfg.cookieJar = new CookieJar() From c329cc1742021d41276dfa933674b0b07a19285c Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Fri, 16 Dec 2022 13:45:07 +0000 Subject: [PATCH 13/40] added description of each agentOptions attribute --- lib/nano.d.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/nano.d.ts b/lib/nano.d.ts index 4dbd3a54..58635d4f 100644 --- a/lib/nano.d.ts +++ b/lib/nano.d.ts @@ -30,24 +30,59 @@ declare function nano( declare namespace nano { /** AgentOptionsConnect options */ interface AgentOptionsConnect extends ConnectionOptions { + /** An IPC endpoint, either Unix domain socket or Windows named pipe. + * Default: null */ socketPath: string, + /** Maximum number of TLS cached sessions. Use 0 to disable TLS session + * caching. Default: 100 */ maxCachedSessions: number, + /** Connection timeout in ms. Default: 10000 */ timeout?: number, + /** Default: null */ servername: string } /** AgentOptions options */ interface AgentOptions { + /** The timeout after which a request will time out, in milliseconds. + * Monitors time between receiving body data. Use 0 to disable it entirely. + * Default: 30000 */ bodyTimeout?: number, + /** The amount of time the parser will wait to receive the complete + * HTTP headers while not sending the request. Default: 30000 */ headersTimeout?: number, + /** The maximum allowed keepAliveTimeout in ms when overridden by keep-alive hints + * from the server. Default: 600000 */ keepAliveMaxTimeout?: number, + /** The timeout in ms after which a socket without active requests will time out. + * Monitors time between activity on a connected socket. This value may be + * overridden by keep-alive hints from the server. Default: 4000 */ keepAliveTimeout?: number, + /** A number subtracted from server keep-alive hints when overriding + * keepAliveTimeout to account for timing inaccuracies caused by + * e.g. transport latency. Default: 1000 */ keepAliveTimeoutThreshold?: number, + /** The maximum length of request headers in bytes. Default: 16384 */ maxHeaderSize?: number, + /** The maximum length of response body in bytes. Set to -1 to disable. Default: -1 */ maxResponseSize?: number, + /** The amount of concurrent requests to be sent over the single TCP/TLS + * connection according to RFC7230. Carefully consider your workload and + * environment before enabling concurrent requests as pipelining may reduce + * performance if used incorrectly. Pipelining is sensitive to network stack + * settings as well as head of line blocking caused by e.g. long running r + * equests. Set to 0 to disable keep-alive connections. Default: 1 */ pipelining?: number, + /** Connection options */ connect?: AgentOptionsConnect, + /** Whether to treat request content length mismatches as errors. If true, + * an error is thrown when the request content-length header doesn't match + * the length of the request body. Default: true */ strictContentLength?: boolean, + /** The number of Client instances to create. + * When set to null, the Pool instance will create an unlimited amount + * of Client instances. */ connections: null, + /** The number of HTTP redirection to follow - Default: 0 */ maxRedirections?: null } From c40a4a399ac9c25ff9f181eb2f77c427b09381f5 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Fri, 16 Dec 2022 15:36:32 +0000 Subject: [PATCH 14/40] added missing test file --- test/database.changes.test.js | 100 ++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 test/database.changes.test.js diff --git a/test/database.changes.test.js b/test/database.changes.test.js new file mode 100644 index 00000000..0444fb1a --- /dev/null +++ b/test/database.changes.test.js @@ -0,0 +1,100 @@ +// Licensed under the Apache License, Version 2.0 (the 'License'); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +const test = require('node:test') +const assert = require('node:assert/strict') +const { COUCH_URL, mockAgent, mockPool, JSON_HEADERS } = require('./mock.js') +const Nano = require('..') +const nano = Nano(COUCH_URL) + +const response = { + results: [ + { + seq: '1-nC1J', + id: 'c42ddf1272c7d05b2dc45b6962000b10', + changes: [ + { + rev: '1-23202479633c2b380f79507a776743d5' + } + ] + } + ], + last_seq: '1-C1J', + pending: 0 +} +const errResponse = { + error: 'not_found', + reason: 'Database does not exist.' +} + +test('should be able to fetch the changes - GET /db/_changes - nano.db.changes', async () => { + // mocks + mockPool + .intercept({ path: '/db/_changes' }) + .reply(200, response, JSON_HEADERS) + + // test GET /db/_changes + const p = await nano.db.changes('db') + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() +}) + +test('should be able to fetch the changes with opts - GET /db/_changes - nano.db.changes', async () => { + // mocks + const opts = { include_docs: true, feed: 'continuous' } + mockPool + .intercept({ path: '/db/_changes?include_docs=true&feed=continuous' }) + .reply(200, response, JSON_HEADERS) + + // test GET /db/_changes + const p = await nano.db.changes('db', opts) + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() +}) + +test('should be able to handle a missing database - GET /db/_changes - nano.db.changes', async () => { + // mocks + mockPool + .intercept({ path: '/db/_changes' }) + .reply(404, errResponse, JSON_HEADERS) + + // test GET /db/_changes + await assert.rejects(nano.db.changes('db'), { message: 'Database does not exist.' }) + mockAgent.assertNoPendingInterceptors() +}) + +test('should not attempt invalid parameters - nano.db.changes', async () => { + await assert.rejects(nano.db.changes(), { message: 'Invalid parameters' }) + await assert.rejects(nano.db.changes(''), { message: 'Invalid parameters' }) +}) + +test('should detect missing parameters (callback) - nano.db.changes', async () => { + return new Promise((resolve, reject) => { + nano.db.changes(undefined, undefined, (err, data) => { + assert.notEqual(err, null) + resolve() + }) + }) +}) + +test('should be able to fetch the changes from db.changes - GET /db/_changes - db.changes', async () => { + // mocks + mockPool + .intercept({ path: '/db/_changes' }) + .reply(200, response, JSON_HEADERS) + + // test GET /db/_changes + const db = nano.db.use('db') + const p = await db.changes() + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() +}) From d14ff639be28b42537b2d420a24cd75b7a2dc523 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 20 Dec 2022 09:28:46 +0000 Subject: [PATCH 15/40] ensure "fetch" works on 16/18/19 --- lib/nano.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nano.js b/lib/nano.js index 77a6a48d..d45eaa7a 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -15,7 +15,7 @@ const assert = require('assert') const stream = require('stream') const Readable = stream.Readable const undici = require('undici') -const fetcher = fetch || global.fetch || undici.fetch +const fetcher = global.fetch || undici.fetch const ChangesReader = require('./changesreader.js') const CookieJar = require('./cookie.js') const MultiPartFactory = require('./multipart.js') From f5280d5ba8dfbac8379ab182e8406d79fc763f09 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 20 Dec 2022 09:36:23 +0000 Subject: [PATCH 16/40] fix test --- test/document.changesreader.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/document.changesreader.test.js b/test/document.changesreader.test.js index 3917d156..f22a947a 100644 --- a/test/document.changesreader.test.js +++ b/test/document.changesreader.test.js @@ -132,7 +132,7 @@ test('should emit change and batch events - db.changesReader.start', async () => assert.equal(seq, '1-0') db.changesReader.stop() resolve() - }) + }).on('error', reject) }) }) From aa9506dcb05439d3c28e107cf6e10c8522f8db09 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 20 Dec 2022 11:56:28 +0000 Subject: [PATCH 17/40] nvm use 16.18.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3bfd4e58..1a173085 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ dist: focal language: "node_js" node_js: - - "16.8.1" + - "16.18.1" - "18" - "19" services: From 3208204a378c7c1f277c78b35635ad838959f87b Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 9 Jan 2023 10:26:12 +0000 Subject: [PATCH 18/40] remove node 14 support --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 16dccef2..d7446b8c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x, 18.x] + node-version: [16.x, 18.x, 19.x] steps: - uses: actions/checkout@v3 From 7e8ffb8163943f8096e71c5e397a05546a59c5a0 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 11 Jan 2023 12:39:45 +0000 Subject: [PATCH 19/40] upgrade undici to 5.15.0 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index d48ffb28..e6f2cd4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "11.0.0", "license": "Apache-2.0", "dependencies": { - "undici": "^5.14.0" + "undici": "^5.15.0" }, "devDependencies": { "@types/node": "^18.11.15", @@ -58,9 +58,9 @@ } }, "node_modules/undici": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", - "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.15.0.tgz", + "integrity": "sha512-wCAZJDyjw9Myv+Ay62LAoB+hZLPW9SmKbQkbHIhMw/acKSlpn7WohdMUc/Vd4j1iSMBO0hWwU8mjB7a5p5bl8g==", "dependencies": { "busboy": "^1.6.0" }, @@ -96,9 +96,9 @@ "dev": true }, "undici": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", - "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.15.0.tgz", + "integrity": "sha512-wCAZJDyjw9Myv+Ay62LAoB+hZLPW9SmKbQkbHIhMw/acKSlpn7WohdMUc/Vd4j1iSMBO0hWwU8mjB7a5p5bl8g==", "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index f5c823c9..1782e69f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "database" ], "dependencies": { - "undici": "^5.14.0" + "undici": "^5.15.0" }, "devDependencies": { "@types/node": "^18.11.15", From cffcd42a232b22efe883978bdbdda15e121a0c9a Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 11 Jan 2023 13:00:39 +0000 Subject: [PATCH 20/40] merge in latest changes --- test/nano.auth.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/nano.auth.test.js b/test/nano.auth.test.js index 3623410f..2e5cd3b9 100644 --- a/test/nano.auth.test.js +++ b/test/nano.auth.test.js @@ -39,6 +39,7 @@ test('should be able to authenticate - POST /_session - nano.auth', async () => 'Set-Cookie': cookie } }) + mockPool .intercept({ path: '/_all_dbs', From 0e7c06b241a3c98998ba1dcd751ffc6a4de147de Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 14 Feb 2023 09:19:09 +0000 Subject: [PATCH 21/40] dependency bump --- package-lock.json | 42 +++++++++++++++++++++--------------------- package.json | 6 +++--- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ca81d35..a3a602ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,20 +9,20 @@ "version": "11.0.0", "license": "Apache-2.0", "dependencies": { - "undici": "^5.15.0" + "undici": "^5.19.1" }, "devDependencies": { - "@types/node": "^18.11.15", - "typescript": "^4.9.4" + "@types/node": "^18.13.0", + "typescript": "^4.9.5" }, "engines": { "node": ">=16.8" } }, "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", "dev": true }, "node_modules/busboy": { @@ -45,9 +45,9 @@ } }, "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -58,9 +58,9 @@ } }, "node_modules/undici": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.16.0.tgz", - "integrity": "sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.19.1.tgz", + "integrity": "sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==", "dependencies": { "busboy": "^1.6.0" }, @@ -71,9 +71,9 @@ }, "dependencies": { "@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", "dev": true }, "busboy": { @@ -90,15 +90,15 @@ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "undici": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.16.0.tgz", - "integrity": "sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.19.1.tgz", + "integrity": "sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==", "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index 1782e69f..436a107a 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,11 @@ "database" ], "dependencies": { - "undici": "^5.15.0" + "undici": "^5.19.1" }, "devDependencies": { - "@types/node": "^18.11.15", - "typescript": "^4.9.4" + "@types/node": "^18.13.0", + "typescript": "^4.9.5" }, "scripts": { "test": "tsc lib/nano.d.ts && node --test ./test/*.test.js" From aba321c10ca2f8baaa774e307bc71b36e5e96e31 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 14 Feb 2023 09:28:54 +0000 Subject: [PATCH 22/40] fix cookie handling bug --- lib/nano.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nano.js b/lib/nano.js index 72b3ac33..aa765227 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -152,7 +152,7 @@ module.exports = exports = function dbScope (cfg) { const responseHeaders = Object.assign({ uri: scrubURL(req.url), statusCode - }, response.headers ? Object.fromEntries(response.headers) : {}) + }, response.headers ? response.headers : {}) if (!response.status) { response.statusText = response.cause.toString() log({ err: 'socket', body, headers: responseHeaders }) From e0c738aeefd38658434c75528eb5b4e35d54ddeb Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 6 Mar 2023 11:03:49 +0000 Subject: [PATCH 23/40] dependency bump --- package-lock.json | 28 ++++++++++++++-------------- package.json | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3a602ff..b3ea8179 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "11.0.0", "license": "Apache-2.0", "dependencies": { - "undici": "^5.19.1" + "undici": "^5.20.0" }, "devDependencies": { - "@types/node": "^18.13.0", + "@types/node": "^18.14.6", "typescript": "^4.9.5" }, "engines": { @@ -20,9 +20,9 @@ } }, "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", "dev": true }, "node_modules/busboy": { @@ -58,9 +58,9 @@ } }, "node_modules/undici": { - "version": "5.19.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.19.1.tgz", - "integrity": "sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", + "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", "dependencies": { "busboy": "^1.6.0" }, @@ -71,9 +71,9 @@ }, "dependencies": { "@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", "dev": true }, "busboy": { @@ -96,9 +96,9 @@ "dev": true }, "undici": { - "version": "5.19.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.19.1.tgz", - "integrity": "sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", + "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index 436a107a..16b1be8e 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,10 @@ "database" ], "dependencies": { - "undici": "^5.19.1" + "undici": "^5.20.0" }, "devDependencies": { - "@types/node": "^18.13.0", + "@types/node": "^18.14.6", "typescript": "^4.9.5" }, "scripts": { From aa4cc70eadf5073ae9486484f915ce060d095427 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Fri, 24 Mar 2023 08:59:08 +0000 Subject: [PATCH 24/40] bump undici --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b3ea8179..e8c9dceb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "11.0.0", "license": "Apache-2.0", "dependencies": { - "undici": "^5.20.0" + "undici": "^5.21.0" }, "devDependencies": { "@types/node": "^18.14.6", @@ -58,9 +58,9 @@ } }, "node_modules/undici": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", - "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", + "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", "dependencies": { "busboy": "^1.6.0" }, @@ -96,9 +96,9 @@ "dev": true }, "undici": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", - "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", + "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index 16b1be8e..992a79b0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "database" ], "dependencies": { - "undici": "^5.20.0" + "undici": "^5.21.0" }, "devDependencies": { "@types/node": "^18.14.6", From 46e08ba576840c40aa0f7e7cf8f1b6880804382e Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 22 May 2023 15:19:42 +0100 Subject: [PATCH 25/40] dependency bump --- package-lock.json | 46 +++++++++++++++++++++++----------------------- package.json | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8c9dceb..178139a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,20 +9,20 @@ "version": "11.0.0", "license": "Apache-2.0", "dependencies": { - "undici": "^5.21.0" + "undici": "^5.22.1" }, "devDependencies": { - "@types/node": "^18.14.6", - "typescript": "^4.9.5" + "@types/node": "^20.2.3", + "typescript": "^5.0.4" }, "engines": { "node": ">=16.8" } }, "node_modules/@types/node": { - "version": "18.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", - "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", + "version": "20.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", + "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==", "dev": true }, "node_modules/busboy": { @@ -45,35 +45,35 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/undici": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", - "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", "dependencies": { "busboy": "^1.6.0" }, "engines": { - "node": ">=12.18" + "node": ">=14.0" } } }, "dependencies": { "@types/node": { - "version": "18.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", - "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", + "version": "20.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", + "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==", "dev": true }, "busboy": { @@ -90,15 +90,15 @@ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" }, "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true }, "undici": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", - "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index 992a79b0..59dc8a87 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,11 @@ "database" ], "dependencies": { - "undici": "^5.21.0" + "undici": "^5.22.1" }, "devDependencies": { - "@types/node": "^18.14.6", - "typescript": "^4.9.5" + "@types/node": "^20.2.3", + "typescript": "^5.0.4" }, "scripts": { "test": "tsc lib/nano.d.ts && node --test ./test/*.test.js" From c181a39b57d5e3f1cd503f09f3b3e44ef7f9bb65 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 22 May 2023 15:23:26 +0100 Subject: [PATCH 26/40] add node 20 to testing matrix --- .github/workflows/ci.yaml | 2 +- test/attachment.getAsStream.test.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d7446b8c..2d44a1f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x, 19.x] + node-version: [16.x, 18.x, 20.x] steps: - uses: actions/checkout@v3 diff --git a/test/attachment.getAsStream.test.js b/test/attachment.getAsStream.test.js index b217bed0..35909b86 100644 --- a/test/attachment.getAsStream.test.js +++ b/test/attachment.getAsStream.test.js @@ -50,7 +50,6 @@ test('should emit an error when stream attachment does not exist - GET /db/id/at const db = nano.db.use('db') db.attachment.getAsStream('id', 'notexist.gif') .on('error', (e) => { - console.log(e) assert.equal(e.statusCode, 404) resolve() }) From 9c42fc3ee924adcb07e7a931841a75c1708632d6 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 18 Sep 2023 12:56:56 +0100 Subject: [PATCH 27/40] pre v11 release tidy up --- .github/workflows/ci.yaml | 2 +- NOTICE | 2 +- README.md | 6 ++++- lib/nano.js | 16 +++-------- migration_8_to_9.md | 43 ------------------------------ package-lock.json | 56 +++++++++++++++++++++------------------ package.json | 15 ++++------- test/nano.agent.test.js | 5 ++-- 8 files changed, 49 insertions(+), 96 deletions(-) delete mode 100644 migration_8_to_9.md diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2d44a1f0..9a3750c6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x] steps: - uses: actions/checkout@v3 diff --git a/NOTICE b/NOTICE index ca01fe4b..a6c08859 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache CouchDB Nano -Copyright [2016-2018] The Apache Software Foundation +Copyright [2016-2013] The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index c92b6b51..8a33830f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Offical [Apache CouchDB](https://couchdb.apache.org/) library for [Node.js](https://nodejs.org/). +> Note: Nano >=11.0.0 is for Node 18/20 and above. If you are using Node 16 or older, you need Nano 10.1.2. + Features: * **Minimalistic** - There is only a minimum of abstraction between you and @@ -241,7 +243,9 @@ const agentOptions = { connections: null, maxRedirections: 0 } -const nano = Nano({ url: 'http://127.0.0.1:5984', agentOptions }) +const undici = require('undici') +const undiciOptions = new undici.Agent(agentOptions) +const nano = Nano({ url: 'http://127.0.0.1:5984', undiciOptions }) ``` The meanings of the agentOptions attributes is described [here](https://undici.nodejs.org/#/docs/api/Agent?id=new-undiciagentoptions), [here](https://undici.nodejs.org/#/docs/api/Pool?id=parameter-pooloptions) and [here](https://undici.nodejs.org/#/docs/api/Client?id=parameter-clientoptions) diff --git a/lib/nano.js b/lib/nano.js index aa765227..9e470434 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -11,13 +11,9 @@ // the License. const { URL } = require('url') -const http = require('http') -const https = require('https') const assert = require('assert') const stream = require('stream') const Readable = stream.Readable -const undici = require('undici') -const fetcher = global.fetch || undici.fetch const ChangesReader = require('./changesreader.js') const CookieJar = require('./cookie.js') const MultiPartFactory = require('./multipart.js') @@ -86,11 +82,7 @@ module.exports = exports = function dbScope (cfg) { // if we've been passed a undici.Agent or undici.MockAgent, // basically anything inherited from undici.Dispatcher, we // can use it - if (cfg.agentOptions instanceof undici.Dispatcher) { - cfg.agent = cfg.agentOptions - } else if (typeof cfg.agentOptions === 'object') { - cfg.agent = new undici.Agent(cfg.agentOptions) - } + cfg.agent = cfg.agentOptions } // warn using still using requestDefaults @@ -445,7 +437,7 @@ module.exports = exports = function dbScope (cfg) { if (opts.stream) { // return the Request object for streaming const outStream = new stream.PassThrough() - fetcher(fetchOptions.url, fetchOptions).then((response) => { + fetch(fetchOptions.url, fetchOptions).then((response) => { const readableWebStream = response.body const readableNodeStream = Readable.fromWeb ? Readable.fromWeb(readableWebStream) : Readable.from(readableWebStream) if (response.status > 300) { @@ -459,14 +451,14 @@ module.exports = exports = function dbScope (cfg) { return outStream } else { if (typeof callback === 'function') { - fetcher(fetchOptions.url, fetchOptions).then((response) => { + fetch(fetchOptions.url, fetchOptions).then((response) => { responseHandler(response, fetchOptions, opts, null, null, callback) }).catch((e) => { responseHandler(e, fetchOptions, opts, null, null, callback) }) } else { return new Promise((resolve, reject) => { - fetcher(fetchOptions.url, fetchOptions).then((response) => { + fetch(fetchOptions.url, fetchOptions).then((response) => { responseHandler(response, fetchOptions, opts, resolve, reject) }).catch((e) => { responseHandler(e, fetchOptions, opts, resolve, reject) diff --git a/migration_8_to_9.md b/migration_8_to_9.md deleted file mode 100644 index fb29ee1f..00000000 --- a/migration_8_to_9.md +++ /dev/null @@ -1,43 +0,0 @@ -# Migration Guide for moving from Nano 8.x to 9.x - -The 9.x release of Nano sees the following changes: - -- the underlying library that handles HTTP request changes to [axios](https://www.npmjs.com/package/axios) as the previous library has been deprecated. -- the number of dependencies has been reduced - there are now only two runtime dependencies. -- the changes feed handler has been rewritten and bundled as part of Nano. See "changesReader". -- reworked custom logging. - -Most Nano users will be able to switch from Nano 8.x to Nano 9.x without modifying any code but as this is a major version release, some things have changed which _may_ break your code - pay particular attention if you were using the "Follow" library or had configured custom logging. - -## Following the changes feed - -The changes feed reader is completely rewritten and has a new interface: - -```js -const db = nano.db.use('mydb') -db.changesReader.start({ batchSize: 50 }) - .on('batch', (b) => { - console.log('a batch of', b.length, 'changes has arrived'); - }).on('seq', (s) => { - console.log('sequence token', s); - }).on('error', (e) => { - console.error('error', e); - }) -``` - -## Logging - -```js -const url = require('url') -const logger = (data) => { - // if this is a request - if (typeof data.err === 'undefined') { - const u = new url.URL(data.uri) - console.log(data.method, u.pathname, data.qs) - } else { - // this is a response - const prefix = data.err ? 'ERR' : 'OK' - console.log(prefix, data.headers.statusCode, JSON.stringify(data.body).length) - } -} -const nano = Nano({ url: process.env.COUCH_URL, log: logger }) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 178139a7..d148b87a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,27 +8,26 @@ "name": "nano", "version": "11.0.0", "license": "Apache-2.0", - "dependencies": { - "undici": "^5.22.1" - }, "devDependencies": { - "@types/node": "^20.2.3", - "typescript": "^5.0.4" + "@types/node": "^20.6.2", + "typescript": "^5.2.2", + "undici": "^5.24.0" }, "engines": { - "node": ">=16.8" + "node": ">=18.0" } }, "node_modules/@types/node": { - "version": "20.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", - "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==", + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, "dependencies": { "streamsearch": "^1.1.0" }, @@ -40,27 +39,29 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, "engines": { "node": ">=10.0.0" } }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.24.0.tgz", + "integrity": "sha512-OKlckxBjFl0oXxcj9FU6oB8fDAaiRUq+D8jrFWGmOfI/gIyjk/IeS75LMzgYKUaeHzLUcYvf9bbJGSrUwTfwwQ==", + "dev": true, "dependencies": { "busboy": "^1.6.0" }, @@ -71,15 +72,16 @@ }, "dependencies": { "@types/node": { - "version": "20.2.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.3.tgz", - "integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==", + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, "busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, "requires": { "streamsearch": "^1.1.0" } @@ -87,18 +89,20 @@ "streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true }, "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true }, "undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.24.0.tgz", + "integrity": "sha512-OKlckxBjFl0oXxcj9FU6oB8fDAaiRUq+D8jrFWGmOfI/gIyjk/IeS75LMzgYKUaeHzLUcYvf9bbJGSrUwTfwwQ==", + "dev": true, "requires": { "busboy": "^1.6.0" } diff --git a/package.json b/package.json index 59dc8a87..4bff7f73 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,11 @@ "database" ], "dependencies": { - "undici": "^5.22.1" }, "devDependencies": { - "@types/node": "^20.2.3", - "typescript": "^5.0.4" + "undici": "^5.24.0", + "@types/node": "^20.6.2", + "typescript": "^5.2.2" }, "scripts": { "test": "tsc lib/nano.d.ts && node --test ./test/*.test.js" @@ -29,14 +29,9 @@ "main": "./lib/nano.js", "types": "./lib/nano.d.ts", "engines": { - "node": ">=16.8" + "node": ">=18.0" }, "pre-commit": [ "test" - ], - "standard": { - "env": [ - "jest" - ] - } + ] } diff --git a/test/nano.agent.test.js b/test/nano.agent.test.js index 4397af0c..a124b0d9 100644 --- a/test/nano.agent.test.js +++ b/test/nano.agent.test.js @@ -8,8 +8,9 @@ test('should be able to supply a custom agent parameters', async () => { const agentOptions = { bodyTimeout: 10000 } - const nano = Nano({ url: COUCH_URL, agentOptions }) - assert(nano.config.agent instanceof undici.Agent) + const undiciOptions = new undici.Agent(agentOptions) + const nano = Nano({ url: COUCH_URL, undiciOptions }) + assert.equal(nano.config.agent, nano.config.agent) }) test('should be able to supply a custom agent', async () => { From e16ad540b9f23e32e561c2f3d77541fa72d6f097 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Tue, 2 Jan 2024 14:51:22 +0000 Subject: [PATCH 28/40] latest dependencies --- package-lock.json | 59 ++++++++++++++++++++++------------------------- package.json | 6 ++--- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5320246e..b2ad5cad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,45 +9,36 @@ "version": "11.0.0", "license": "Apache-2.0", "devDependencies": { - "@types/node": "^20.6.2", - "typescript": "^5.2.2", - "undici": "^5.24.0" + "@types/node": "^20.10.6", + "typescript": "^5.3.3", + "undici": "^6.2.1" }, "engines": { "node": ">=18.0" } }, - "node_modules/@types/node": { - "version": "20.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", - "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", - "dev": true - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", "dev": true, - "dependencies": { - "streamsearch": "^1.1.0" - }, "engines": { - "node": ">=10.16.0" + "node": ">=14" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "node_modules/@types/node": { + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", "dev": true, - "engines": { - "node": ">=10.0.0" + "dependencies": { + "undici-types": "~5.26.4" } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -58,16 +49,22 @@ } }, "node_modules/undici": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.24.0.tgz", - "integrity": "sha512-OKlckxBjFl0oXxcj9FU6oB8fDAaiRUq+D8jrFWGmOfI/gIyjk/IeS75LMzgYKUaeHzLUcYvf9bbJGSrUwTfwwQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.2.1.tgz", + "integrity": "sha512-7Wa9thEM6/LMnnKtxJHlc8SrTlDmxqJecgz1iy8KlsN0/iskQXOQCuPkrZLXbElPaSw5slFFyKIKXyJ3UtbApw==", "dev": true, "dependencies": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" }, "engines": { - "node": ">=14.0" + "node": ">=18.0" } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true } } } diff --git a/package.json b/package.json index 4bff7f73..614ff591 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,9 @@ "dependencies": { }, "devDependencies": { - "undici": "^5.24.0", - "@types/node": "^20.6.2", - "typescript": "^5.2.2" + "undici": "^6.2.1", + "@types/node": "^20.10.6", + "typescript": "^5.3.3" }, "scripts": { "test": "tsc lib/nano.d.ts && node --test ./test/*.test.js" From b7c560c3b5eb4a7d3b4e0d3e34cfee0a3e4cb6e4 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Wed, 14 Aug 2024 13:35:56 +0100 Subject: [PATCH 29/40] add Node v22 to the CI - it's been that long --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9a3750c6..c5bcc78b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x] steps: - uses: actions/checkout@v3 From 47d4663a4531a582f5d5f5af0018c6ecdf7fcc46 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 4 Nov 2024 10:15:17 +0000 Subject: [PATCH 30/40] Update NOTICE Co-authored-by: Jan Lehnardt --- NOTICE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE b/NOTICE index a6c08859..4d637b65 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache CouchDB Nano -Copyright [2016-2013] The Apache Software Foundation +Copyright [2016-2024] The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). From c62d5080d633d883e91d048216a3313155806986 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 4 Nov 2024 10:23:07 +0000 Subject: [PATCH 31/40] use contentType instead of ct --- lib/nano.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nano.js b/lib/nano.js index 9e470434..75776c2c 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -165,15 +165,15 @@ module.exports = exports = function dbScope (cfg) { if (statusCode >= 200 && statusCode < 400) { // collect response - const ct = response.headers.get('content-type') + const contentType = response.headers.get('content-type') let retval = '' - if (ct === 'application/json') { + if (contentType === 'application/json') { try { retval = await response.json() } catch { // do nothing } - } else if (ct && (ct.startsWith('text/') || ct.startsWith('multipart/related'))) { + } else if (contentType && (contentType.startsWith('text/') || contentType.startsWith('multipart/related'))) { retval = await response.text() } else { const ab = await response.arrayBuffer() From 4f05cdb2250bdabcd0e78e7dbd6e8d59365cf15c Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 4 Nov 2024 11:11:55 +0000 Subject: [PATCH 32/40] beefed up the "breaking change" nature of Nano 11 for Node 16 (and older) users --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6f689e3..076bf76f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Offical [Apache CouchDB](https://couchdb.apache.org/) library for [Node.js](https://nodejs.org/). -> Note: Nano >=11.0.0 is for Node 18/20 and above. If you are using Node 16 or older, you need Nano 10.1.2. +> Note: Nano >=11.0.0 is a **breaking change for Node.js versions 16 and older**. Nano 11 uses Node.js's built-in "fetch" HTTP client but this is only available in Node.js versions 18 or later. If you are using Node 16 or older then continue using Nano 10. Features: From e95b56b47f1f078d0ccc150829faad5eba29be38 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 4 Nov 2024 11:27:15 +0000 Subject: [PATCH 33/40] assertion failures are rendered differently in Node 22, so the tests no longer look for exact strings being returned in the assertion failure as that is flaky --- test/nano.config.test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/nano.config.test.js b/test/nano.config.test.js index 80218aa1..3209dd79 100644 --- a/test/nano.config.test.js +++ b/test/nano.config.test.js @@ -69,7 +69,6 @@ test('should be able to handle missing URL - nano.config', () => { Nano() } catch (e) { assert(e instanceof assert.AssertionError) - assert.equal(e.message, 'You must specify the endpoint url when invoking this module') } }) @@ -79,7 +78,6 @@ test('should be able to handle invalid URL #1 - nano.config', () => { Nano(INVALID_URL) } catch (e) { assert(e instanceof assert.AssertionError) - assert.equal(e.message, 'url is not valid') } }) @@ -89,7 +87,6 @@ test('should be able to handle invalid URL #2 - nano.config', () => { Nano({ url: INVALID_URL }) } catch (e) { assert(e instanceof assert.AssertionError) - assert.equal(e.message, 'url is not valid') } }) From ff2911152234f3cd2838087afe5540d615a3b6bf Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Mon, 4 Nov 2024 11:47:38 +0000 Subject: [PATCH 34/40] added migration guide --- README.md | 1 + migration_guide_v10_to_v11.md | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 migration_guide_v10_to_v11.md diff --git a/README.md b/README.md index 076bf76f..0799119d 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Offical [Apache CouchDB](https://couchdb.apache.org/) library for [Node.js](https://nodejs.org/). > Note: Nano >=11.0.0 is a **breaking change for Node.js versions 16 and older**. Nano 11 uses Node.js's built-in "fetch" HTTP client but this is only available in Node.js versions 18 or later. If you are using Node 16 or older then continue using Nano 10. +> See our [migration guide](migration_guide_v10_to_v11.md) for moving from Nano 10 to Nano 11. Features: diff --git a/migration_guide_v10_to_v11.md b/migration_guide_v10_to_v11.md new file mode 100644 index 00000000..2883a69c --- /dev/null +++ b/migration_guide_v10_to_v11.md @@ -0,0 +1,45 @@ +# Migrating from Nano 10 to Nano 11 + +Nano 10 uses the Axios library as an HTTP/HTTPS client. Keeping up with changes to Axios and its dependencies made maintaining this library a chore, so as of Nano 11 we use Node.js's built-in _fetch_ API as our HTTP client. This makes Nano a _zero dependency_ library which makes for faster installs, easier maintenance and slightly better performance. + +There are some things to bear in mind if you are switching from Nano 10 to Nano 11, so please consider the following advice carefully before you do. + +## Node.js versions + +> ** Nano 11 is a breaking change for users of Node.s 16 or earlier ** + +Nano 11 is only compatible with Node.js versions 18 and older, because it is only these Node versions that have the [fetch](https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#fetch) HTTP client baked in. See [Node.js's Long-term Support page](https://nodejs.org/en/about/previous-releases) to see which are the currently supported and maintained versions. In short: + +- If you are using Node.js 18 or newer, use Nano 11. +- If you need to use Node.js 16 or older, use Nano 10. + +Nano 10 may continue to receive some security fixes for a time, but Nano 11 represents the future of this project and at some point, support for Nano 10 will cease. + +## Agent options + +None of Nano's API has changed _except_ when a user is supplying non-default connection handling parameters. Gone is `requestDefaults` which dates back to the "request" days and instead an optional `agentOptions` can be provided which is documented in the README and in TypeScript. + +```js +const agentOptions = { + bodyTimeout: 30000, + headersTimeout: 30000, + keepAliveMaxTimeout: 600000, + keepAliveTimeout: 30000, + keepAliveTimeoutThreshold: 1000, + maxHeaderSize: 16384, + maxResponseSize: -1, + pipelining: 6, + connect: { + timeout: 10000 + }, + strictContentLength: true, + connections: null, + maxRedirections: 0 +} +const undici = require('undici') +const undiciOptions = new undici.Agent(agentOptions) +const nano = Nano({ url: 'http://127.0.0.1:5984', undiciOptions }) +``` + +> Note: to supply a custom agent, you will need the [undici](https://www.npmjs.com/package/undici) module as a dependency in your own project. Undici is the library that powers Node.js's _fetch_ API but its "Agent" is not programmatically accessible unless undici is imported separately. + From e0a42f7dffe46ce27f7b965b6fd0f778117ee3cd Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 7 Nov 2024 09:51:40 +0000 Subject: [PATCH 35/40] strip callback support from Nano and remove any tests that tested the callback variant --- lib/nano.js | 455 +++++++++------------- test/attachment.destroy.test.js | 9 - test/attachment.get.test.js | 9 - test/attachment.insert.test.js | 10 - test/database.changes.test.js | 9 - test/database.compact.test.js | 9 - test/database.create.test.js | 8 - test/database.destroy.test.js | 8 - test/database.get.test.js | 8 - test/database.replicate.test.js | 9 - test/database.replication.disable.test.js | 9 - test/database.replication.enable.test.js | 9 - test/database.replication.query.test.js | 9 - test/design.atomic.test.js | 20 - test/design.createIndex.test.js | 9 - test/design.find.test.js | 9 - test/design.search.test.js | 9 - test/design.show.test.js | 9 - test/design.view.test.js | 9 - test/document.destroy.test.js | 9 - test/document.fetch.test.js | 9 - test/document.fetchRevs.test.js | 9 - test/document.get.test.js | 10 - test/document.head.test.js | 35 -- test/multipart.get.test.js | 9 - test/multipart.insert.test.js | 9 - test/nano.request.test.js | 103 +---- test/nano.uuids.test.js | 22 -- test/partition.find.test.js | 9 - test/partition.info.test.js | 25 -- test/partition.list.test.js | 36 +- test/partition.search.test.js | 9 - test/partition.view.test.js | 9 - 33 files changed, 189 insertions(+), 740 deletions(-) diff --git a/lib/nano.js b/lib/nano.js index 75776c2c..ed337808 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -25,32 +25,14 @@ function isEmpty (val) { return val == null || !(Object.keys(val) || val).length } -function getCallback (opts, callback) { - if (typeof opts === 'function') { - callback = opts - opts = {} - } - opts = opts || {} - return { - opts, - callback - } -} - // feed this any number of arguments, it will return true if // any of them are missing (falsey) function missing (...params) { return params.some(param => !param) } -// calls the supplied callback or if not supplied, returns a rejected promise -function callbackOrRejectError (callback, error = new Error('Invalid parameters')) { - if (callback) { - return callback(error, null) - } else { - return Promise.reject(error) - } -} +// the stock error returned when a call has missing or invalid parameters +const invalidParametersError = new Error('Invalid parameters') module.exports = exports = function dbScope (cfg) { let serverScope = {} @@ -127,7 +109,7 @@ module.exports = exports = function dbScope (cfg) { } } - const responseHandler = async function (response, req, opts, resolve, reject, callback) { + const responseHandler = async function (response, req, opts, resolve, reject) { const statusCode = response.status || 500 let body = response.body response.statusCode = statusCode @@ -151,12 +133,6 @@ module.exports = exports = function dbScope (cfg) { if (reject) { reject(new Error(`error happened in your connection. Reason: ${response.statusText}`)) } - if (callback) { - const returnError = new Error(`error happened in your connection. Reason: ${response.statusText}`) - returnError.scope = 'socket' - returnError.errid = 'request' - callback(returnError) - } return } @@ -167,7 +143,10 @@ module.exports = exports = function dbScope (cfg) { // collect response const contentType = response.headers.get('content-type') let retval = '' - if (contentType === 'application/json') { + // when doing head requests, we return the response headers, not the response body + if (req.method === 'head') { + retval = Object.fromEntries(response.headers) + } else if (contentType === 'application/json') { try { retval = await response.json() } catch { @@ -186,9 +165,6 @@ module.exports = exports = function dbScope (cfg) { // promisey if (resolve) { resolve(retval) - } else if (callback) { - // callbacky - callback(null, retval, Object.fromEntries(response.headers)) } return } @@ -234,9 +210,6 @@ module.exports = exports = function dbScope (cfg) { if (reject) { reject(errors) } - if (callback) { - callback(errors) - } } const streamResponseHandler = function (response, req, stream) { @@ -265,9 +238,8 @@ module.exports = exports = function dbScope (cfg) { }, 10) } - function relax (opts, callback) { + function relax (opts) { if (typeof opts === 'function') { - callback = opts opts = { path: '' } } if (typeof opts === 'string') { @@ -275,7 +247,6 @@ module.exports = exports = function dbScope (cfg) { } if (!opts) { opts = { path: '' } - callback = null } // the building blocks of the request @@ -450,26 +421,18 @@ module.exports = exports = function dbScope (cfg) { }) return outStream } else { - if (typeof callback === 'function') { + return new Promise((resolve, reject) => { fetch(fetchOptions.url, fetchOptions).then((response) => { - responseHandler(response, fetchOptions, opts, null, null, callback) + responseHandler(response, fetchOptions, opts, resolve, reject) }).catch((e) => { - responseHandler(e, fetchOptions, opts, null, null, callback) - }) - } else { - return new Promise((resolve, reject) => { - fetch(fetchOptions.url, fetchOptions).then((response) => { - responseHandler(response, fetchOptions, opts, resolve, reject) - }).catch((e) => { - responseHandler(e, fetchOptions, opts, resolve, reject) - }) + responseHandler(e, fetchOptions, opts, resolve, reject) }) - } + }) } } // http://docs.couchdb.org/en/latest/api/server/authn.html#cookie-authentication - function auth (username, password, callback) { + function auth (username, password) { return relax({ method: 'POST', db: '_session', @@ -477,56 +440,54 @@ module.exports = exports = function dbScope (cfg) { name: username, password } - }, callback) + }) } // http://docs.couchdb.org/en/latest/api/server/authn.html#post--_session - function session (callback) { - return relax({ db: '_session' }, callback) + function session () { + return relax({ db: '_session' }) } // https://docs.couchdb.org/en/latest/api/server/common.html#api-server-root - function info (callback) { - return relax({ path: '' }, callback) + function info () { + return relax({ path: '' }) } // http://docs.couchdb.org/en/latest/api/server/common.html#get--_db_updates - function updates (qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function updates (qs) { return relax({ db: '_db_updates', - qs: opts - }, callback) + qs + }) } // http://docs.couchdb.org/en/latest/api/database/common.html#put--db - function createDb (dbName, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function createDb (dbName, qs) { if (missing(dbName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return relax({ db: dbName, method: 'PUT', qs: opts }, callback) + return relax({ db: dbName, method: 'PUT', qs }) } // http://docs.couchdb.org/en/latest/api/database/common.html#delete--db - function destroyDb (dbName, callback) { + function destroyDb (dbName) { if (missing(dbName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return relax({ db: dbName, method: 'DELETE' }, callback) + return relax({ db: dbName, method: 'DELETE' }) } // http://docs.couchdb.org/en/latest/api/database/common.html#get--db - function getDb (dbName, callback) { + function getDb (dbName) { if (missing(dbName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return relax({ db: dbName }, callback) + return relax({ db: dbName }) } // http://docs.couchdb.org/en/latest/api/server/common.html#get--_all_dbs - function listDbs (callback) { - return relax({ db: '_all_dbs' }, callback) + function listDbs () { + return relax({ db: '_all_dbs' }) } // http://docs.couchdb.org/en/latest/api/server/common.html#get--_all_dbs @@ -535,33 +496,28 @@ module.exports = exports = function dbScope (cfg) { } // http://docs.couchdb.org/en/latest/api/database/compact.html#post--db-_compact - function compactDb (dbName, ddoc, callback) { - if (typeof ddoc === 'function') { - callback = ddoc - ddoc = null - } + function compactDb (dbName, ddoc) { if (missing(dbName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ db: dbName, doc: '_compact', att: ddoc, method: 'POST' - }, callback) + }) } // http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes - function changesDb (dbName, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function changesDb (dbName, qs) { if (missing(dbName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return relax({ db: dbName, path: '_changes', qs: opts }, callback) + return relax({ db: dbName, path: '_changes', qs }) } - function changesDbAsStream (dbName, opts) { - return relax({ db: dbName, path: '_changes', stream: true, qs: opts }) + function changesDbAsStream (dbName, qs) { + return relax({ db: dbName, path: '_changes', stream: true, qs }) } function _serializeAsUrl (db) { @@ -580,67 +536,61 @@ module.exports = exports = function dbScope (cfg) { } // http://docs.couchdb.org/en/latest/api/server/common.html#post--_replicate - function replicateDb (source, target, opts0, callback0) { - const { opts, callback } = getCallback(opts0, callback0) - + function replicateDb (source, target, opts) { if (missing(source, target)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } // _replicate + opts = opts || {} opts.source = _serializeAsUrl(source) opts.target = _serializeAsUrl(target) - return relax({ db: '_replicate', body: opts, method: 'POST' }, callback) + return relax({ db: '_replicate', body: opts, method: 'POST' }) } // http://docs.couchdb.org/en/latest/api/server/common.html#uuids - function uuids (count, callback) { - if (typeof count === 'function') { - callback = count - count = 1 - } + function uuids (count) { count = count || 1 - return relax({ method: 'GET', path: '_uuids', qs: { count } }, callback) + return relax({ method: 'GET', path: '_uuids', qs: { count } }) } // http://guide.couchdb.org/draft/replication.html - function enableReplication (source, target, opts0, callback0) { - const { opts, callback } = getCallback(opts0, callback0) + function enableReplication (source, target, opts) { if (missing(source, target)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } // _replicator + opts = opts || {} opts.source = _serializeAsUrl(source) opts.target = _serializeAsUrl(target) - return relax({ db: '_replicator', body: opts, method: 'POST' }, callback) + return relax({ db: '_replicator', body: opts, method: 'POST' }) } // http://guide.couchdb.org/draft/replication.html - function queryReplication (id, opts0, callback0) { - const { opts, callback } = getCallback(opts0, callback0) + function queryReplication (id, qs) { if (missing(id)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return relax({ db: '_replicator', method: 'GET', path: id, qs: opts }, callback) + return relax({ db: '_replicator', method: 'GET', path: id, qs }) } // http://guide.couchdb.org/draft/replication.html - function disableReplication (id, rev, opts0, callback0) { - const { opts, callback } = getCallback(opts0, callback0) + function disableReplication (id, rev, opts) { if (missing(id, rev)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } + opts = opts || {} const req = { db: '_replicator', method: 'DELETE', path: id, qs: Object.assign(opts, { rev }) } - return relax(req, callback) + return relax(req) } function docModule (dbName) { @@ -649,31 +599,29 @@ module.exports = exports = function dbScope (cfg) { // http://docs.couchdb.org/en/latest/api/document/common.html#put--db-docid // http://docs.couchdb.org/en/latest/api/database/common.html#post--db - function insertDoc (doc, qs0, callback0) { + function insertDoc (doc, qs ) { const req = { db: dbName, body: doc, method: 'POST' } - let { opts, callback } = getCallback(qs0, callback0) - - if (typeof opts === 'string') { - opts = { docName: opts } + if (typeof qs === 'string') { + qs = { docName: qs } } - if (opts) { - if (opts.docName) { - req.doc = opts.docName + if (qs) { + if (qs.docName) { + req.doc = qs.docName req.method = 'PUT' - delete opts.docName + delete qs.docName } - req.qs = opts + req.qs = qs } - return relax(req, callback) + return relax(req) } // http://docs.couchdb.org/en/latest/api/document/common.html#delete--db-docid - function destroyDoc (docName, rev, callback) { + function destroyDoc (docName, rev) { if (missing(docName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -681,72 +629,49 @@ module.exports = exports = function dbScope (cfg) { doc: docName, method: 'DELETE', qs: { rev } - }, callback) + }) } // http://docs.couchdb.org/en/latest/api/document/common.html#get--db-docid - function getDoc (docName, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) - + function getDoc (docName, qs) { if (missing(docName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return relax({ db: dbName, doc: docName, qs: opts }, callback) + return relax({ db: dbName, doc: docName, qs }) } // http://docs.couchdb.org/en/latest/api/document/common.html#head--db-docid - function headDoc (docName, callback) { + function headDoc (docName) { if (missing(docName)) { - return callbackOrRejectError(callback) - } - if (callback) { - relax({ - db: dbName, - doc: docName, - method: 'HEAD', - qs: {} - }, callback) - } else { - // this function doesn't pass on the Promise from relax because it needs - // to return the headers when resolving the Promise - return new Promise(function (resolve, reject) { - relax({ - db: dbName, - doc: docName, - method: 'HEAD', - qs: {} - }, function (err, body, headers) { - if (err) { - reject(err) - } else { - resolve(headers) - } - }) - }) + return Promise.reject(invalidParametersError) } + return relax({ + db: dbName, + doc: docName, + method: 'HEAD' + }) } // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs - function listDoc (qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) - return relax({ db: dbName, path: '_all_docs', qs: opts }, callback) + function listDoc (qs) { + return relax({ db: dbName, path: '_all_docs', qs }) } // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs - function listDocAsStream (opts) { - return relax({ db: dbName, path: '_all_docs', qs: opts, stream: true }) + function listDocAsStream (qs) { + return relax({ db: dbName, path: '_all_docs', qs, stream: true }) } // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs - function fetchDocs (docNames, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function fetchDocs (docNames, qs) { + const opts = qs || {} opts.include_docs = true if (missing(docNames) || typeof docNames !== 'object' || !docNames.keys || !Array.isArray(docNames.keys) || docNames.keys.length === 0) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -755,32 +680,29 @@ module.exports = exports = function dbScope (cfg) { method: 'POST', qs: opts, body: docNames - }, callback) + }) } - function fetchRevs (docNames, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function fetchRevs (docNames, qs) { if (missing(docNames) || typeof docNames !== 'object' || !docNames.keys || !Array.isArray(docNames.keys) || docNames.keys.length === 0) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ db: dbName, path: '_all_docs', method: 'POST', - qs: opts, + qs, body: docNames - }, callback) + }) } - function view (ddoc, viewName, meta, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) - + function view (ddoc, viewName, meta, qs) { if (missing(ddoc, viewName) && !meta.viewPath) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } if (typeof meta.stream !== 'boolean') { @@ -788,7 +710,7 @@ module.exports = exports = function dbScope (cfg) { } // prevent mutation of the client qs object by using a clone - const qs1 = Object.assign({}, opts) + const qs1 = Object.assign({}, qs) const viewPath = meta.viewPath || '_design/' + ddoc + '/_' + meta.type + '/' + viewName @@ -800,7 +722,7 @@ module.exports = exports = function dbScope (cfg) { method: 'POST', body: qs1, stream: meta.stream - }, callback) + }) } else if (qs1 && qs1.keys) { const body = { keys: qs1.keys } delete qs1.keys @@ -811,7 +733,7 @@ module.exports = exports = function dbScope (cfg) { qs: qs1, body, stream: meta.stream - }, callback) + }) } else if (qs1 && qs1.queries) { const body = { queries: qs1.queries } delete qs1.queries @@ -821,7 +743,7 @@ module.exports = exports = function dbScope (cfg) { method: 'POST', qs: qs1, body - }, callback) + }) } else { const req = { db: dbName, @@ -835,13 +757,13 @@ module.exports = exports = function dbScope (cfg) { req.body = meta.body } - return relax(req, callback) + return relax(req) } } // http://docs.couchdb.org/en/latest/api/ddoc/views.html#post--db-_design-ddoc-_view-view - function viewDocs (ddoc, viewName, qs, callback) { - return view(ddoc, viewName, { type: 'view' }, qs, callback) + function viewDocs (ddoc, viewName, qs) { + return view(ddoc, viewName, { type: 'view' }, qs) } // http://docs.couchdb.org/en/latest/api/ddoc/views.html#post--db-_design-ddoc-_view-view @@ -850,8 +772,8 @@ module.exports = exports = function dbScope (cfg) { } // cloudant - function viewSearch (ddoc, viewName, qs, callback) { - return view(ddoc, viewName, { type: 'search' }, qs, callback) + function viewSearch (ddoc, viewName, qs) { + return view(ddoc, viewName, { type: 'search' }, qs) } // cloudant @@ -860,56 +782,52 @@ module.exports = exports = function dbScope (cfg) { } // http://docs.couchdb.org/en/latest/api/ddoc/render.html#get--db-_design-ddoc-_show-func - function showDoc (ddoc, viewName, docName, qs, callback) { + function showDoc (ddoc, viewName, docName, qs) { if (missing(ddoc, viewName, docName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } - return view(ddoc, viewName + '/' + docName, { type: 'show' }, qs, callback) + return view(ddoc, viewName + '/' + docName, { type: 'show' }, qs) } // http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid - function updateWithHandler (ddoc, viewName, docName, body, callback) { - if (typeof body === 'function') { - callback = body - body = undefined - } + function updateWithHandler (ddoc, viewName, docName, body) { if (missing(ddoc, viewName, docName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return view(ddoc, viewName + '/' + encodeURIComponent(docName), { type: 'update', method: 'PUT', body - }, callback) + }) } - function viewWithList (ddoc, viewName, listName, qs, callback) { + function viewWithList (ddoc, viewName, listName, qs) { return view(ddoc, listName + '/' + viewName, { type: 'list' - }, qs, callback) + }, qs) } - function viewWithListAsStream (ddoc, viewName, listName, qs, callback) { + function viewWithListAsStream (ddoc, viewName, listName, qs) { return view(ddoc, listName + '/' + viewName, { - type: 'list', stream: true - }, qs, callback) + type: 'list', + stream: true + }, qs) } // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_bulksDoc - function bulksDoc (docs, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function bulksDoc (docs, qs) { return relax({ db: dbName, path: '_bulk_docs', body: docs, method: 'POST', - qs: opts - }, callback) + qs + }) } // http://docs.couchdb.org/en/latest/api/document/common.html#creating-multiple-attachments - function insertMultipart (doc, attachments, qs, callback) { + function insertMultipart (doc, attachments, qs) { if (typeof qs === 'string') { qs = { docName: qs } } @@ -919,7 +837,7 @@ module.exports = exports = function dbScope (cfg) { delete qs.docName if (missing(doc, attachments, docName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } doc = Object.assign({ _attachments: {} }, doc) @@ -949,15 +867,15 @@ module.exports = exports = function dbScope (cfg) { doc: docName, qs, multipart - }, callback) + }) } - function getMultipart (docName, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) - opts.attachments = true + function getMultipart (docName, qs) { + qs = qs || {} + qs.attachments = true if (missing(docName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -965,14 +883,13 @@ module.exports = exports = function dbScope (cfg) { doc: docName, encoding: null, accept: 'multipart/related', - qs: opts - }, callback) + qs + }) } - function insertAtt (docName, attName, att, contentType, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function insertAtt (docName, attName, att, contentType, qs) { if (missing(docName, attName, att, contentType)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -981,44 +898,43 @@ module.exports = exports = function dbScope (cfg) { method: 'PUT', contentType, doc: docName, - qs: opts, + qs, body: att, dontStringify: true - }, callback) + }) } - function getAtt (docName, attName, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) - + function getAtt (docName, attName, qs) { + if (missing(docName, attName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ db: dbName, att: attName, doc: docName, - qs: opts, + qs, encoding: null, dontParse: true - }, callback) + }) } - function getAttAsStream (docName, attName, opts) { + function getAttAsStream (docName, attName, qs) { return relax({ db: dbName, att: attName, doc: docName, - qs: opts, + qs, stream: true, encoding: null, dontParse: true }) } - function destroyAtt (docName, attName, qs, callback) { + function destroyAtt (docName, attName, qs) { if (missing(docName, attName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -1027,12 +943,12 @@ module.exports = exports = function dbScope (cfg) { method: 'DELETE', doc: docName, qs - }, callback) + }) } - function find (query, callback) { + function find (query) { if (missing(query) || typeof query !== 'object') { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -1040,7 +956,7 @@ module.exports = exports = function dbScope (cfg) { path: '_find', method: 'POST', body: query - }, callback) + }) } function findAsStream (query) { @@ -1053,9 +969,9 @@ module.exports = exports = function dbScope (cfg) { }) } - function createIndex (indexDef, callback) { + function createIndex (indexDef) { if (missing(indexDef) || typeof indexDef !== 'object') { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -1063,30 +979,29 @@ module.exports = exports = function dbScope (cfg) { path: '_index', method: 'POST', body: indexDef - }, callback) + }) } - function partitionInfo (partitionKey, callback) { + function partitionInfo (partitionKey) { if (missing(partitionKey)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ db: dbName, path: '_partition/' + encodeURIComponent(partitionKey) - }, callback) + }) } - function partitionedList (partitionKey, qs0, callback0) { - const { opts, callback } = getCallback(qs0, callback0) + function partitionedList (partitionKey, qs) { if (missing(partitionKey)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ db: dbName, path: '_partition/' + encodeURIComponent(partitionKey) + '/_all_docs', - qs: opts - }, callback) + qs + }) } function partitionedListAsStream (partitionKey, qs) { @@ -1098,9 +1013,9 @@ module.exports = exports = function dbScope (cfg) { }) } - function partitionedFind (partition, query, callback) { + function partitionedFind (partition, query) { if (missing(partition, query) || typeof query !== 'object') { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ @@ -1108,7 +1023,7 @@ module.exports = exports = function dbScope (cfg) { path: '_partition/' + encodeURIComponent(partition) + '/_find', method: 'POST', body: query - }, callback) + }) } function partitionedFindAsStream (partition, query) { @@ -1121,59 +1036,59 @@ module.exports = exports = function dbScope (cfg) { }) } - function partitionedSearch (partition, ddoc, searchName, opts, callback) { - if (missing(partition, ddoc, searchName, opts) || typeof opts !== 'object') { - return callbackOrRejectError(callback) + function partitionedSearch (partition, ddoc, searchName, qs) { + if (missing(partition, ddoc, searchName, qs) || typeof qs !== 'object') { + return Promise.reject(invalidParametersError) } return relax({ db: dbName, path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_search/' + searchName, - qs: opts - }, callback) + qs + }) } - function partitionedSearchAsStream (partition, ddoc, searchName, opts) { + function partitionedSearchAsStream (partition, ddoc, searchName, qs) { return relax({ db: dbName, path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_search/' + searchName, - qs: opts, + qs, stream: true }) } - function partitionedView (partition, ddoc, viewName, opts, callback) { + function partitionedView (partition, ddoc, viewName, qs) { if (missing(partition, ddoc, viewName)) { - return callbackOrRejectError(callback) + return Promise.reject(invalidParametersError) } return relax({ db: dbName, path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_view/' + viewName, - qs: opts - }, callback) + qs + }) } - function partitionedViewAsStream (partition, ddoc, viewName, opts) { + function partitionedViewAsStream (partition, ddoc, viewName, qs) { return relax({ db: dbName, path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_view/' + viewName, - qs: opts, + qs, stream: true }) } // db level exports docScope = { - info: function (cb) { - return getDb(dbName, cb) + info: function () { + return getDb(dbName) }, - replicate: function (target, opts, cb) { - return replicateDb(dbName, target, opts, cb) + replicate: function (target, opts) { + return replicateDb(dbName, target, opts) }, - compact: function (cb) { - return compactDb(dbName, cb) + compact: function () { + return compactDb(dbName) }, - changes: function (qs, cb) { - return changesDb(dbName, qs, cb) + changes: function (qs) { + return changesDb(dbName, qs) }, changesAsStream: function (qs) { return changesDbAsStream(dbName, qs) @@ -1216,14 +1131,14 @@ module.exports = exports = function dbScope (cfg) { viewWithListAsStream, server: serverScope, replication: { - enable: function (target, opts, cb) { - return enableReplication(dbName, target, opts, cb) + enable: function (target, opts) { + return enableReplication(dbName, target, opts) }, - disable: function (id, revision, opts, cb) { - return disableReplication(id, revision, opts, cb) + disable: function (id, revision, opts) { + return disableReplication(id, revision, opts) }, - query: function (id, opts, cb) { - return queryReplication(id, opts, cb) + query: function (id, opts) { + return queryReplication(id, opts) } }, partitionInfo, @@ -1237,8 +1152,8 @@ module.exports = exports = function dbScope (cfg) { partitionedViewAsStream } - docScope.view.compact = function (ddoc, cb) { - return compactDb(dbName, ddoc, cb) + docScope.view.compact = function (ddoc) { + return compactDb(dbName, ddoc) } return docScope diff --git a/test/attachment.destroy.test.js b/test/attachment.destroy.test.js index fba5c161..bb5bbf22 100644 --- a/test/attachment.destroy.test.js +++ b/test/attachment.destroy.test.js @@ -56,12 +56,3 @@ test('should detect missing doc id - db.attachment.destroy', async () => { await assert.rejects(db.attachment.destroy('', 'logo.jpg'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.attachment.destroy', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.attachment.destroy(undefined, undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/attachment.get.test.js b/test/attachment.get.test.js index 703e9523..fcb70c46 100644 --- a/test/attachment.get.test.js +++ b/test/attachment.get.test.js @@ -51,12 +51,3 @@ test('should detect missing parameters - db.attachment.get', async () => { await assert.rejects(db.attachment.get('', 'transparent.gif'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.attachment.get', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.attachment.get(undefined, undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/attachment.insert.test.js b/test/attachment.insert.test.js index 898fec2d..af9c9ec2 100644 --- a/test/attachment.insert.test.js +++ b/test/attachment.insert.test.js @@ -72,16 +72,6 @@ test('should detect missing parameters - db.attachment.insert', async () => { await assert.rejects(db.attachment.insert('docname', 't.gif', image), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.attachment.insert', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.attachment.insert(undefined, undefined, undefined, undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be able to insert document attachment as stream - PUT /db/docname/attachment - db.attachment.insert', async () => { // mocks const response = { ok: true, id: 'docname', rev: '2-456' } diff --git a/test/database.changes.test.js b/test/database.changes.test.js index 0444fb1a..44506b8f 100644 --- a/test/database.changes.test.js +++ b/test/database.changes.test.js @@ -77,15 +77,6 @@ test('should not attempt invalid parameters - nano.db.changes', async () => { await assert.rejects(nano.db.changes(''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.changes', async () => { - return new Promise((resolve, reject) => { - nano.db.changes(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be able to fetch the changes from db.changes - GET /db/_changes - db.changes', async () => { // mocks mockPool diff --git a/test/database.compact.test.js b/test/database.compact.test.js index 0fb5a8be..38c7a8f9 100644 --- a/test/database.compact.test.js +++ b/test/database.compact.test.js @@ -46,15 +46,6 @@ test('should not attempt compact with invalid parameters - nano.db.compact', asy await assert.rejects(nano.db.compact(), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.compact', () => { - return new Promise((resolve, reject) => { - nano.db.compact(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be able to send compaction request from db.compact - POST /db/_compact - db.compact', async () => { // mocks mockPool diff --git a/test/database.create.test.js b/test/database.create.test.js index e71d103a..fef1795a 100644 --- a/test/database.create.test.js +++ b/test/database.create.test.js @@ -64,11 +64,3 @@ test('should not attempt to create database with invalid parameters - nano.db.cr await assert.rejects(nano.db.create(''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.create', () => { - return new Promise((resolve, reject) => { - nano.db.create(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/database.destroy.test.js b/test/database.destroy.test.js index bb5ac2b4..835d0573 100644 --- a/test/database.destroy.test.js +++ b/test/database.destroy.test.js @@ -48,11 +48,3 @@ test('should not attempt to destroy database with empty database name - nano.db. await assert.rejects(nano.db.destroy(''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.destroy', () => { - return new Promise((resolve, reject) => { - nano.db.destroy(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/database.get.test.js b/test/database.get.test.js index 5775deab..290834e2 100644 --- a/test/database.get.test.js +++ b/test/database.get.test.js @@ -89,11 +89,3 @@ test('should not attempt info fetch with missing parameters - nano.db.get', asyn await assert.rejects(nano.db.get(''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.get', () => { - return new Promise((resolve, reject) => { - nano.db.get(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/database.replicate.test.js b/test/database.replicate.test.js index 55859467..14d332b7 100644 --- a/test/database.replicate.test.js +++ b/test/database.replicate.test.js @@ -77,15 +77,6 @@ test('should not attempt compact invalid parameters - nano.db.replicate', async await assert.rejects(nano.db.replicate('', 'target'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.replicate', () => { - return new Promise((resolve, reject) => { - nano.db.replicate(undefined, undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be replicate from db.replicate - POST /_replicate - db.replicate', async () => { // mocks mockPool.intercept({ diff --git a/test/database.replication.disable.test.js b/test/database.replication.disable.test.js index 0baae9ac..04e1f9b0 100644 --- a/test/database.replication.disable.test.js +++ b/test/database.replication.disable.test.js @@ -53,15 +53,6 @@ test('should not to try to disable with invalid parameters - nano.db.replication await assert.rejects(nano.db.replication.disable('rep1'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.replication.disable', () => { - return new Promise((resolve, reject) => { - nano.db.replication.disable(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be able to delete a replication from db.replication.disable - DELETE /_replicator/id - db.replication.disable', async () => { // mocks mockPool.intercept({ diff --git a/test/database.replication.enable.test.js b/test/database.replication.enable.test.js index eead7933..38b64bc2 100644 --- a/test/database.replication.enable.test.js +++ b/test/database.replication.enable.test.js @@ -88,15 +88,6 @@ test('should not attempt compact with invalid parameters - nano.db.replication.e await assert.rejects(nano.db.replication.enable('source', ''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.replication.enable', () => { - return new Promise((resolve, reject) => { - nano.db.replication.enable(undefined, undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be able to send replication request db.replication.enable - POST /_replicator - db.replication.enable', async () => { // mocks mockPool.intercept({ diff --git a/test/database.replication.query.test.js b/test/database.replication.query.test.js index bbbc913d..e15d016e 100644 --- a/test/database.replication.query.test.js +++ b/test/database.replication.query.test.js @@ -82,15 +82,6 @@ test('should not attempt info fetch with invalid parameters - nano.db.replicatio await assert.rejects(nano.db.replication.query(), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.replication.query', () => { - return new Promise((resolve, reject) => { - nano.db.replication.query(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('should be able to query a replication from db.replication.quey - GET /_replicator/id - db.replication.query', async () => { // mocks mockPool.intercept({ diff --git a/test/design.atomic.test.js b/test/design.atomic.test.js index bcc0d891..a471b7bc 100644 --- a/test/design.atomic.test.js +++ b/test/design.atomic.test.js @@ -94,23 +94,3 @@ test('should detect missing parameters - db.update', async () => { await assert.rejects(db.atomic('ddoc', 'updatename'), { message: 'Invalid parameters' }) await assert.rejects(db.atomic('', 'updatename', 'docid'), { message: 'Invalid parameters' }) }) - -test('should detect missing parameters (callback) - db.update', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.atomic('', '', '', {}, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - -test('should detect missing parameters (callback no body) - db.update', async () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.atomic('', '', '', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/design.createIndex.test.js b/test/design.createIndex.test.js index b0c7dfea..48028631 100644 --- a/test/design.createIndex.test.js +++ b/test/design.createIndex.test.js @@ -80,12 +80,3 @@ test('should detect missing index - db.createIndex', async () => { await assert.rejects(db.createIndex('myindex'), { message: 'Invalid parameters' }) }) -test('should detect missing index (callback) - db.createIndex', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.createIndex('', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/design.find.test.js b/test/design.find.test.js index 1df757aa..07895823 100644 --- a/test/design.find.test.js +++ b/test/design.find.test.js @@ -81,12 +81,3 @@ test('should detect missing query - db.find', async () => { await assert.rejects(db.find('susan'), { message: 'Invalid parameters' }) }) -test('should detect missing query (callback) - db.find', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.find('', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/design.search.test.js b/test/design.search.test.js index a7568866..ac02f85c 100644 --- a/test/design.search.test.js +++ b/test/design.search.test.js @@ -70,12 +70,3 @@ test('should detect missing parameters - db.search', async () => { await assert.rejects(db.search('', 'susan'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.search', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.search('', '', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/design.show.test.js b/test/design.show.test.js index eca31e6f..90d6847f 100644 --- a/test/design.show.test.js +++ b/test/design.show.test.js @@ -56,12 +56,3 @@ test('should detect missing parameters - db.show', async () => { await assert.rejects(db.show('', 'showname', 'docid'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.show', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.show('', '', '', {}, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/design.view.test.js b/test/design.view.test.js index ceb702ef..a36f24a3 100644 --- a/test/design.view.test.js +++ b/test/design.view.test.js @@ -164,12 +164,3 @@ test('should detect missing parameters - db.view', async () => { await assert.rejects(db.view('', 'susan'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.view', () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.view('', '', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/document.destroy.test.js b/test/document.destroy.test.js index c5f41af5..82f2d3fe 100644 --- a/test/document.destroy.test.js +++ b/test/document.destroy.test.js @@ -57,12 +57,3 @@ test('should detect missing parameters - db.destroy', async () => { await assert.rejects(db.destroy(undefined, '1-123'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.destroy', async () => { - await new Promise((resolve, reject) => { - const db = nano.db.use('db') - db.destroy(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/document.fetch.test.js b/test/document.fetch.test.js index 9bcd6d80..97df61ff 100644 --- a/test/document.fetch.test.js +++ b/test/document.fetch.test.js @@ -172,12 +172,3 @@ test('should detect invalid parameters - db.fetch', async () => { await assert.rejects(db.fetch({ keys: [] }), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.fetch', async () => { - return new Promise((resolve, reject) => { - const db = nano.db.use('db') - db.fetch(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/document.fetchRevs.test.js b/test/document.fetchRevs.test.js index b33ce3ab..5d5771da 100644 --- a/test/document.fetchRevs.test.js +++ b/test/document.fetchRevs.test.js @@ -136,12 +136,3 @@ test('should detect missing parameters - db.fetchRevs', async () => { await assert.rejects(db.fetchRevs({ keys: [] }), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.fetchRevs', async () => { - await new Promise((resolve, reject) => { - const db = nano.db.use('db') - db.fetchRevs(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/document.get.test.js b/test/document.get.test.js index 17d119e9..1babced1 100644 --- a/test/document.get.test.js +++ b/test/document.get.test.js @@ -79,16 +79,6 @@ test('should detect missing doc id - db.get', async () => { await assert.rejects(db.get(), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.get', async () => { - await new Promise((resolve, reject) => { - const db = nano.db.use('db') - db.get(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) - test('check request can fetch local documents - db.get', async () => { // mocks const response = { _id: '_local/id', _rev: '1-123', a: 1 } diff --git a/test/document.head.test.js b/test/document.head.test.js index d0dad424..70941cea 100644 --- a/test/document.head.test.js +++ b/test/document.head.test.js @@ -37,32 +37,6 @@ test('should be able to head a document - HEAD /db/id - db.head', async () => { mockAgent.assertNoPendingInterceptors() }) -test('should be able to head a document with callback - HEAD /db/id - db.head', async () => { - // mocks - const headers = { - 'content-type': 'application/json', - etag: '1-123' - } - mockPool - .intercept({ - method: 'head', - path: '/db/id' - }) - .reply(200, '', { headers }) - - // test HEAD /db - await new Promise((resolve, reject) => { - const db = nano.db.use('db') - db.head('id', (err, data, headers) => { - // headers get lowercased - assert.equal(err, null) - assert.equal(headers.etag, '1-123') - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - test('should be able to head a missing document - HEAD /db/id - db.head', async () => { // mocks mockPool @@ -83,12 +57,3 @@ test('should detect missing parameters - db.head', async () => { await assert.rejects(db.head(), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.head', async () => { - await new Promise((resolve, reject) => { - const db = nano.db.use('db') - db.head(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/multipart.get.test.js b/test/multipart.get.test.js index 3f7a10d5..5b6056a2 100644 --- a/test/multipart.get.test.js +++ b/test/multipart.get.test.js @@ -98,12 +98,3 @@ test('should detect missing docName - db.multipart.get', async () => { await assert.rejects(db.multipart.get(undefined, { conflicts: true }), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.multipart.get', async () => { - const db = nano.db.use('db') - return new Promise((resolve, reject) => { - db.multipart.get(undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/multipart.insert.test.js b/test/multipart.insert.test.js index 2971e595..38dce827 100644 --- a/test/multipart.insert.test.js +++ b/test/multipart.insert.test.js @@ -124,12 +124,3 @@ test('should detect missing docName - db.multipart.insert', async () => { await assert.rejects(db.multipart.insert({ a: 1 }, [{}], {}), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.multipart.insert', async () => { - const db = nano.db.use('db') - await new Promise((resolve, reject) => { - db.multipart.insert(undefined, undefined, undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/nano.request.test.js b/test/nano.request.test.js index 6b920549..02954a60 100644 --- a/test/nano.request.test.js +++ b/test/nano.request.test.js @@ -124,58 +124,10 @@ test('check request can do HEAD requests - nano.request', async () => { path: 'mydoc' } const p = await nano.request(req) - assert.deepEqual(p, response) + assert.deepEqual(p, headers) mockAgent.assertNoPendingInterceptors() }) -test('check request can do GET requests with callback - nano.request', async () => { - // mocks - const response = { ok: true } - mockPool - .intercept({ path: '/db?a=1&b=2' }) - .reply(200, response, JSON_HEADERS) - - // test GET /db?a=1&b=2 - const req = { - method: 'get', - db: 'db', - qs: { a: 1, b: 2 } - } - await new Promise((resolve, reject) => { - nano.request(req, (err, data) => { - assert.equal(err, null) - assert.deepEqual(data, response) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - -test('check request can do failed GET requests with callback - nano.request', async () => { - // mocks - const response = { - error: 'not_found', - reason: 'missing' - } - mockPool - .intercept({ path: '/db/a' }) - .reply(404, response, JSON_HEADERS) - - // test GET /db/a - const req = { - method: 'get', - db: 'db', - path: 'a' - } - await new Promise((resolve, reject) => { - nano.request(req, (err, data) => { - assert.notEqual(err, null) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - test('check request formats keys properly - nano.request', async () => { // mocks const response = { ok: true } @@ -313,29 +265,6 @@ test('check request can do 500s - nano.request', async () => { mockAgent.assertNoPendingInterceptors() }) -test('check request can do 500s with callback - nano.request', async () => { - // mocks - const errorMessage = 'Internal server error' - mockPool - .intercept({ path: '/db?a=1&b=2' }) - .reply(500, errorMessage) - - // test GET /db?a=1&b=2 - const req = { - method: 'get', - db: 'db', - qs: { a: 1, b: 2 } - } - - await new Promise((resolve, reject) => { - nano.request(req, (err, data) => { - assert.notEqual(err, null) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - test('check request handle empty parameter list - nano.request', async () => { // mocks const response = { @@ -361,36 +290,6 @@ test('check request handle empty parameter list - nano.request', async () => { mockAgent.assertNoPendingInterceptors() }) -test('check request handle empty parameter list (callback) - nano.request', async () => { - // mocks - const response = { - couchdb: 'Welcome', - version: '2.3.1', - git_sha: 'c298091a4', - uuid: '865f5b0c258c5749012ce7807b4b0622', - features: [ - 'pluggable-storage-engines', - 'scheduler' - ], - vendor: { - name: 'The Apache Software Foundation' - } - } - mockPool - .intercept({ path: '/' }) - .reply(200, response, JSON_HEADERS) - - // test GET / - await new Promise((resolve, reject) => { - nano.request((err, data) => { - assert.equal(err, null) - assert.deepEqual(data, response) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - test('check request handles single string parameter - nano.request', async () => { // mocks const response = { diff --git a/test/nano.uuids.test.js b/test/nano.uuids.test.js index 01f14c92..26ffb2df 100644 --- a/test/nano.uuids.test.js +++ b/test/nano.uuids.test.js @@ -51,25 +51,3 @@ test('should be able to fetch more uuids - GET /_uuids?count=3 - nano.uuids', as assert.deepEqual(p, response) mockAgent.assertNoPendingInterceptors() }) - -test('should be able to fetch uuids callback - GET /_uuids - nano.uuids', async () => { - // mocks - const response = { - uuids: [ - 'c42ddf1272c7d05b2dc45b696200145f' - ] - } - mockPool - .intercept({ path: '/_uuids?count=1' }) - .reply(200, response, JSON_HEADERS) - - // test GET /_uuids - await new Promise((resolve, reject) => { - nano.uuids((err, data) => { - assert.equal(err, null) - assert.deepEqual(data, response) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) diff --git a/test/partition.find.test.js b/test/partition.find.test.js index d5e96ac5..86043078 100644 --- a/test/partition.find.test.js +++ b/test/partition.find.test.js @@ -81,12 +81,3 @@ test('should detect missing query - db.partitionedFind', async () => { await assert.rejects(db.partitionedFind('partition', 'susan'), { message: 'Invalid parameters' }) }) -test('should detect missing query (callback) - db.partitionedFind', async () => { - const db = nano.db.use('db') - await new Promise((resolve, reject) => { - db.partitionedFind(undefined, '', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/partition.info.test.js b/test/partition.info.test.js index 7a4feb65..5724aae9 100644 --- a/test/partition.info.test.js +++ b/test/partition.info.test.js @@ -40,23 +40,6 @@ test('should be able to fetch partition info info - GET /db/_partition/partition mockAgent.assertNoPendingInterceptors() }) -test('should be able to fetch partition info info (callback) - GET /db/_partition/partition - db.partitionInfo', async () => { - // mocks - mockPool - .intercept({ path: '/db/_partition/partition' }) - .reply(200, response, JSON_HEADERS) - - // test GET /db/_partition/partition - await new Promise((resolve, reject) => { - db.partitionInfo('partition', (err, data) => { - assert.equal(err, null) - assert.deepEqual(data, response) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - test('should handle missing database - PUT /db - nano.db.create', async () => { // mocks const response = { @@ -77,11 +60,3 @@ test('should not attempt info fetch with missing parameters - nano.db.get', asyn await assert.rejects(db.partitionInfo(''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - nano.db.get', async () => { - await new Promise((resolve, reject) => { - db.partitionInfo(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/partition.list.test.js b/test/partition.list.test.js index 05b55082..4bb52d33 100644 --- a/test/partition.list.test.js +++ b/test/partition.list.test.js @@ -102,23 +102,6 @@ test('should be list documents form a partition with opts - GET /db/_partition/_ mockAgent.assertNoPendingInterceptors() }) -test('should be able to list partition docs (callback) - GET /db/_partition/_all_docs - db.partitionedList', async () => { - // mocks - mockPool - .intercept({ path: '/db/_partition/partition/_all_docs' }) - .reply(200, response, JSON_HEADERS) - - // test GET /db/_partition/_all_docs - await new Promise((resolve, reject) => { - db.partitionedList('partition', (err, data) => { - assert.equal(err, null) - assert.deepEqual(data, response) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) -}) - test('should escape unusual characters - GET /db/_partition/a+b/_all_docs - db.partitionedList', async () => { // mocks mockPool @@ -126,14 +109,9 @@ test('should escape unusual characters - GET /db/_partition/a+b/_all_docs - db.p .reply(200, response, JSON_HEADERS) // test GET /db/_partition/_all_docs - await new Promise((resolve, reject) => { - db.partitionedList('a+b', (err, data) => { - assert.equal(err, null) - assert.deepEqual(data, response) - mockAgent.assertNoPendingInterceptors() - resolve() - }) - }) + const p = await db.partitionedList('a+b') + assert.deepEqual(p, response) + mockAgent.assertNoPendingInterceptors() }) test('should handle missing database - GET /db/_partition/_all_docs - db.partitionedList', async () => { @@ -156,11 +134,3 @@ test('should not attempt info fetch with missing parameters - db.partitionedList await assert.rejects(db.partitionedList(''), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.partitionedList', async () => { - await new Promise((resolve, reject) => { - db.partitionedList(undefined, (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/partition.search.test.js b/test/partition.search.test.js index ed8efbf8..1de358a7 100644 --- a/test/partition.search.test.js +++ b/test/partition.search.test.js @@ -64,12 +64,3 @@ test('should detect missing parameters - db.partitionedSearch', async () => { await assert.rejects(db.partitionedSearch('partition', '', 'susan'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.partitionedSearch', async () => { - const db = nano.db.use('db') - await new Promise((resolve, reject) => { - db.partitionedSearch('', '', '', '', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) diff --git a/test/partition.view.test.js b/test/partition.view.test.js index 9a5cf9e6..a6fd0c09 100644 --- a/test/partition.view.test.js +++ b/test/partition.view.test.js @@ -84,12 +84,3 @@ test('should detect missing parameters - db.partitionedView', async () => { await assert.rejects(db.partitionedView('partition', '', 'susan'), { message: 'Invalid parameters' }) }) -test('should detect missing parameters (callback) - db.partitionedView', async () => { - const db = nano.db.use('db') - await new Promise((resolve, reject) => { - db.partitionedView('', '', '', '', (err, data) => { - assert.notEqual(err, null) - resolve() - }) - }) -}) From ab4fa5dd5b145a7fadf030cd828ac15bda62fe33 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 7 Nov 2024 09:56:20 +0000 Subject: [PATCH 36/40] remove callback references from the README --- README.md | 181 +++++++++++++++++++++++++----------------------------- 1 file changed, 82 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 0799119d..24396157 100644 --- a/README.md +++ b/README.md @@ -34,66 +34,66 @@ Note the minimum required version of Node.js is 10. - [Tutorials & screencasts](#tutorials-examples-in-the-wild--screencasts) - [Configuration](#configuration) - [Database functions](#database-functions) - - [nano.db.create(name, [callback])](#nanodbcreatename-callback) - - [nano.db.get(name, [callback])](#nanodbgetname-callback) - - [nano.db.destroy(name, [callback])](#nanodbdestroyname-callback) - - [nano.db.list([callback])](#nanodblistcallback) + - [nano.db.create(name)](#nanodbcreatename) + - [nano.db.get(name)](#nanodbgetname) + - [nano.db.destroy(name)](#nanodbdestroyname) + - [nano.db.list()](#nanodblist) - [nano.db.listAsStream()](#nanodblistasstream) - - [nano.db.compact(name, [designname], [callback])](#nanodbcompactname-designname-callback) - - [nano.db.replicate(source, target, [opts], [callback])](#nanodbreplicatesource-target-opts-callback) - - [nano.db.replication.enable(source, target, [opts], [callback])](#nanodbreplicationenablesource-target-opts-callback) - - [nano.db.replication.query(id, [opts], [callback])](#nanodbreplicationenablesource-target-opts-callback) - - [nano.db.replication.disable(id, [opts], [callback])](#nanodbreplicationdisableid-opts-callback) - - [nano.db.changes(name, [params], [callback])](#nanodbchangesname-params-callback) + - [nano.db.compact(name, [designname])](#nanodbcompactname-designname) + - [nano.db.replicate(source, target, [opts])](#nanodbreplicatesource-target-opts) + - [nano.db.replication.enable(source, target, [opts])](#nanodbreplicationenablesource-target-opts) + - [nano.db.replication.query(id, [opts])](#nanodbreplicationenablesource-target-opts) + - [nano.db.replication.disable(id, [opts])](#nanodbreplicationdisableid-opts) + - [nano.db.changes(name, [params])](#nanodbchangesname-params) - [nano.db.changesAsStream(name, [params])](#nanodbchangesasstreamname-params) - - [nano.db.info([callback])](#nanodbinfocallback) + - [nano.db.info()](#nanodbinfo) - [nano.use(name)](#nanousename) - - [nano.request(opts, [callback])](#nanorequestopts-callback) + - [nano.request(opts)](#nanorequestopts) - [nano.config](#nanoconfig) - - [nano.updates([params], [callback])](#nanoupdatesparams-callback) - - [nano.info([callback])](#nanoinfocallback) + - [nano.updates([params])](#nanoupdatesparams) + - [nano.info()](#nanoinfo) - [Document functions](#document-functions) - - [db.insert(doc, [params], [callback])](#dbinsertdoc-params-callback) - - [db.destroy(docname, rev, [callback])](#dbdestroydocname-rev-callback) - - [db.get(docname, [params], [callback])](#dbgetdocname-params-callback) - - [db.head(docname, [callback])](#dbheaddocname-callback) - - [db.bulk(docs, [params], [callback])](#dbbulkdocs-params-callback) - - [db.list([params], [callback])](#dblistparams-callback) + - [db.insert(doc, [params])](#dbinsertdoc-params) + - [db.destroy(docname, rev)](#dbdestroydocname-rev) + - [db.get(docname, [params])](#dbgetdocname-params) + - [db.head(docname)](#dbheaddocname) + - [db.bulk(docs, [params])](#dbbulkdocs-params) + - [db.list([params])](#dblistparams) - [db.listAsStream([params])](#dblistasstreamparams) - - [db.fetch(docnames, [params], [callback])](#dbfetchdocnames-params-callback) - - [db.fetchRevs(docnames, [params], [callback])](#dbfetchrevsdocnames-params-callback) - - [db.createIndex(indexDef, [callback])](#dbcreateindexindexdef-callback) + - [db.fetch(docnames, [params])](#dbfetchdocnames-params) + - [db.fetchRevs(docnames, [params])](#dbfetchrevsdocnames-params) + - [db.createIndex(indexDef)](#dbcreateindexindexdef) - [db.changesReader](#reading-changes-feed) - [Partitioned database functions](#partition-functions) - - [db.partitionInfo(partitionKey, [callback])](#dbpartitioninfopartitionkey-callback)) - - [db.partitionedList(partitionKey, [params], [callback])](#dbpartitionedlistpartitionkey-params-callback) + - [db.partitionInfo(partitionKey)](#dbpartitioninfopartitionkey)) + - [db.partitionedList(partitionKey, [params])](#dbpartitionedlistpartitionkey-params) - [db.partitionedListAsStream(partitionKey, [params])](#dbpartitionedlistasstreampartitionkey-params) - - [db.partitionedFind(partitionKey, query, [callback])](#dbpartitionedfindpartitionkey-query-params) + - [db.partitionedFind(partitionKey, query)](#dbpartitionedfindpartitionkey-query-params) - [db.partitionedFindAsStream(partitionKey, query)](#dbpartitionedfindasstreampartitionkey-query) - - [db.partitionedSearch(partitionKey, designName, searchName, params, [callback])](#dbpartitionedsearchpartitioney-designname-searchname-params-callback) + - [db.partitionedSearch(partitionKey, designName, searchName, params)](#dbpartitionedsearchpartitioney-designname-searchname-params) - [db.partitionedSearchAsStream(partitionKey, designName, searchName, params)](#dbpartitionedsearchasstreampartitionkey-designName-searchName-params) - - [db.partitionedView(partitionKey, designName, viewName, [params], [callback])](#dbpartitionediewpartitionkey-designname-viewname-params-callback) + - [db.partitionedView(partitionKey, designName, viewName, [params])](#dbpartitionediewpartitionkey-designname-viewname-params) - [db.partitionedViewAsStream(partitionKey, designName, viewName, [params])](#dbpartitionediewasstreampartitionkey-designname-viewname-params) - [Multipart functions](#multipart-functions) - - [db.multipart.insert(doc, attachments, [params], [callback])](#dbmultipartinsertdoc-attachments-params-callback) - - [db.multipart.get(docname, [params], [callback])](#dbmultipartgetdocname-params-callback) + - [db.multipart.insert(doc, attachments, [params])](#dbmultipartinsertdoc-attachments-params) + - [db.multipart.get(docname, [params])](#dbmultipartgetdocname-params) - [Attachments functions](#attachments-functions) - - [db.attachment.insert(docname, attname, att, contenttype, [params], [callback])](#dbattachmentinsertdocname-attname-att-contenttype-params-callback) + - [db.attachment.insert(docname, attname, att, contenttype, [params])](#dbattachmentinsertdocname-attname-att-contenttype-params) - [db.attachment.insertAsStream(docname, attname, att, contenttype, [params])](#dbattachmentinsertasstreamdocname-attname-att-contenttype-params) - - [db.attachment.get(docname, attname, [params], [callback])](#dbattachmentgetdocname-attname-params-callback) + - [db.attachment.get(docname, attname, [params])](#dbattachmentgetdocname-attname-params) - [db.attachment.getAsStream(docname, attname, [params])](#dbattachmentgetasstreamdocname-attname-params) - - [db.attachment.destroy(docname, attname, [params], [callback])](#dbattachmentdestroydocname-attname-params-callback) + - [db.attachment.destroy(docname, attname, [params])](#dbattachmentdestroydocname-attname-params) - [Views and design functions](#views-and-design-functions) - - [db.view(designname, viewname, [params], [callback])](#dbviewdesignname-viewname-params-callback) + - [db.view(designname, viewname, [params])](#dbviewdesignname-viewname-params) - [db.viewAsStream(designname, viewname, [params])](#dbviewasstreamdesignname-viewname-params) - [db.viewWithList(designname, viewname, listname, [params])](#dbviewwithlistdesignname-viewname-params) - [db.viewWithListAsStream(designname__viewname, listname, [params])](#dbviewwithlistasstreamdesignname-viewname-params) - - [db.show(designname, showname, doc_id, [params], [callback])](#dbshowdesignname-showname-doc_id-params-callback) - - [db.atomic(designname, updatename, docname, [body], [callback])](#dbatomicdesignname-updatename-docname-body-callback) - - [db.search(designname, viewname, params, [callback])](#dbsearchdesignname-searchname-params-callback) + - [db.show(designname, showname, doc_id, [params])](#dbshowdesignname-showname-doc_id-params) + - [db.atomic(designname, updatename, docname, [body])](#dbatomicdesignname-updatename-docname-body) + - [db.search(designname, viewname, params)](#dbsearchdesignname-searchname-params) - [db.searchAsStream(designname, viewname, params)](#dbsearchasstreamdesignname-searchname-params) - - [db.find(selector, [callback])](#dbfindselector-callback) + - [db.find(selector)](#dbfindselector) - [db.findAsStream(selector)](#dbfindasstreamselector) - [Using cookie authentication](#using-cookie-authentication) - [Advanced features](#advanced-features) @@ -137,7 +137,7 @@ nano.db.create('alice').then((data) => { }) ``` -or in the async/await style: +2) or in the async/await style: ```js try { @@ -150,21 +150,6 @@ try { } ``` -2) Callbacks - -```js -nano.db.create('alice', (err, data) => { - // errors are in 'err' & response is in 'data' -}) -``` - -In `nano` the callback function receives always three arguments: - -* `err` - The error, if any. -* `body` - The HTTP _response body_ from CouchDB, if no error. - JSON parsed body, binary for non JSON responses. -* `header` - The HTTP _response header_ from CouchDB, if no error. - The documentation will follow the *async/await* style. ------------------ @@ -256,7 +241,7 @@ You may also supply a pre-existing `undici.Agent` e.g. ```js const agent = new undici.Agent({bodyTimeout: 30000 }) const nano = Nano({ url: 'http://127.0.0.1:5984', agentOptions: agent }) -`` +``` > Note `requestDefaults` is no longer supported. @@ -320,7 +305,7 @@ db.insert(p).then((response) => { ## Database functions -### nano.db.create(name, [opts], [callback]) +### nano.db.create(name, [opts]) Creates a CouchDB database with the given `name`, with options `opts`. @@ -328,7 +313,7 @@ Creates a CouchDB database with the given `name`, with options `opts`. await nano.db.create('alice', { n: 3 }) ``` -### nano.db.get(name, [callback]) +### nano.db.get(name) Get information about the database `name`: @@ -336,7 +321,7 @@ Get information about the database `name`: const info = await nano.db.get('alice') ``` -### nano.db.destroy(name, [callback]) +### nano.db.destroy(name) Destroys the database `name`: @@ -344,7 +329,7 @@ Destroys the database `name`: await nano.db.destroy('alice') ``` -### nano.db.list([callback]) +### nano.db.list() Lists all the CouchDB databases: @@ -362,11 +347,11 @@ nano.db.listAsStream() .pipe(process.stdout); ``` -### nano.db.compact(name, [designname], [callback]) +### nano.db.compact(name, [designname]) Compacts `name`, if `designname` is specified also compacts its views. -### nano.db.replicate(source, target, [opts], [callback]) +### nano.db.replicate(source, target, [opts]) Replicates `source` to `target` with options `opts`. The `target`database has to exist, add `create_target:true` to `opts` to create it prior to @@ -378,7 +363,7 @@ const response = await nano.db.replicate('alice', { create_target:true }) ``` -### nano.db.replication.enable(source, target, [opts], [callback]) +### nano.db.replication.enable(source, target, [opts]) Enables replication using the new CouchDB api from `source` to `target` with options `opts`. `target` has to exist, add `create_target:true` to @@ -390,7 +375,7 @@ const response = await nano.db.replication.enable('alice', { create_target:true }) ``` -### nano.db.replication.query(id, [opts], [callback]) +### nano.db.replication.query(id, [opts]) Queries the state of replication using the new CouchDB API. The `id` comes from the response given by the call to `replication.enable`: @@ -402,7 +387,7 @@ const r = await nano.db.replication.enable('alice', const q = await nano.db.replication.query(r.id) ``` -### nano.db.replication.disable(id, [opts], [callback]) +### nano.db.replication.disable(id, [opts]) Disables replication using the new CouchDB API. The `id` comes from the response given by the call to `replication.enable`: @@ -414,7 +399,7 @@ const r = await nano.db.replication.enable('alice', await nano.db.replication.disable(r.id); ``` -### nano.db.changes(name, [params], [callback]) +### nano.db.changes(name, [params]) Asks for the changes feed of `name`, `params` contains additions to the query string. @@ -431,7 +416,7 @@ Same as `nano.db.changes` but returns a stream. nano.db.changes('alice').pipe(process.stdout); ``` -### nano.db.info([callback]) +### nano.db.info() Gets database information: @@ -462,7 +447,7 @@ Alias for `nano.use` Alias for `nano.use` -### nano.request(opts, [callback]) +### nano.request(opts) Makes a custom request to CouchDB. This can be used to create your own HTTP request to the CouchDB server, to perform operations where there is no `nano` function that encapsulates it. The available `opts` are: @@ -481,7 +466,7 @@ server, to perform operations where there is no `nano` function that encapsulate * `opts.multipart` – array of objects for multipart request * `opts.stream` - if `true`, a `request` object is returned. Default `false` and a Promise is returned. -### nano.relax(opts, [callback]) +### nano.relax(opts) Alias for `nano.request` @@ -492,7 +477,7 @@ An object containing the `nano` configurations, possible keys are: * `url` - the CouchDB URL * `db` - the database name -### nano.updates([params], [callback]) +### nano.updates([params]) Listen to db updates, the available `params` are: @@ -503,7 +488,7 @@ Listen to db updates, the available `params` are: * `params.timeout` – Number of seconds until CouchDB closes the connection. Default is 60. * `params.heartbeat` – Whether CouchDB will send a newline character (\n) on timeout. Default is true. -### nano.info([callback]) +### nano.info() Fetch information about the CouchDB cluster: @@ -515,7 +500,7 @@ The response is an object with [CouchDB cluster information](https://docs.couchd ## Document functions -### db.insert(doc, [params], [callback]) +### db.insert(doc, [params]) Inserts `doc` in the database with optional `params`. If params is a string, it's assumed it is the intended document `_id`. If params is an object, it's passed as query string parameters and `docName` is checked for defining the document `_id`: @@ -524,7 +509,7 @@ const alice = nano.use('alice'); const response = await alice.insert({ happy: true }, 'rabbit') ``` -The `insert` function can also be used with the method signature `db.insert(doc,[callback])`, where the `doc` contains the `_id` field e.g. +The `insert` function can also be used with the method signature `db.insert(doc,)`, where the `doc` contains the `_id` field e.g. ```js const alice = nano.use('alice') @@ -538,7 +523,7 @@ const alice = nano.use('alice') const response = await alice.insert({ _id: 'myid', _rev: '1-23202479633c2b380f79507a776743d5', happy: false }) ``` -### db.destroy(docname, rev, [callback]) +### db.destroy(docname, rev) Removes a document from CouchDB whose `_id` is `docname` and whose revision (`_rev`) is `rev`: @@ -546,7 +531,7 @@ Removes a document from CouchDB whose `_id` is `docname` and whose revision (`_r const response = await alice.destroy('rabbit', '3-66c01cdf99e84c83a9b3fe65b88db8c0') ``` -### db.get(docname, [params], [callback]) +### db.get(docname, [params]) Gets a document from CouchDB whose `_id` is `docname`: @@ -562,13 +547,13 @@ const doc = await alice.get('rabbit', { revs_info: true }) If you pass `attachments=true`, the `doc._attachments.attachmentNameN.data` fields will contain the [base-64 encoded attachments](https://docs.couchdb.org/en/stable/json-structure.html#document-with-attachments). -Or, you can use [`db.multipart.get`](https://github.com/DougReeder/couchdb-nano#dbmultipartgetdocname-params-callback) +Or, you can use [`db.multipart.get`](https://github.com/DougReeder/couchdb-nano#dbmultipartgetdocname-params) and parse the returned buffer to get the document and attachments. See the [attachments methods](https://github.com/apache/couchdb-nano#attachments-functions) to retrieve *just* an attachment. -### db.head(docname, [callback]) +### db.head(docname) Same as `get` but lightweight version that returns headers only: @@ -576,9 +561,7 @@ Same as `get` but lightweight version that returns headers only: const headers = await alice.head('rabbit') ``` -*Note:* if you call `alice.head` in the callback style, the headers are returned to you as the third argument of the callback function. - -### db.bulk(docs, [params], [callback]) +### db.bulk(docs, [params]) Bulk operations(update/delete/insert) on the database, refer to the [CouchDB doc](https://docs.couchdb.org/en/stable/api/database/bulk-api.html#post--db-_bulk_docs) e.g: @@ -591,7 +574,7 @@ const documents = [ const response = await alice.bulk({ docs: documents }) ``` -### db.list([params], [callback]) +### db.list([params]) List all the docs in the database . @@ -619,7 +602,7 @@ alice.listAsStream() .pipe(process.stdout) ``` -### db.fetch(docnames, [params], [callback]) +### db.fetch(docnames, [params]) Bulk fetch of the database documents, `docnames` are specified as per [CouchDB doc](https://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs). @@ -631,7 +614,7 @@ const keys = ['tiger', 'zebra', 'donkey']; const datat = await alice.fetch({keys: keys}) ``` -### db.fetchRevs(docnames, [params], [callback]) +### db.fetchRevs(docnames, [params]) ** changed in version 6 ** @@ -640,7 +623,7 @@ Bulk fetch of the revisions of the database documents, `docnames` are specified additional query string `params` can be specified, this is the same method as fetch but `include_docs` is not automatically set to `true`. -### db.createIndex(indexDef, [callback]) +### db.createIndex(indexDef) Create index on database fields, as specified in [CouchDB doc](https://docs.couchdb.org/en/latest/api/database/find.html#db-index). @@ -844,7 +827,7 @@ const ddoc = { await db.insert(ddoc) ``` -### db.partitionInfo(partitionKey, [callback]) +### db.partitionInfo(partitionKey) Fetch the stats of a single partition: @@ -852,7 +835,7 @@ Fetch the stats of a single partition: const stats = await alice.partitionInfo('canidae') ``` -### db.partitionedList(partitionKey, [params], [callback]) +### db.partitionedList(partitionKey, [params]) Fetch documents from a database partition: @@ -900,7 +883,7 @@ db.partitionedFindAsStream('canidae', { 'selector' : { 'name': 'Wolf' }}) .pipe(process.stdout) ``` -### db.partitionedSearch(partitionKey, designName, searchName, params, [callback]) +### db.partitionedSearch(partitionKey, designName, searchName, params) Search documents from a partition by supplying a Lucene query: @@ -926,7 +909,7 @@ db.partitionedSearchAsStream('canidae', 'search-ddoc', 'search-index', params) // { total_rows: ... , bookmark: ..., rows: [ ...] } ``` -### db.partitionedView(partitionKey, designName, viewName, params, [callback]) +### db.partitionedView(partitionKey, designName, viewName, params) Fetch documents from a MapReduce view from a partition: @@ -958,7 +941,7 @@ db.partitionedViewAsStream('canidae', 'view-ddoc', 'view-name', params) ## Multipart functions -### db.multipart.insert(doc, attachments, params, [callback]) +### db.multipart.insert(doc, attachments, params) Inserts a `doc` together with `attachments` and `params`. If params is a string, it's assumed as the intended document `_id`. If params is an object, its passed as query string parameters and `docName` is checked for defining the `_id`. Refer to the [doc](https://docs.couchdb.org/en/stable/api/document/common.html) for more details. The `attachments` parameter must be an array of objects with `name`, `data` and `content_type` properties. @@ -973,7 +956,7 @@ fs.readFile('rabbit.png', (err, data) => { }); ``` -### db.multipart.get(docname, [params], [callback]) +### db.multipart.get(docname, [params]) Get `docname` together with its attachments via `multipart/related` request with optional [query string additions](https://docs.couchdb.org/en/stable/api/document/common.html#get--db-docid). The multipart response body is a `Buffer`. @@ -983,7 +966,7 @@ const response = await alice.multipart.get('rabbit') ## Attachments functions -### db.attachment.insert(docname, attname, att, contenttype, [params], [callback]) +### db.attachment.insert(docname, attname, att, contenttype, [params]) Inserts an attachment `attname` to `docname`, in most cases `params.rev` is required. Refer to the @@ -1008,7 +991,7 @@ fs.readFile('rabbit.png', (err, data) => { As of Nano 9.x, the function `db.attachment.insertAsStream` is now deprecated. Now simply pass a readable stream to `db.attachment.insert` as the third paramseter. -### db.attachment.get(docname, attname, [params], [callback]) +### db.attachment.get(docname, attname, [params]) Get `docname`'s attachment `attname` with optional query string additions `params`. @@ -1029,7 +1012,7 @@ alice.attachment.getAsStream('rabbit', 'rabbit.png') .pipe(fs.createWriteStream('rabbit.png')); ``` -### db.attachment.destroy(docname, attname, [params], [callback]) +### db.attachment.destroy(docname, attname, [params]) **changed in version 6** @@ -1041,7 +1024,7 @@ const response = await alice.attachment.destroy('rabbit', 'rabbit.png', {rev: '1 ## Views and design functions -### db.view(designname, viewname, [params], [callback]) +### db.view(designname, viewname, [params]) Calls a view of the specified `designname` with optional query string `params`. If you're looking to filter the view results by key(s) pass an array of keys, e.g `{ keys: ['key1', 'key2', 'key_n'] }`, as `params`. @@ -1079,7 +1062,7 @@ alice.viewAsStream('characters', 'happy_ones', {reduce: false}) .pipe(process.stdout); ``` -### db.viewWithList(designname, viewname, listname, [params], [callback]) +### db.viewWithList(designname, viewname, listname, [params]) Calls a list function fed by the given view from the specified design document. @@ -1087,7 +1070,7 @@ Calls a list function fed by the given view from the specified design document. const body = await alice.viewWithList('characters', 'happy_ones', 'my_list') ``` -### db.viewWithListAsStream(designname, viewname, listname, [params], [callback]) +### db.viewWithListAsStream(designname, viewname, listname, [params]) Calls a list function fed by the given view from the specified design document as a stream. @@ -1097,7 +1080,7 @@ alice.viewWithListAsStream('characters', 'happy_ones', 'my_list') .pipe(process.stdout); ``` -### db.show(designname, showname, doc_id, [params], [callback]) +### db.show(designname, showname, doc_id, [params]) Calls a show function from the specified design for the document specified by doc_id with optional query string additions `params`. @@ -1109,7 +1092,7 @@ const doc = await alice.show('characters', 'format_doc', '3621898430') Take a look at the [CouchDB wiki](https://guide.couchdb.org/draft/show.html) for possible query paramaters and more information on show functions. -### db.atomic(designname, updatename, docname, [body], [callback]) +### db.atomic(designname, updatename, docname, [body]) Calls the design's update function with the specified doc in input. @@ -1133,7 +1116,7 @@ An example update handler follows: } ``` -### db.search(designname, searchname, params, [callback]) +### db.search(designname, searchname, params) Calls a view of the specified design with optional query string additions `params`. @@ -1158,7 +1141,7 @@ Calls a view of the specified design with optional query string additions `param alice.search('characters', 'happy_ones', { q: 'cat' }).pipe(process.stdout); ``` -### db.find(selector, [callback]) +### db.find(selector) Perform a ["Mango" query](https://docs.couchdb.org/en/2.1.1/api/database/find.html) by supplying a JavaScript object containing a selector: From 493ab279869c443a513b74ce9c2e0af5b5ed5838 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 7 Nov 2024 10:11:23 +0000 Subject: [PATCH 37/40] update Typescript definitions to remove callback references --- lib/nano.d.ts | 197 +++++++++++++++++++++----------------------------- 1 file changed, 82 insertions(+), 115 deletions(-) diff --git a/lib/nano.d.ts b/lib/nano.d.ts index 96ae489b..60131cec 100644 --- a/lib/nano.d.ts +++ b/lib/nano.d.ts @@ -1,7 +1,7 @@ /** * @file nano.d.ts * - * Type definitions for nano 6.4 + * Type definitions for nano 11 * * Project: https://github.com/apache/couchdb-nano * @@ -108,8 +108,6 @@ declare namespace nano { parseUrl?: boolean; } - type Callback = (error: RequestError | null, response: R, headers?: any) => void; - /** An error triggered by nano */ interface RequestError extends Error { /** An error code. */ @@ -154,44 +152,44 @@ declare namespace nano { scope(db: string): DocumentScope; /** * Initiates a custom request - * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts-callback} + * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts} **/ - request(opts: RequestOptions | string, callback?: Callback): Promise; + request(opts: RequestOptions | string): Promise; /** * Initiates a custom request - * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts-callback} + * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts} **/ - relax(opts: RequestOptions | string, callback?: Callback): Promise; + relax(opts: RequestOptions | string): Promise; /** * Initiates a custom request - * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts-callback} + * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts} **/ - dinosaur(opts: RequestOptions | string, callback?: Callback): Promise; + dinosaur(opts: RequestOptions | string): Promise; /** * Initiates new session for specified user credentials by providing Cookie value. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/authn.html#cookie-authentication} */ - auth(username: string, userpass: string, callback?: Callback): Promise; + auth(username: string, userpass: string): Promise; /** * Returns information about the authenticated user, including a User Context Object, the authentication method and database that were used, and a list of configured authentication handlers on the server. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/authn.html#get--_session} */ - session(callback?: Callback): Promise; + session(): Promise; /** * Returns a list of all database events in the CouchDB instance. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#get--_db_updates} */ - updates(callback?: Callback): Promise; + updates(): Promise; /** * Returns a list of all database events in the CouchDB instance. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#get--_db_updates} */ - updates(params: UpdatesParams, callback?: Callback): Promise; + updates(params: UpdatesParams): Promise; /** * Requests one or more Universally Unique Identifiers (UUIDs) from the CouchDB instance. * @see Docs: {@link https://docs.couchdb.org/en/stable/api/server/common.html#uuids} */ - uuids(num?: number, callback?: Callback): Promise; + uuids(num?: number): Promise; /** * Accessing the root of a CouchDB instance returns meta information about the instance. * @see Docs: {@link https://docs.couchdb.org/en/stable/api/server/common.html#api-server-root} */ - info(callback?: Callback): Promise; + info(): Promise; } interface UUIDObject { @@ -222,23 +220,23 @@ declare namespace nano { /** Database scope */ interface DatabaseScope { replication: { - enable(source: string, target: string, opts0: object, callback0?: Callback): Promise; - disable(id:string, rev: string, opts0: object, callback0?: Callback): Promise; - query(id: string, opts0: object, callback0?: Callback): Promise; + enable(source: string, target: string, opts: object): Promise; + disable(id:string, rev: string, opts: object): Promise; + query(id: string, opts: object): Promise; }; /** * Create database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/common.html#put--db} */ - create(name: string, params?: DatabaseCreateParams, callback?: Callback): Promise; + create(name: string, params?: DatabaseCreateParams): Promise; /** Get database information. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/common.html#get--db} */ - get(name: string, callback?: Callback): Promise; + get(name: string): Promise; /** Delete database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/common.html#delete--db} */ - destroy(name: string, callback?: Callback): Promise; + destroy(name: string): Promise; /** List databases. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#get--_all_dbs} */ - list(callback?: Callback): Promise; + list(): Promise; /** List databases as a stream. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#get--_all_dbs} */ listAsStream(): NodeJS.ReadStream; @@ -247,31 +245,29 @@ declare namespace nano { use(db: string): DocumentScope; /** Request compaction on a database. * @see Docs: {@link https://docs.couchdb.org/en/stable/api/database/compact.html} */ - compact(name: string, callback?: Callback): Promise; + compact(name: string): Promise; /** Request compaction of a database's view indexes. * @see Docs: {@link https://docs.couchdb.org/en/stable/api/database/compact.html} */ - compact(name: string, designname: string, callback?: Callback): Promise; + compact(name: string, designname: string): Promise; /** Request a replication operation. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#post--_replicate} */ replicate( source: string | DocumentScope, - target: string | DocumentScope, - callback?: Callback + target: string | DocumentScope ): Promise; /** Reqiest a replication * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#post--_replicate} */ replicate( source: string | DocumentScope, target: string | DocumentScope, - options: DatabaseReplicateOptions, - callback?: Callback + options: DatabaseReplicateOptions ): Promise; /** Return sorted list of changes to a database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes} */ - changes(name: string, callback?: Callback): Promise; + changes(name: string): Promise; /** Return sorted list of changes to a database with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/compact.html#post--db-_compact} */ - changes(name: string, params: DatabaseChangesParams, callback?: Callback): Promise; + changes(name: string, params: DatabaseChangesParams): Promise; /** Return sorted list of changes to a database as a stream. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes} */ changesAsStream(name: string): NodeJS.ReadStream; @@ -280,10 +276,10 @@ declare namespace nano { changesAsStream(name: string, params: DatabaseChangesParams): NodeJS.ReadStream; /** Return a list of all database events. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#get--_db_updates} */ - updates(callback?: Callback): Promise; + updates(): Promise; /** Return a list of all database event with options * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#get--_db_updates} */ - updates(params: UpdatesParams, callback?: Callback): Promise; + updates(params: UpdatesParams): Promise; } /** ChangesReader options */ @@ -330,75 +326,70 @@ declare namespace nano { readonly config: ServerConfig; /** Get database info * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/common.html#get--db} */ - info(callback?: Callback): Promise; + info(): Promise; /** Request a replication opertation with this datbase as the target. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#post--_replicate} */ - replicate( - target: string | DocumentScope, - callback?: Callback - ): Promise; + replicate(target: string | DocumentScope): Promise; /** Request a replication opertation with this datbase as the target with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/common.html#post--_replicate} */ replicate( target: string | DocumentScope, - options: any, - callback?: Callback + options: any ): Promise; /** Request compaction on this database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/compact.html#post--db-_compact} */ - compact(callback?: Callback): Promise; + compact(): Promise; /** Return sorted list of changes to this database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes} */ - changes(callback?: Callback): Promise; + changes(): Promise; /** Return sorted list of changes to this database with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes} */ - changes(params: DatabaseChangesParams, callback?: Callback): Promise; + changes(params: DatabaseChangesParams): Promise; /** Changes feed follower. * @see README: {@link https://www.npmjs.com/package/nano#reading-changes-feed} */ changesReader: ChangesReaderScope; /** Initiates new session for specified user credentials by providing Cookie value. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/authn.html#cookie-authentication} */ - auth(username: string, userpass: string, callback?: Callback): Promise; + auth(username: string, userpass: string): Promise; /** Returns information about the authenticated user, including a User Context Object, the authentication method and database that were used, and a list of configured authentication handlers on the server. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/server/authn.html#get--_session} */ - session(callback?: Callback): Promise; + session(): Promise; /** Insert a document into this database. * @see POST Docs: {@link http://docs.couchdb.org/en/latest/api/database/common.html#post--db} * @see PUT Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#put--db-docid} */ - insert(document: ViewDocument | D & MaybeDocument, callback?: Callback): Promise; + insert(document: ViewDocument | D & MaybeDocument): Promise; /** * Insert a document into this database with options. * @see POST Docs: {@link http://docs.couchdb.org/en/latest/api/database/common.html#post--db} * @see PUT Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#put--db-docid} */ insert( document: ViewDocument | D & MaybeDocument, - params: DocumentInsertParams | string | null, - callback?: Callback + params: DocumentInsertParams | string | null ): Promise; /** Fetch a document from this database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#get--db-docid} */ - get(docname: string, callback?: Callback): Promise; + get(docname: string): Promise; /** Fetch a document from this database with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#get--db-docid} */ - get(docname: string, params?: DocumentGetParams, callback?: Callback): Promise; + get(docname: string, params?: DocumentGetParams): Promise; /** Fetch document meta data, useful for fetching a document's current revision. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#head--db-docid} */ - head(docname: string, callback?: Callback): Promise; + head(docname: string): Promise; /** Delete a document from this database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#delete--db-docid} */ - destroy(docname: string, rev: string, callback?: Callback): Promise; + destroy(docname: string, rev: string): Promise; /** Bulk insert/update/delete multiple documents in this database. * @see Docs: {@link https://docs.couchdb.org/en/stable/api/database/bulk-api.html#db-bulk-docs} */ - bulk(docs: BulkModifyDocsWrapper, callback?: Callback): Promise; + bulk(docs: BulkModifyDocsWrapper): Promise; /** Bulk insert/update/delete multiple documents in this database, with options. * @see Docs: {@link https://docs.couchdb.org/en/stable/api/database/bulk-api.html#db-bulk-docs} */ - bulk(docs: BulkModifyDocsWrapper, params: any, callback?: Callback): Promise; + bulk(docs: BulkModifyDocsWrapper, params: any): Promise; /** List documents from this database. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs} */ - list(callback?: Callback>): Promise>; + list(): Promise>; /** List documents from this database with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs} */ - list(params: DocumentListParams, callback?: Callback>): Promise>; + list(params: DocumentListParams): Promise>; /** List document from this database as a stream. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs} */ listAsStream(): NodeJS.ReadStream; @@ -407,29 +398,25 @@ declare namespace nano { listAsStream(params: DocumentListParams): NodeJS.ReadStream; /** Fetch a list of documents by _id. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs} */ - fetch(docnames: BulkFetchDocsWrapper, callback?: Callback>): Promise>; + fetch(docnames: BulkFetchDocsWrapper): Promise>; /** Fetch a list of documents by _id with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs} */ fetch( docnames: BulkFetchDocsWrapper, - params: DocumentFetchParams, - callback?: Callback> + params: DocumentFetchParams ): Promise>; /** Fetch revisions of a list of document _ids. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs} */ - fetchRevs(docnames: BulkFetchDocsWrapper, callback?: Callback>): Promise>; + fetchRevs(docnames: BulkFetchDocsWrapper): Promise>; /** Fetch revisions of a list of document _ids with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs} */ fetchRevs( docnames: BulkFetchDocsWrapper, - params: DocumentFetchParams, - callback?: Callback> + params: DocumentFetchParams ): Promise>; /** Create a Mango index. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/find.html#db-index} */ - createIndex(indexDef: CreateIndexRequest, - callback?: Callback - ): Promise; + createIndex(indexDef: CreateIndexRequest): Promise; /** Multipart HTTP functions */ multipart: Multipart; /** Attachment functions */ @@ -439,8 +426,7 @@ declare namespace nano { show( designname: string, showname: string, - doc_id: string, - callback?: Callback + doc_id: string ): Promise; /** Apply a show function to a document. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#get--db-_design-ddoc-_show-func} */ @@ -448,16 +434,14 @@ declare namespace nano { designname: string, showname: string, doc_id: string, - params: any, - callback?: Callback + params: any ): Promise; /** Executes an update function on the server side for the supplied document id. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid} */ atomic( designname: string, updatename: string, - docname: string, - callback?: Callback + docname: string ): Promise; /** Executes an update function on the server side for the supplied document id with body. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid} */ @@ -465,16 +449,14 @@ declare namespace nano { designname: string, updatename: string, docname: string, - body: any, - callback?: Callback + body: any ): Promise; /** Executes an update function on the server side for the supplied document id. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid} */ updateWithHandler( designname: string, updatename: string, - docname: string, - callback?: Callback + docname: string ): Promise; /** Executes an update function on the server side for the supplied document id with body. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid} */ @@ -482,16 +464,14 @@ declare namespace nano { designname: string, updatename: string, docname: string, - body: any, - callback?: Callback + body: any ): Promise; /** Executes a search request against the named index. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/ddoc/search.html#db-design-design-doc-search-index-name} */ search( designname: string, searchname: string, - params: DocumentSearchParams, - callback?: Callback> + params: DocumentSearchParams ): Promise>; /** Executes a search request against the named index as a stream. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/ddoc/search.html#db-design-design-doc-search-index-name} */ @@ -506,23 +486,20 @@ declare namespace nano { designname: string, viewname: string, meta: any, - params?: any, - callback?: Callback + params?: any ): Promise; /** Executes a view from a Design Document. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/views.html#get--db-_design-ddoc-_view-view} */ view( designname: string, - viewname: string, - callback?: Callback> + viewname: string ): Promise>; /** Executes a view from a Design Document, with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/views.html#get--db-_design-ddoc-_view-view} */ view( designname: string, viewname: string, - params: DocumentViewParams, - callback?: Callback> + params: DocumentViewParams ): Promise>; /** Executes a view from a Design Document as a stream * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/views.html#get--db-_design-ddoc-_view-view} */ @@ -542,8 +519,7 @@ declare namespace nano { viewWithList( designname: string, viewname: string, - listname: string, - callback?: Callback + listname: string ): Promise; /** Applies a list function to a view with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#db-design-design-doc-list-list-name-view-name} */ @@ -551,16 +527,14 @@ declare namespace nano { designname: string, viewname: string, listname: string, - params: DocumentViewParams, - callback?: Callback + params: DocumentViewParams ): Promise; /** Applies a list function to a view as a stream. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#db-design-design-doc-list-list-name-view-name} */ viewWithListAsStream( designname: string, viewname: string, - listname: string, - callback?: Callback + listname: string ): NodeJS.ReadStream; /** Applies a list function to a view with options as a stream. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/ddoc/render.html#db-design-design-doc-list-list-name-view-name} */ @@ -568,26 +542,25 @@ declare namespace nano { designname: string, viewname: string, listname: string, - params: DocumentViewParams, - callback?: Callback + params: DocumentViewParams ): NodeJS.ReadStream; /** Run Mango query. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/database/find.html#db-find} */ - find(query: MangoQuery, callback?: Callback>): Promise >; + find(query: MangoQuery): Promise >; /** Server scope */ server: ServerScope; /** Fetch information about a single partition in this database. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/partitioned-dbs.html#db-partition-partition} */ - partitionInfo(partitionKey: string, callback?: Callback): Promise ; + partitionInfo(partitionKey: string): Promise ; /** List documents in a single partition in this database. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/partitioned-dbs.html#db-partition-partition-all-docs} */ - partitionedList(partitionKey: string, params?: DocumentFetchParams, callback?: Callback>): Promise>; + partitionedList(partitionKey: string, params?: DocumentFetchParams): Promise>; /** List documents in a single partition in this database as a stream. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/partitioned-dbs.html#db-partition-partition-all-docs} */ partitionedListAsStream(partitionKey: string, params?: DocumentFetchParams): NodeJS.ReadStream; /** Run Mango query a single partition in this database. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/partitioned-dbs.html#db-partition-partition-id-find} */ - partitionedFind(partitionKey: string, query: MangoQuery, callback?: Callback>): Promise >; + partitionedFind(partitionKey: string, query: MangoQuery): Promise >; /** Run Mango query a single partition in this database, as a stream. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/partitioned-dbs.html#db-partition-partition-id-find} */ partitionedFindAsStream(partitionKey: string, query: MangoQuery): NodeJS.ReadStream; @@ -596,8 +569,7 @@ declare namespace nano { partitionKey: string, designname: string, searchname: string, - params: DocumentSearchParams, - callback?: Callback> + params: DocumentSearchParams ): Promise>; /** Run a full-text search in a single partition in this database, as a stream. */ partitionedSearchAsStream( @@ -612,8 +584,7 @@ declare namespace nano { partitionKey: string, designname: string, viewname: string, - params: DocumentViewParams, - callback?: Callback> + params: DocumentViewParams ): Promise>; /** Executes the specified view function in a single partition from the specified design document, as a stream * @see Docs: {@link https://docs.couchdb.org/en/latest/api/partitioned-dbs.html#db-partition-partition-design-design-doc-view-view-name} */ @@ -636,16 +607,16 @@ declare namespace nano { interface Multipart { /** Create doc with multiple attachments using mutlipart HTTP request. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#creating-multiple-attachments} */ - insert(doc: D, attachments: AttachmentData[], callback?: Callback): Promise; + insert(doc: D, attachments: AttachmentData[]): Promise; /** Create doc with multiple attachments using mutlipart HTTP request with options. * @see Docs: {@link http://docs.couchdb.org/en/latest/api/document/common.html#creating-multiple-attachments} */ - insert(doc: D, attachments: AttachmentData[], params: any, callback?: Callback): Promise; + insert(doc: D, attachments: AttachmentData[], params: any): Promise; /** Fetch document and its attachments as a multipart HTTP request. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/common.html#efficient-multiple-attachments-retrieving} */ - get(docname: string, callback?: Callback): Promise; + get(docname: string): Promise; /** Fetch document and its attachments as a multipart HTTP request with options. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/common.html#efficient-multiple-attachments-retrieving} */ - get(docname: string, params: any, callback?: Callback): Promise; + get(docname: string, params: any): Promise; } /** Attachment functions */ @@ -656,8 +627,7 @@ declare namespace nano { docname: string, attname: string, att: any, - contenttype: string, - callback?: Callback + contenttype: string ): Promise; /** Insert an attachment with options. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/attachments.html#put--db-docid-attname} */ @@ -666,12 +636,11 @@ declare namespace nano { attname: string, att: any, contenttype: string, - params: any, - callback?: Callback + params: any ): Promise; /** Get an attachment. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/attachments.html#get--db-docid-attname} */ - get(docname: string, attname: string, callback?: Callback): Promise; + get(docname: string, attname: string): Promise; /** Get an attachment as a stream. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/attachments.html#get--db-docid-attname} */ getAsStream(docname: string, attname: string): NodeJS.ReadStream; @@ -680,19 +649,17 @@ declare namespace nano { get( docname: string, attname: string, - params: any, - callback?: Callback + params: any ): Promise; /** Delete an attachment. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/attachments.html#delete--db-docid-attname} */ - destroy(docname: string, attname: string, callback?: Callback): Promise; + destroy(docname: string, attname: string): Promise; /** Delete an attachment with options. * @see Docs: {@link https://docs.couchdb.org/en/latest/api/document/attachments.html#delete--db-docid-attname} */ destroy( docname: string, attname: string, - params: any, - callback?: Callback + params: any ): Promise; } @@ -703,7 +670,7 @@ declare namespace nano { } /** Custom request options - * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts-callback}*/ + * @see README: {@link https://www.npmjs.com/package/nano#nanorequestopts}*/ interface RequestOptions { db?: string; method?: string; From 72bcb2f09a4d5541e314f5a7a323bbbcecefccaf Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 7 Nov 2024 10:18:57 +0000 Subject: [PATCH 38/40] remove the examples as they are ancient and beyond redemption --- examples/bulk_transform.js | 46 -------- examples/express.js | 29 ----- examples/lazy_creation_of_views.js | 115 ------------------- examples/lazy_db_creation_and_replication.js | 65 ----------- examples/pipe.js | 25 ---- examples/readme.md | 7 -- 6 files changed, 287 deletions(-) delete mode 100644 examples/bulk_transform.js delete mode 100644 examples/express.js delete mode 100644 examples/lazy_creation_of_views.js delete mode 100644 examples/lazy_db_creation_and_replication.js delete mode 100644 examples/pipe.js delete mode 100644 examples/readme.md diff --git a/examples/bulk_transform.js b/examples/bulk_transform.js deleted file mode 100644 index 8954f718..00000000 --- a/examples/bulk_transform.js +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const db = require('nano')('http://127.0.0.1:5984/emails') -const async = require('async') - -function updateRow (row, cb) { - const doc = row.doc - delete doc.subject - db.insert(doc, doc._id, function (err, data) { - if (err) { console.log('err at ' + doc._id); cb(err) } else { console.log('updated ' + doc._id); cb() } - }) -} - -function list (offset) { - let ended = false - offset = offset || 0 - db.list({ include_docs: true, limit: 10, skip: offset }, - function (err, data) { - let rows - if (err) { console.log('fuuuu: ' + err.message); rows = []; return } - const total = data.total_rows - const offset = data.offset - rows = data.rows - if (offset === total) { - ended = true - return - } - async.forEach(rows, updateRow, function (err) { - if (err) { console.log('something failed, check logs') } - if (ended) { return } - list(offset + 10) - }) - }) -} - -list() diff --git a/examples/express.js b/examples/express.js deleted file mode 100644 index f09a7252..00000000 --- a/examples/express.js +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const express = require('express') -const db = require('nano')('http://127.0.0.1:5984/my_couch') -const app = module.exports = express() - -app.get('/', function (req, res) { - db.get('foo', function (error, body, headers) { - if (error) { - res.status(error.statusCode) - return res.send(error.message) - } - res.status(200) - res.send(body) - }) -}) - -app.listen(3333) -console.log('server is running. check expressjs.com for more cool tricks') diff --git a/examples/lazy_creation_of_views.js b/examples/lazy_creation_of_views.js deleted file mode 100644 index 47b8524e..00000000 --- a/examples/lazy_creation_of_views.js +++ /dev/null @@ -1,115 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -module.exports = function () { - const nano = require('nano')('http://127.0.0.1:5984') - const users = nano.use('users') - const VIEWS = { - by_twitter_id: - { map: 'function(doc) { emit(doc.twitter.screen_name, doc); }' } - } - - /***************************************************************************** - * user.get() - ****************************************************************************/ - function userGet (id, callback) { - return users.get(id, callback) - } - - /***************************************************************************** - * user.new() - ****************************************************************************/ - function userNew (id, body, callback) { - return users.insert(body, id, callback) - } - - /***************************************************************************** - * user.create() - ****************************************************************************/ - function createUsersDatabase (emailAddress, secret, name, retries) { - nano.db.create('users', function (e, b, h) { - userCreate(emailAddress, secret, name, retries + 1) - }) - } - - function userCreate (emailAddress, secret, name, retries) { - if (!retries) { - retries = 0 - } - users.insert({ emailAddress, secret, name }, secret, - function (e, b, h) { - if (e && e.message === 'no_db_file' && retries < 1) { - return createUsersDatabase(emailAddress, secret, name, retries) - } - (function () { })(e, b, h) - }) - } - - /***************************************************************************** - * user.find() - ****************************************************************************/ - // - // some more logic needed - // what if design document exists but view doesnt, we cant just overwrite it - // - // we need a way to fectch and build on - // and thats the reason why im not doing this at 5am - - function userFind (view, id, opts, tried, callback) { - if (typeof tried === 'function') { - callback = tried - tried = { tried: 0, max_retries: 2 } - } - users.view('users', view, opts, function (e, b, h) { - if (e) { - const currentView = VIEWS[view] - if (!currentView) { - e.message = 'View is not available' - return callback(e, b, h) - } - if (tried.tried < tried.max_retries) { - if (e.message === 'missing' || e.message === 'deleted') { // create design document - const designDoc = { views: {} } - designDoc.views[view] = currentView - return users.insert(designDoc, '_design/users', function () { - tried.tried += 1 - userFind(view, id, opts, tried, callback) - }) - } - if (e.message === 'missing_named_view') { - users.get('_design/users', function (e, b, h) { // create view - tried.tried += 1 - if (e) { return userFind(view, id, opts, tried, callback) } - b.views[view] = currentView - users.insert(b, '_design/users', function (e, b, h) { - return userFind(view, id, opts, tried, callback) - }) - }) - return - } - } else { return callback(e, b, h) } - } - return callback(null, b, h) - }) - } - - function userFirst (view, id, callback) { - return userFind(view, id, { startkey: ('"' + id + '"'), limit: 1 }, callback) - } - - return { - new: userNew, - get: userGet, - create: userCreate, - first: userFirst - } -} diff --git a/examples/lazy_db_creation_and_replication.js b/examples/lazy_db_creation_and_replication.js deleted file mode 100644 index ae10c5df..00000000 --- a/examples/lazy_db_creation_and_replication.js +++ /dev/null @@ -1,65 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const nano = require('nano') -const couch = - { - master: 'http://127.0.0.1:5984/landing_m', - replica: 'http://127.0.0.1:5984/landing_r' - } - -function insertWithRetry (db, email, retries, callback) { - if (typeof retries === 'function') { - callback = retries - retries = 0 - } - callback = callback || function () {} - db.insert(email, function (err, resp, head) { - if (err) { - if (err.message === 'no_db_file' && retries < 1) { - const dbName = db.config.db - const server = nano(db.config.url) - - server.db.create(dbName, function (err2, resp2, head2) { - if (err2) { return callback(err2, resp2, head2) } - insertWithRetry(db, email, retries + 1, callback) - }) - } else { return callback(err, resp, head) } - } - callback(err, resp, head) - }) -} - -function replicateWithRetry (masterUri, replicaUri, retries, callback) { - if (typeof retries === 'function') { - callback = retries - retries = 0 - } - callback = callback || function () {} - retries = retries || 0 - const master = nano(couch.master) - master.replicate(couch.replica, function (err, resp, head) { - if (err && err.error === 'db_not_found' && retries < 1) { - const replica = nano(couch.replica) - const dbName = replica.config.db - const server = nano(replica.config.url) - - server.db.create(dbName, function (err2, resp2, head2) { - if (err2) { return callback(err2, resp2, head2) } - replicateWithRetry(masterUri, replicaUri, retries + 1, callback) - }) - } - callback(err, resp, head) - }) -} - -module.exports = { insert: insertWithRetry, replicate: replicateWithRetry } diff --git a/examples/pipe.js b/examples/pipe.js deleted file mode 100644 index 5f2cc9dc..00000000 --- a/examples/pipe.js +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the 'License'); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -const express = require('express') -const nano = require('nano')('http://127.0.0.1:5984') -const app = express.createServer() -const dbName = 'test' -const db = nano.use(dbName) - -app.get('/', function (request, response) { - db.attachment.get('new', 'logo.png').pipe(response) -}) - -app.listen(3333) - -module.exports = app diff --git a/examples/readme.md b/examples/readme.md deleted file mode 100644 index 093b7cd5..00000000 --- a/examples/readme.md +++ /dev/null @@ -1,7 +0,0 @@ -# samples - -if you have a sample please feel free to send a pull request. - -also the tests are very concise and helpful. - -i would recommend taking a peek. \ No newline at end of file From e412086b7c814a61a9553197850381a17d12a3f0 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 7 Nov 2024 10:30:01 +0000 Subject: [PATCH 39/40] added callback notice to the migration guide --- migration_guide_v10_to_v11.md | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/migration_guide_v10_to_v11.md b/migration_guide_v10_to_v11.md index 2883a69c..bcd7875f 100644 --- a/migration_guide_v10_to_v11.md +++ b/migration_guide_v10_to_v11.md @@ -1,13 +1,17 @@ # Migrating from Nano 10 to Nano 11 -Nano 10 uses the Axios library as an HTTP/HTTPS client. Keeping up with changes to Axios and its dependencies made maintaining this library a chore, so as of Nano 11 we use Node.js's built-in _fetch_ API as our HTTP client. This makes Nano a _zero dependency_ library which makes for faster installs, easier maintenance and slightly better performance. +The highlights: -There are some things to bear in mind if you are switching from Nano 10 to Nano 11, so please consider the following advice carefully before you do. +- Nano 11's HTTP client is replaced with the native Node.js _fetch_ function meaning that Nano 11 only works on Node.js 18 and above. +- Nano no longer supports `requestDefaults` to configure the client options. +- Nano no longer supports callbacks. ## Node.js versions > ** Nano 11 is a breaking change for users of Node.s 16 or earlier ** +Nano 10 uses the Axios library as an HTTP/HTTPS client. Keeping up with changes to Axios and its dependencies made maintaining this library a chore, so as of Nano 11 we use Node.js's built-in _fetch_ API as our HTTP client. This makes Nano a _zero dependency_ library which makes for faster installs, easier maintenance and slightly better performance. + Nano 11 is only compatible with Node.js versions 18 and older, because it is only these Node versions that have the [fetch](https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#fetch) HTTP client baked in. See [Node.js's Long-term Support page](https://nodejs.org/en/about/previous-releases) to see which are the currently supported and maintained versions. In short: - If you are using Node.js 18 or newer, use Nano 11. @@ -17,6 +21,8 @@ Nano 10 may continue to receive some security fixes for a time, but Nano 11 repr ## Agent options +> ** Nano 11 no longer supports `requestDefaults` to configure the HTTP client ** + None of Nano's API has changed _except_ when a user is supplying non-default connection handling parameters. Gone is `requestDefaults` which dates back to the "request" days and instead an optional `agentOptions` can be provided which is documented in the README and in TypeScript. ```js @@ -43,3 +49,29 @@ const nano = Nano({ url: 'http://127.0.0.1:5984', undiciOptions }) > Note: to supply a custom agent, you will need the [undici](https://www.npmjs.com/package/undici) module as a dependency in your own project. Undici is the library that powers Node.js's _fetch_ API but its "Agent" is not programmatically accessible unless undici is imported separately. +## Callbacks + +> ** Nano 11 no longer supports callbacks ** + +In Nano 10 and earlier, the last parameter to most Nano functions was a callback so you could do: + +```js +db.list(function(err, data) { + console.log('response', err, data) +}) +``` + +This was the way asynchronous activity was handled in the early days of Node.js but as of Nano 11 all callbacks are removed and we expect the use of Promises: + +```js +db.list().then((data) => { console.log('response', data )}) +``` + +or more commonly, the `await` pattern: + +```js +const data = await db.list() +console.log('response', data) +``` + +If your code makes use of the callback style then **it will not work with Nano 11**: you will need to rewrite your code to use Promises or await, or remain on Nano 10. From 5c18b7542d8f0a7e8f449c44aaea71d777f848d8 Mon Sep 17 00:00:00 2001 From: Glynn Bird Date: Thu, 14 Nov 2024 13:49:47 +0000 Subject: [PATCH 40/40] comment why we do body = '' when there is not response body --- lib/nano.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/nano.js b/lib/nano.js index 75776c2c..9ebea4b0 100644 --- a/lib/nano.js +++ b/lib/nano.js @@ -197,6 +197,11 @@ module.exports = exports = function dbScope (cfg) { try { body = await response.json() } catch (e) { + // if we were expecting a JSON response but didn't get one, set the body to a blank string + // rather than throw an error. This happens when + // - we do HEAD /db/docid + // - or we get a 500 from CouchDB with no body + // In these cases we expect a rejected promise. body = '' }