diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..52f270c --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,219 @@ +{ + "env": { + "es6": true, + "node": true + }, + "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended" ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parser": "@typescript-eslint/parser", + "plugins": [ "@typescript-eslint" ], + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "module" + }, + "rules": { + "accessor-pairs": "warn", + "array-callback-return": "warn", + "array-bracket-newline": [ "warn", "consistent" ], + "array-bracket-spacing": [ "warn", "always", { "objectsInArrays": false, "arraysInArrays": false }], + "arrow-spacing": "warn", + "block-scoped-var": "warn", + "block-spacing": [ "warn", "always" ], + "brace-style": [ "warn", "1tbs" ], + "callback-return": "warn", + "camelcase": "warn", + "comma-dangle": [ "warn", "only-multiline" ], + "comma-spacing": [ + "warn", + { + "after": true, + "before": false + } + ], + "comma-style": "warn", + "computed-property-spacing": [ + "warn", + "never" + ], + "consistent-this": "warn", + "dot-notation": [ + "warn", + { + "allowKeywords": true + } + ], + "dot-location": [ + "error", + "property" + ], + "eol-last": [ + "warn", + "never" + ], + "eqeqeq": "warn", + "func-call-spacing": "warn", + "func-name-matching": "warn", + "func-names": "warn", + "func-style": "warn", + "function-paren-newline": "warn", + "generator-star-spacing": "warn", + "grouped-accessor-pairs": "warn", + "guard-for-in": "warn", + "handle-callback-err": "warn", + "id-blacklist": "warn", + "id-match": "warn", + "implicit-arrow-linebreak": "warn", + "indent": "warn", + "init-declarations": "warn", + "jsx-quotes": [ "warn", "prefer-single" ], + "key-spacing": [ "warn", { "beforeColon": false, "afterColon": true }], + "keyword-spacing": [ "warn", { "after": true, "before": true }], + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "warn", + "lines-around-directive": "warn", + "max-classes-per-file": "warn", + "max-nested-callbacks": "warn", + "new-parens": "warn", + "no-alert": "warn", + "no-array-constructor": "warn", + "no-bitwise": "warn", + "no-buffer-constructor": "warn", + "no-caller": "warn", + "no-console": "warn", + "no-div-regex": "warn", + "no-dupe-else-if": "warn", + "no-duplicate-imports": "warn", + "no-else-return": "warn", + "no-empty-function": "warn", + "no-eq-null": "warn", + "no-eval": "warn", + "no-extend-native": "warn", + "no-extra-bind": "warn", + "no-extra-label": "warn", + "no-extra-parens": "warn", + "no-floating-decimal": "warn", + "no-implicit-coercion": "warn", + "no-implicit-globals": "warn", + "no-implied-eval": "error", + "no-import-assign": "warn", + "no-invalid-this": "warn", + "no-iterator": "warn", + "no-label-var": "warn", + "no-lone-blocks": "warn", + "no-lonely-if": "warn", + "no-loop-func": "warn", + "no-mixed-requires": "warn", + "no-multi-assign": "warn", + "no-multi-spaces": "warn", + "no-multi-str": "warn", + "no-multiple-empty-lines": "warn", + "no-native-reassign": "warn", + "no-negated-in-lhs": "warn", + "no-negated-condition": "error", + "no-nested-ternary": "warn", + "no-new": "warn", + "no-new-func": "warn", + "no-new-object": "warn", + "no-new-require": "warn", + "no-new-wrappers": "warn", + "no-octal-escape": "warn", + "no-path-concat": "warn", + "no-process-exit": "warn", + "no-proto": "warn", + "no-restricted-globals": "warn", + "no-restricted-imports": "warn", + "no-restricted-modules": "warn", + "no-restricted-properties": "warn", + "no-restricted-syntax": "warn", + "no-return-assign": "warn", + "no-return-await": "warn", + "no-script-url": "warn", + "no-self-compare": "warn", + "no-sequences": "warn", + "no-setter-return": "warn", + "no-spaced-func": "warn", + "@typescript-eslint/no-shadow": "error", + "no-tabs": "warn", + "no-template-curly-in-string": "error", + "no-throw-literal": "warn", + "no-undef-init": "error", + "no-undefined": "error", + "no-unmodified-loop-condition": "warn", + "no-unneeded-ternary": "error", + "no-unused-expressions": "warn", + "no-use-before-define": "error", + "no-useless-call": "warn", + "no-useless-computed-key": "warn", + "no-useless-concat": "warn", + "no-useless-constructor": "warn", + "no-useless-rename": "warn", + "no-useless-return": "warn", + "no-var": "warn", + "no-void": "warn", + "no-whitespace-before-property": "error", + "nonblock-statement-body-position": [ "warn", "below" ], + "object-curly-spacing": [ + "warn", + "always" + ], + "object-property-newline": [ "warn", { "allowAllPropertiesOnSameLine": true }], + "object-shorthand": "warn", + "one-var-declaration-per-line": "warn", + "operator-assignment": "warn", + "operator-linebreak": [ "warn", "before" ], + "padding-line-between-statements": "warn", + "padded-blocks": [ "warn", { "switches": "never" }, { "allowSingleLineBlocks": true }], + "prefer-arrow-callback": "warn", + "prefer-const": "warn", + "prefer-destructuring": "warn", + "prefer-exponentiation-operator": "warn", + "prefer-numeric-literals": "warn", + "prefer-object-spread": "error", + "prefer-promise-reject-errors": "warn", + "prefer-regex-literals": "warn", + "prefer-rest-params": "warn", + "prefer-spread": "warn", + "require-jsdoc": "warn", + "require-unicode-regexp": "warn", + "rest-spread-spacing": "warn", + "semi": "error", + "semi-spacing": "warn", + "semi-style": [ + "warn", + "last" + ], + "space-before-blocks": "warn", + "space-before-function-paren": [ "error", "always" ], + "space-in-parens": [ + "warn", + "never" + ], + "spaced-comment": [ "warn", "always" ], + "strict": "warn", + "switch-colon-spacing": "warn", + "symbol-description": "warn", + "template-curly-spacing": [ + "warn", + "never" + ], + "template-tag-spacing": "warn", + "unicode-bom": [ + "warn", + "never" + ], + "vars-on-top": "warn", + "wrap-iife": "warn", + "wrap-regex": "error", + "yield-star-spacing": "warn", + "yoda": [ + "warn", + "never" + ] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ceaea36..1e9f773 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ bower_components # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release +build # Dependency directories node_modules/ diff --git a/README.md b/README.md index f7e039b..f7b044c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ # wrappers -Various wrapper classes I use in my projects \ No newline at end of file +Various wrapper classes I use in my projects. +These are specifically written for my use cases, though feel free to use. + +MessageBroker: Wraps `amqp-connection-manager` and `amqplib` by extension. Ensures smooth failover when connected to a cluster. +MariaDB: Wraps `mysql`. Takes care of connection pooling whether connecting to a cluster or single instance. +MongoDB: Wraps `mongodb`. Primarily just adds helper functions. + +Expected to be used together with a parent class that has a `createLogger` method, as defined in `/src/interfaces/Server.ts` and `/src/interfaces/Logger.ts`, utilising the logger from https://git.corgi.wtf/Navy.gif/logger. \ No newline at end of file diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..1945314 --- /dev/null +++ b/index.ts @@ -0,0 +1,3 @@ +export { MessageBroker } from "./src/MessageBroker.js"; +export { MariaDB } from './src/MariaDB.js'; +export { MongoDB } from './src/MongoDB.js'; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e1266af --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "@navy.gif/wrappers", + "version": "1.0.0", + "description": "Various wrapper classes I use in my projects", + "main": "index.js", + "repository": "https://git.corgi.wtf/Navy.gif/wrappers.git", + "author": "Navy.gif", + "license": "MIT", + "private": false, + "type": "module", + "files": [ + "build" + ], + "scripts": { + "build": "tsc", + "test": "tsc && jest", + "release": "tsc && yarn publish", + "lint": "eslint --fix" + }, + "devDependencies": { + "@types/amqplib": "^0.10.1", + "@types/mysql": "^2.15.21", + "@types/node": "^18.15.11", + "@typescript-eslint/eslint-plugin": "^5.57.1", + "@typescript-eslint/parser": "^5.57.1", + "eslint": "^8.37.0", + "typescript": "^5.0.3" + }, + "dependencies": { + "amqp-connection-manager": "^4.1.12", + "amqplib": "^0.10.3", + "mongodb": "^5.2.0", + "mysql": "^2.18.1" + } +} diff --git a/src/MariaDB.ts b/src/MariaDB.ts new file mode 100644 index 0000000..c1db9a8 --- /dev/null +++ b/src/MariaDB.ts @@ -0,0 +1,223 @@ +import { inspect } from 'node:util'; +import { ILogger, IServer } from './interfaces/index.js'; + +import mysql, { Pool, PoolCluster, PoolClusterConfig, PoolConfig, PoolConnection, FieldInfo } from 'mysql'; +import { LoggerClientOptions } from './interfaces/Logger.js'; + +const SAFE_TO_RETRY = [ 'ER_LOCK_DEADLOCK' ]; + +type Credentials = { + user: string, + password: string, + host: string, + port: number, + database: string +} + +type MariaOptions = { + load: boolean, + cluster: PoolClusterConfig, + client: PoolConfig, + credentials: Credentials, + loggerOptions?: LoggerClientOptions +} + +type MariaError = { + code: string, + errno: number, + fatal: boolean, + sql: string, + sqlState: string, + sqlMessage:string +} & Error + +class MariaDB { + + #_activeQueries: number; + #afterLastQuery: (() => void) | null; + #logger: ILogger; + #_ready: boolean; + + #config: MariaOptions; + #credentials: Credentials[]; + #cluster: boolean; + #pool: PoolCluster | Pool | null; + + constructor (server: IServer, options: MariaOptions) { + + if (!server) + throw new Error('Missing reference to server!'); + if (!options) + throw new Error('No config options provided!'); + + this.#config = options; + const { host, user, port, password, database } = options.credentials; + const hosts = host.split(','); + this.#credentials = []; + for (const remote of hosts) { + this.#credentials.push({ host: remote, user, port, password, database }); + } + + this.#pool = null; + this.#_ready = false; + + this.#_activeQueries = 0; + this.#afterLastQuery = null; + + this.#cluster = this.#credentials.length > 1; + this.#logger = server.createLogger(this, options.loggerOptions); + + } + + get ready () { + return this.#_ready; + } + + get activeQueries () { + return this.#_activeQueries; + } + + async init () { + + if (this.#config.load) + return this.#logger.info('Not loading MariaDB'); + + this.#logger.status(`Creating${this.#cluster ? ' cluster' : ''} connection pool`); + if (this.#cluster) { + this.#pool = mysql.createPoolCluster(this.#config.cluster); + for (const creds of this.#credentials) + this.#pool.add({ ...this.#config.client, ...creds }); + } else { + this.#pool = mysql.createPool({ ...this.#config.client, ...this.#credentials[0] }); + } + + this.#pool.on('connection', (connection) => { + this.#logger.debug(`New connection: ${connection?.threadId || null}`); + }); + + this.#pool.on('acquire', (connection) => { + this.#_activeQueries++; + this.#logger.debug(`Connection acquired: ${connection?.threadId || null}`); + }); + + this.#pool.on('enqueue', () => { + this.#logger.debug(`Query enqueued for connection`); + }); + + this.#pool.on('release', (connection) => { + this.#_activeQueries--; + + if (!this.ready && !this.#_activeQueries && this.#afterLastQuery) + this.#afterLastQuery(); + + this.#logger.debug(`Connection released: ${connection?.threadId || null}`); + }); + + this.#logger.info(`Testing MariaDB connection`); + await new Promise((resolve, reject) => { + if (!this.#pool) + return reject(new Error('Missing connection pool')); + this.#pool.getConnection((err, conn) => { + if (err) + return reject(err); + conn.release(); + return resolve(); + }); + }); + + this.#logger.status(`Database connected`); + this.#_ready = true; + + return this; + + } + + async close () { + this.#logger.status(`Shutting down database connections`); + if (!this.ready) + return Promise.resolve(); + this.#_ready = false; + if (this.#_activeQueries) { + this.#logger.info(`${this.#_activeQueries} active queries still running, letting them finish`); + await this.finishQueries(); + this.#logger.info(`Queries finished, shutting down`); + } + return new Promise(resolve => { + if (!this.#pool) + return resolve(); + this.#pool.end(() => { + this.#pool?.removeAllListeners(); + resolve(); + }); + }); + } + + finishQueries () { + return new Promise(resolve => { + this.#afterLastQuery = resolve; + }); + } + + getConnection (): Promise { + return new Promise((resolve, reject) => { + if (!this.#pool) + return reject(new Error('Pool closed')); + this.#pool.getConnection((err, conn) => { + if (err) + return reject(err); + resolve(conn); + }); + }); + } + + /** + * Retry certain queries that are safe to retry, e.g. deadlock + * @throws {MariaError} + * @private + * */ + async #_query (query: string, values: (string | number | string[] | number[])[], timeout?: number, attempts = 0): Promise { + const connection = await this.getConnection(); + try { + const result = await new Promise((resolve, reject) => { + const q = connection.query({ timeout, sql: query }, values, (err, results, fields) => { + if (err) + reject(err); + else if (results) + resolve(results); + else + resolve(fields); + connection.release(); + }); + this.#logger.debug(`Constructed query: ${q.sql}`); + }); + return Promise.resolve(result ?? null); + } catch (err) { + const error = err as MariaError; + // Retry safe errors // (Galera) Instance not ready for query + if ((SAFE_TO_RETRY.includes(error.code) || error.errno === 1047) && attempts < 5) // + return this.#_query(query, values, timeout, ++attempts); + return Promise.reject(error); + } + } + + async query (query: string, values: (string | number | string[] | number[])[], timeout?: number) { + + if (!this.ready) + return Promise.reject(new Error('MariaDB not ready')); + + let batch = false; + if (values && typeof values.some === 'function') + batch = values.some(val => val instanceof Array); + this.#logger.debug(`Incoming query (batch: ${batch})\n${query}\n${inspect(values)}`); + + return this.#_query(query, values, timeout); + + } + + q (query: string, values: (string | number | string[] | number[])[], timeout?: number) { + return this.query(query, values, timeout); + } + +} + +export { MariaDB }; \ No newline at end of file diff --git a/src/MessageBroker.ts b/src/MessageBroker.ts new file mode 100644 index 0000000..3dd1094 --- /dev/null +++ b/src/MessageBroker.ts @@ -0,0 +1,333 @@ +import { ILogger, IServer } from "./interfaces/index.js"; +import amqp, { AmqpConnectionManager, ChannelWrapper } from 'amqp-connection-manager'; +import { Channel, ConfirmChannel, ConsumeMessage, Options } from 'amqplib'; + +type ExchangeDef = { + durable?: boolean, + internal?: boolean, + autoDelete?: boolean, + type?: string, + arguments?: object +} + +type QueueDef = { + durable?: boolean, + messageTtl?: number, + exclusive?: boolean, + autoDelete?: boolean, + arguments?: string, + expires?: number, + deadLetterExchange?: string, + maxLength: number, + maxPriority: number +} + +type BrokerOptions = { + host: string, + user: string, + pass: string, + vhost: string, + exchanges?: { + [key: string]: ExchangeDef + }, + queues?: { + [key: string]: QueueDef + } +} + +type InternalMessage = { + properties: object, + content: object +} + +type InternalPublishMsg = { + exchange: string, + routingKey: string, +} & InternalMessage + +type InternalQueueMsg = { + queue: string +} & InternalMessage + +type Consumer = (content: object, msg: ConsumeMessage) => Promise +type Subscriber = (content: object, msg: ConsumeMessage) => Promise + +class MessageBroker { + + // Broker definitions + server: IServer; + hosts: string[]; + username: string; + password: string; + vhost: string; + exchanges: { [key: string]: ExchangeDef }; + queues: {[key: string]: QueueDef}; + + // Wrapper related + connection: AmqpConnectionManager | null; + channel: ChannelWrapper | null; + + logger: ILogger; + subscribers: Map; + consumers: Map; + + _pQueue: InternalPublishMsg[]; + _qQueue: InternalQueueMsg[]; + _qTO: NodeJS.Timeout | null; + + constructor (server: IServer, options: BrokerOptions) { + this.server = server; + + this.hosts = options.host.split(','); + this.username = options.user; + this.password = options.pass; + this.vhost = options.vhost || ''; + + this.exchanges = options.exchanges || {}; + this.queues = options.queues || {}; + + this.connection = null; + this.channel = null; + this.logger = server.createLogger(this); + + // Exchanges + this.subscribers = new Map(); + // Queues + this.consumers = new Map(); + + // Internal queues for trying durign connection outage + this._pQueue = []; + this._qQueue = []; + this._qTO = null; + + } + + async init () { + + this.logger.info('Initialising message broker'); + const credentials = this.username ? `${this.username}:${this.password}@` : ''; + const connectionStrings = this.hosts.map(host => `amqp://${credentials}${host}/${this.vhost}`); + this.connection = await amqp.connect(connectionStrings); + + this.connection.on('disconnect', async ({ err }) => { + this.logger.status(`Disconnected: ${err.message}`); + await this.channel?.close(); + this.channel = null; + }); + this.connection.on('blocked', ({ reason }) => { + this.logger.status(`Blocked: ${reason}`); + }); + this.connection.on('connectFailed', ({ err }) => { + this.logger.error(`Message broker failed to connect: ${err.stack || err.message}`); + }); + this.connection.on('connect', async ({ url }) => { + this.logger.status(`Message broker connected to ${url}`); + }); + + await new Promise((resolve) => { + this.connection?.once('connect', resolve); + }); + + await this.createChannel(); + this.connection.on('connect', this.createChannel.bind(this)); + + } + + async createChannel () { + const exchanges = Object.entries(this.exchanges); + const queues = Object.entries(this.queues); + + if (this.channel) { + this.logger.debug('Closing old channel'); + await this.channel.close().catch(err => this.logger.error(err.stack)); + } + + if (!this.connection) + throw new Error(); + this.logger.debug('Creating channel'); + this.channel = this.connection.createChannel({ + setup: async (channel: Channel | ConfirmChannel) => { + for (const [ name, props ] of exchanges) { + await channel.assertExchange(name, props.type ?? 'fanout', props); + } + for (const [ name, props ] of queues) { + await channel.assertQueue(name, props); + } + } + }); + + this.channel.on('close', () => this.logger.status('Channel closed')); + this.channel.on('connect', () => this.logger.status('Channel connected')); + this.channel.on('error', (err, info) => this.logger.error(`${info.name}: ${err.stack}`)); + + await new Promise((resolve, reject) => { + if (!this.channel) + return reject(new Error('Missing channel?')); + this.channel.once('error', reject); + this.channel.once('connect', resolve); + }); + + // If the create channel function was called as a result of a failover we'll have to resubscribe + await this._restoreListeners(); + // Processes the interal queues of undelivered messages + await this._processQueues(); + } + + // Consume queue + async consume (queue: string, consumer: Consumer, options: Options.Consume) { + if (!this.channel) + throw new Error('Channel does not exist'); + + this.logger.debug(`Adding queue consumer for ${queue}`); + await this._consume(queue, consumer, options); + + const list = this.consumers.get(queue) ?? []; + list.push({ consumer, options }); + this.consumers.set(queue, list); + } + + private async _consume (queue: string, consumer: Consumer, options: Options.Consume) { + if (!this.channel) + return Promise.reject(new Error('Channel doesn\'t exist')); + await this.channel.consume(queue, async (msg: ConsumeMessage) => { + if (msg.content) + await consumer(JSON.parse(msg.content.toString()), msg); + this.channel?.ack(msg); + }, options); + } + + // Subscribe to exchange, ensures messages aren't lost by binding it to a queue + async subscribe (name: string, listener: Subscriber) { + if (!this.channel) + throw new Error('Channel does not exist'); + + this.logger.debug(`Subscribing to ${name}`); + // if (!this.subscribers.has(name)) + await this._subscribe(name, listener); + + const list = this.subscribers.get(name) ?? []; + list.push(listener); + this.subscribers.set(name, list); + + } + + private async _subscribe (name: string, listener: Subscriber) { + if (!this.channel) + return Promise.reject(new Error('Channel doesn\'t exist')); + + await this.channel.assertExchange(name, 'fanout', { durable: true }); + const queue = await this.channel.assertQueue('', { exclusive: true }); + + await this.channel.bindQueue(queue.queue, name, ''); + await this.channel.consume(queue.queue, async (msg) => { + if (msg.content) + await listener(JSON.parse(msg.content.toString()), msg); + this.channel?.ack(msg); + }); + } + + // Add item to queue + async enqueue (queue: string, content: object, headers: object) { + const properties = { + persistent: true, + contentType: 'application/json', + headers + }; + + // The channel is null while the failover is occurring, so enqueue messages for publishing once the connection is restored + if (!this.channel) + return this._qQueue.push({ queue, content, properties }); + + try { + await this.channel.sendToQueue(queue, Buffer.from(JSON.stringify(content)), properties); + } catch (_) { + this._qQueue.push({ queue, content, properties }); + if (!this._qTO) + this._qTO = setTimeout(this._processQueues.bind(this), 5000); + } + } + + // Publish to exchange + async publish (exchange: string, content: object, { headers, routingKey = '' }: {headers?: string, routingKey?: string} = {}) { + const properties = { + contentType: 'application/json', + headers + }; + + // The channel is null while the failover is occurring, so enqueue messages for publishing once the connection is restored + if (!this.channel) + return this._pQueue.push({ exchange, content, routingKey, properties }); + + try { + await this.channel.publish(exchange, routingKey, Buffer.from(JSON.stringify(content)), properties); + } catch (err) { + const error = err as Error; + if (!error.message.includes('nack')) + this.logger.error(`Error while publishing to ${exchange}:\n${error.stack}`); + this._pQueue.push({ exchange, content, routingKey, properties }); + if (!this._qTO) + this._qTO = setTimeout(this._processQueues.bind(this), 5000); + } + } + + assertExchange (exchange: string, props: ExchangeDef) { + if (!this.channel) + throw new Error('Channel doesn\'t exist'); + return this.channel.assertExchange(exchange, props.type ?? 'fanout', props); + } + + assertQueue (queue: string, opts: QueueDef) { + if (!this.channel) + throw new Error('Channel doesn\'t exist'); + return this.channel.assertQueue(queue, opts); + } + + // Processes messages queued up while the broker was unreachable + private async _processQueues () { + if (!this.channel) + throw new Error('Channel doesn\'t exist'); + this.logger.status('Processing queues of unsent messages'); + const pQ = [ ...this._pQueue ]; + this._pQueue = []; + for (const msg of pQ) { + const { exchange, content, routingKey, properties } = msg; + const result = await this.channel.publish(exchange, routingKey, Buffer.from(JSON.stringify(content)), properties).catch(() => null); + if (!result) + this._pQueue.push(msg); + } + const qQ = [ ...this._qQueue ]; + for (const msg of qQ) { + const { queue, content, properties } = msg; + const result = await this.channel.sendToQueue(queue, Buffer.from(JSON.stringify(content)), properties).catch(() => null); + if (!result) + this._qQueue.push(msg); + } + this.logger.status('Done processing'); + if (this._qTO) { + clearTimeout(this._qTO); + this._qTO = null; + } + } + + private async _restoreListeners () { + this.logger.status(`Restoring ${this.consumers.size} consumers`); + for (const [ name, list ] of this.consumers) { + this.logger.debug(`Processing consumer ${name}: ${list.length}`); + for (const { consumer, options } of list) { + await this._consume(name, consumer, options); + } + } + + this.logger.status(`Restoring ${this.subscribers.size} subscribers`); + for (const [ name, list ] of this.subscribers) { + this.logger.debug(`Processing subscriber ${name}: ${list.length}`); + for (const subscriber of list) { + await this._subscribe(name, subscriber); + } + } + this.logger.status(`Done restoring`); + } + +} + +export { MessageBroker }; \ No newline at end of file diff --git a/src/MongoDB.ts b/src/MongoDB.ts new file mode 100644 index 0000000..bbd8e88 --- /dev/null +++ b/src/MongoDB.ts @@ -0,0 +1,316 @@ +import { inspect } from "node:util"; +import { MongoClient, MongoClientOptions, Db } from "mongodb"; +import { IServer, ILogger, LoggerClientOptions } from "./interfaces/index.js"; + +type Credentials = { + URI: string, + user: string, + password: string, + host: string, + port: number, + database: string, + authDb: string +} + +type MongoOptions = { + credentials: Credentials, + loggerOptions: LoggerClientOptions, + client: MongoClientOptions +} + +/** + * A dedicated class to locally wrap the mongodb API wrapper + * + * @class MongoDB + */ +class MongoDB { + + #database: string; + #config: MongoOptions; + #logger: ILogger; + #URI: string; + + #db: Db | null; + #client: MongoClient; + + constructor (server: IServer, config: MongoOptions) { + + if (!server) + throw new Error('Missing reference to server!'); + if (!config) + throw new Error('No config options provided!'); + + const { user, password, host, port, database, URI, authDb } = config.credentials; + if ((!host?.length || !port || !database?.length) && !URI) + throw new Error(`Must provide host, port, and database OR URI parameters!`); + + this.#config = config; + this.#db = null; // DB connection + this.#database = database; // Which database to connect to + + this.#logger = server.createLogger(this, config.loggerOptions); + + if (URI) { + this.#URI = URI; + } else { + let AUTH_DB = authDb; + const auth = user ? `${user}:${password}@` : ''; + if (!AUTH_DB && auth) { + this.#logger.warn(`No explicit auth db provided with MONGO_AUTH_DB, will attempt to use MONGO_DB for auth source`); + AUTH_DB = authDb; + } else if (!auth) { + this.#logger.warn(`No auth provided, proceeding without`); + } + + this.#URI = `mongodb://${auth}${host}:${port}/${AUTH_DB || ''}?readPreference=secondaryPreferred`; + } + + this.#client = new MongoClient(this.#URI, this.#config.client); + + // TODO figure out reconnecting to DB when connection fails + this.#client.on('error', (error) => this.#logger.error(`MongoDB error:\n${error.stack}`)) + .on('timeout', () => this.#logger.warn(`MongoDB timed out`)) + .on('close', () => this.#logger.info(`MongoDB client disconnected`)) + .on('open', () => this.#logger.info(`MongoDB client connected`)); + + } + + /** + * Initialises the connection to Mongo + * + * @memberof MongoDB + */ + async init () { + + this.#logger.status(`Initializing database connection to ${this.#client.options.hosts}`); + + await this.#client.connect(); + this.#logger.debug(`Connected, selecting DB`); + this.#db = await this.#client.db(this.#database); + + this.#logger.status('MongoDB ready'); + + return this; + + } + + async close () { + this.#logger.status('Closing database connection'); + await this.#client.close(); + this.#db = null; + } + + get mongoClient () { + return this.#client; + } + + /** + * Find and return the first match + * + * @param {String} db The collection in which the data is to be updated + * @param {Object} query The filter that is used to find the data + * @returns {Array} An array containing the corresponding objects for the query + * @memberof Database + */ + async find (db: string, query: object, options: object) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming find query for ${db} with parameters ${inspect(query)}`); + + const cursor = this.#db.collection(db).find(query, options); + return cursor.toArray(); + + } + + /** + * Find and return the first match + * + * @param {String} db The collection in which the data is to be updated + * @param {Object} query The filter that is used to find the data + * @returns {Object} An object containing the queried data + * @memberof Database + */ + async findOne (db: string, query: object, options = {}) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming findOne query for ${db} with parameters ${inspect(query)}`); + const result = await this.#db.collection(db).findOne(query, options); + return result; + + } + + /** + * Update any and all filter matches. + * + * @param {String} db The collection in which the data is to be updated + * @param {Object} filter The filter that is used to find the data + * @param {Object} data The updated data + * @returns {WriteResult} Object containing the followint counts: Matched, Upserted, Modified + * @memberof Database + */ + async updateMany (db: string, filter: object, data: object, upsert = false) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + if (!filter) + throw new Error(`Cannot run update many without a filter, if you mean to update every single document, pass an empty object`); + + this.#logger.debug(`Incoming update query for '${db}' with parameters\n${inspect(filter)}\nand data\n${inspect(data)}`); + const result = await this.#db.collection(db).updateMany(filter, { $set: data }, { upsert }); + return result; + + } + + /** + * Update the first filter match. + * + * @param {String} db The collection in which the data is to be updated + * @param {Object} filter The filter that is used to find the data + * @param {Object} data The updated data + * @returns {WriteResult} Object containing the followint counts: Matched, Upserted, Modified + * @memberof Database + */ + async updateOne (db: string, filter: object, data: object, upsert = false) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming updateOne query for ${db} with parameters ${inspect(filter)}`); + const result = await this.#db.collection(db).updateOne(filter, { $set: data }, { upsert }); + return result; + + } + + /** + * Insert document. + * + * @param {String} db The collection in which the data is to be updated + * @param {Object} filter The filter that is used to find the data + * @param {Object} data The updated data + * @returns {WriteResult} Object containing the followint counts: Matched, Upserted, Modified + * @memberof Database + */ + async insertOne (db: string, data: object) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming insertOne query for ${db} with parameters ${inspect(data)}`); + const result = await this.#db.collection(db).insertOne(data); + return result; + + } + + async deleteOne (db: string, filter: object) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming deleteOne query for ${db} with parameters ${inspect(filter)}`); + const result = await this.#db.collection(db).deleteOne(filter); + return result; + + } + + /** + * Push data to an array + * + * @param {string} db The collection to query + * @param {object} filter The filter to find the document to update + * @param {object} data The data to be pushed + * @param {boolean} [upsert=false] + * @returns + * @memberof Database + */ + async push (db: string, filter: object, data: object, upsert = false) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming push query for ${db}, with upsert ${upsert} and with parameters ${inspect(filter)} and data ${inspect(data)}`); + const result = await this.#db.collection(db).updateOne(filter, { $push: data }, { upsert }); + return result; + + } + + /** + * Find a random element from a database + * + * @param {string} db The collection to query + * @param {object} [filter={}] The filtering object to narrow down the sample pool + * @param {number} [amount=1] Amount of items to return + * @returns {object} + * @memberof Database + */ + random (db: string, filter = {}, amount = 1) { + + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (typeof db !== 'string') + throw new TypeError('Expecting collection name for the first argument'); + + this.#logger.debug(`Incoming random query for ${db} with parameters ${inspect(filter)} and amount ${amount}`); + + if (amount > 100) + amount = 100; + + const cursor = this.#db.collection(db).aggregate([{ $match: filter }, { $sample: { size: amount } }]); + return cursor.toArray(); + + } + + stats (options = {}) { + if (!this.#db) + throw new Error(`MongoDB not connected`); + const result = this.#db.stats(options); + return result; + } + + collection (coll: string) { + if (!this.#db) + throw new Error(`MongoDB not connected`); + return this.#db.collection(coll); + } + + async ensureIndex (collection: string, indices = []) { + if (!this.#db) + throw new Error(`MongoDB not connected`); + if (!(indices instanceof Array)) + indices = [ indices ]; + await this.#db.collection(collection).createIndex(indices); + } + + async getKey (key: string, collection = 'memoryStore') { + const response = await this.findOne(collection, { key }); + if (response) + return response.value; + return null; + } + + async setKey (key: string, value: object, collection = 'memoryStore') { + await this.updateOne(collection, { key }, { value }, true); + return value; + } + +} + +export { MongoDB }; \ No newline at end of file diff --git a/src/interfaces/Logger.ts b/src/interfaces/Logger.ts new file mode 100644 index 0000000..154bc3c --- /dev/null +++ b/src/interfaces/Logger.ts @@ -0,0 +1,14 @@ +export type LoggerClientOptions = { + guard: string, + customStreams: string[], + logLevel: number, + logLevelMapping: {[key: string]: number} +} + +export interface ILogger { + info(str: string): void + status(str: string): void + debug(str: string): void + warn(str: string): void + error(str: string): void +} \ No newline at end of file diff --git a/src/interfaces/Server.ts b/src/interfaces/Server.ts new file mode 100644 index 0000000..87851e9 --- /dev/null +++ b/src/interfaces/Server.ts @@ -0,0 +1,5 @@ +import { ILogger, LoggerClientOptions } from "./Logger.js"; + +export interface IServer { + createLogger(obj: object, options?: LoggerClientOptions): ILogger +} \ No newline at end of file diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts new file mode 100644 index 0000000..defca03 --- /dev/null +++ b/src/interfaces/index.ts @@ -0,0 +1,2 @@ +export { ILogger, LoggerClientOptions } from './Logger.js'; +export { IServer } from './Server.js'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7b6e28c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ES2022", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./build", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..a149af2 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1150 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@acuminous/bitsyntax@^0.1.2": + version "0.1.2" + resolved "https://registry.corgi.wtf/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz#e0b31b9ee7ad1e4dd840c34864327c33d9f1f653" + integrity sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ== + dependencies: + buffer-more-ints "~1.0.0" + debug "^4.3.4" + safe-buffer "~5.1.2" + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.corgi.wtf/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.0" + resolved "https://registry.corgi.wtf/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" + integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== + +"@eslint/eslintrc@^2.0.2": + version "2.0.2" + resolved "https://registry.corgi.wtf/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02" + integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.1" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.38.0": + version "8.38.0" + resolved "https://registry.corgi.wtf/@eslint/js/-/js-8.38.0.tgz#73a8a0d8aa8a8e6fe270431c5e72ae91b5337892" + integrity sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g== + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.corgi.wtf/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.corgi.wtf/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.corgi.wtf/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.corgi.wtf/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.corgi.wtf/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.corgi.wtf/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/amqplib@^0.10.1": + version "0.10.1" + resolved "https://registry.corgi.wtf/@types/amqplib/-/amqplib-0.10.1.tgz#d43d14027b969e82ceec71cc17bd28e5f5abbc7b" + integrity sha512-j6ANKT79ncUDnAs/+9r9eDujxbeJoTjoVu33gHHcaPfmLQaMhvfbH2GqSe8KUM444epAp1Vl3peVOQfZk3UIqA== + dependencies: + "@types/node" "*" + +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.corgi.wtf/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/mysql@^2.15.21": + version "2.15.21" + resolved "https://registry.corgi.wtf/@types/mysql/-/mysql-2.15.21.tgz#7516cba7f9d077f980100c85fd500c8210bd5e45" + integrity sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@^18.15.11": + version "18.15.11" + resolved "https://registry.corgi.wtf/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" + integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== + +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.corgi.wtf/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + +"@types/webidl-conversions@*": + version "7.0.0" + resolved "https://registry.corgi.wtf/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" + integrity sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog== + +"@types/whatwg-url@^8.2.1": + version "8.2.2" + resolved "https://registry.corgi.wtf/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" + integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== + dependencies: + "@types/node" "*" + "@types/webidl-conversions" "*" + +"@typescript-eslint/eslint-plugin@^5.57.1": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz#b1d4b0ad20243269d020ef9bbb036a40b0849829" + integrity sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.58.0" + "@typescript-eslint/type-utils" "5.58.0" + "@typescript-eslint/utils" "5.58.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.57.1": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/parser/-/parser-5.58.0.tgz#2ac4464cf48bef2e3234cb178ede5af352dddbc6" + integrity sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ== + dependencies: + "@typescript-eslint/scope-manager" "5.58.0" + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/typescript-estree" "5.58.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.58.0": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz#5e023a48352afc6a87be6ce3c8e763bc9e2f0bc8" + integrity sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA== + dependencies: + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/visitor-keys" "5.58.0" + +"@typescript-eslint/type-utils@5.58.0": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz#f7d5b3971483d4015a470d8a9e5b8a7d10066e52" + integrity sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w== + dependencies: + "@typescript-eslint/typescript-estree" "5.58.0" + "@typescript-eslint/utils" "5.58.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.58.0": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/types/-/types-5.58.0.tgz#54c490b8522c18986004df7674c644ffe2ed77d8" + integrity sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g== + +"@typescript-eslint/typescript-estree@5.58.0": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz#4966e6ff57eaf6e0fce2586497edc097e2ab3e61" + integrity sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q== + dependencies: + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/visitor-keys" "5.58.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.58.0": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/utils/-/utils-5.58.0.tgz#430d7c95f23ec457b05be5520c1700a0dfd559d5" + integrity sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.58.0" + "@typescript-eslint/types" "5.58.0" + "@typescript-eslint/typescript-estree" "5.58.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.58.0": + version "5.58.0" + resolved "https://registry.corgi.wtf/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz#eb9de3a61d2331829e6761ce7fd13061781168b4" + integrity sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA== + dependencies: + "@typescript-eslint/types" "5.58.0" + eslint-visitor-keys "^3.3.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.corgi.wtf/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.corgi.wtf/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.corgi.wtf/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + 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" + +amqp-connection-manager@^4.1.12: + version "4.1.12" + resolved "https://registry.corgi.wtf/amqp-connection-manager/-/amqp-connection-manager-4.1.12.tgz#3592c0a21a12ce84a06f62ab44a688a3a27e8bcf" + integrity sha512-UuN2+FqS5QsFQDTIpZTm846p84Tyk1b3oB/WfxYii6uoVvWRnLBr96gmuHMEckanq0Fl7haTK+x3ikJ/S120gw== + dependencies: + promise-breaker "^6.0.0" + +amqplib@^0.10.3: + version "0.10.3" + resolved "https://registry.corgi.wtf/amqplib/-/amqplib-0.10.3.tgz#e186a2f74521eb55ec54db6d25ae82c29c1f911a" + integrity sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw== + dependencies: + "@acuminous/bitsyntax" "^0.1.2" + buffer-more-ints "~1.0.0" + readable-stream "1.x >=1.1.9" + url-parse "~1.5.10" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.corgi.wtf/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.corgi.wtf/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.corgi.wtf/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.corgi.wtf/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.corgi.wtf/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +bignumber.js@9.0.0: + version "9.0.0" + resolved "https://registry.corgi.wtf/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" + integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.corgi.wtf/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.corgi.wtf/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +bson@^5.2.0: + version "5.2.0" + resolved "https://registry.corgi.wtf/bson/-/bson-5.2.0.tgz#c81d35dd30e2798203e5422a639780ea98dd25ba" + integrity sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg== + +buffer-more-ints@~1.0.0: + version "1.0.0" + resolved "https://registry.corgi.wtf/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz#ef4f8e2dddbad429ed3828a9c55d44f05c611422" + integrity sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.corgi.wtf/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.corgi.wtf/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.corgi.wtf/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.corgi.wtf/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.corgi.wtf/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.corgi.wtf/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.corgi.wtf/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.corgi.wtf/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.corgi.wtf/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.corgi.wtf/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.corgi.wtf/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.corgi.wtf/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.corgi.wtf/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.corgi.wtf/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0: + version "3.4.0" + resolved "https://registry.corgi.wtf/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" + integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== + +eslint@^8.37.0: + version "8.38.0" + resolved "https://registry.corgi.wtf/eslint/-/eslint-8.38.0.tgz#a62c6f36e548a5574dd35728ac3c6209bd1e2f1a" + integrity sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.2" + "@eslint/js" "8.38.0" + "@humanwhocodes/config-array" "^0.11.8" + "@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-visitor-keys "^3.4.0" + espree "^9.5.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + 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" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +espree@^9.5.1: + version "9.5.1" + resolved "https://registry.corgi.wtf/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4" + integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.0" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.corgi.wtf/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.corgi.wtf/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.corgi.wtf/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.corgi.wtf/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.corgi.wtf/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.corgi.wtf/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.corgi.wtf/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.corgi.wtf/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.corgi.wtf/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.corgi.wtf/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.corgi.wtf/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.corgi.wtf/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.corgi.wtf/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.corgi.wtf/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.corgi.wtf/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.corgi.wtf/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.corgi.wtf/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.corgi.wtf/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.corgi.wtf/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.corgi.wtf/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.corgi.wtf/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.corgi.wtf/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.corgi.wtf/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.corgi.wtf/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.corgi.wtf/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.corgi.wtf/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.corgi.wtf/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.corgi.wtf/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.corgi.wtf/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.corgi.wtf/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.corgi.wtf/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.corgi.wtf/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.corgi.wtf/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.corgi.wtf/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.corgi.wtf/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.corgi.wtf/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-sdsl@^4.1.4: + version "4.4.0" + resolved "https://registry.corgi.wtf/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" + integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.corgi.wtf/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.corgi.wtf/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.corgi.wtf/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.corgi.wtf/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.corgi.wtf/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.corgi.wtf/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.corgi.wtf/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.corgi.wtf/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.corgi.wtf/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.corgi.wtf/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.corgi.wtf/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mongodb-connection-string-url@^2.6.0: + version "2.6.0" + resolved "https://registry.corgi.wtf/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz#57901bf352372abdde812c81be47b75c6b2ec5cf" + integrity sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + +mongodb@^5.2.0: + version "5.2.0" + resolved "https://registry.corgi.wtf/mongodb/-/mongodb-5.2.0.tgz#58c3688614e793a8e970d797255130db9fd6ddea" + integrity sha512-nLgo95eP1acvjBcOdrUV3aqpWwHZCZwhYA2opB8StybbtQL/WoE5pk92qUUfjbKOWcGLYJczTqQbfOQhYtrkKg== + dependencies: + bson "^5.2.0" + mongodb-connection-string-url "^2.6.0" + socks "^2.7.1" + optionalDependencies: + saslprep "^1.0.3" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.corgi.wtf/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mysql@^2.18.1: + version "2.18.1" + resolved "https://registry.corgi.wtf/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" + integrity sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig== + dependencies: + bignumber.js "9.0.0" + readable-stream "2.3.7" + safe-buffer "5.1.2" + sqlstring "2.3.1" + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.corgi.wtf/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.corgi.wtf/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.corgi.wtf/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.corgi.wtf/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + 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" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.corgi.wtf/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.corgi.wtf/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.corgi.wtf/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.corgi.wtf/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.corgi.wtf/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.corgi.wtf/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.corgi.wtf/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.corgi.wtf/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.corgi.wtf/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.corgi.wtf/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise-breaker@^6.0.0: + version "6.0.0" + resolved "https://registry.corgi.wtf/promise-breaker/-/promise-breaker-6.0.0.tgz#107d2b70f161236abdb4ac5a736c7eb8df489d0f" + integrity sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.corgi.wtf/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.corgi.wtf/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.corgi.wtf/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +"readable-stream@1.x >=1.1.9": + version "1.1.14" + resolved "https://registry.corgi.wtf/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@2.3.7: + version "2.3.7" + resolved "https://registry.corgi.wtf/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.corgi.wtf/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.corgi.wtf/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.corgi.wtf/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.corgi.wtf/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.corgi.wtf/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@~5.1.2: + version "5.1.2" + resolved "https://registry.corgi.wtf/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +saslprep@^1.0.3: + version "1.0.3" + resolved "https://registry.corgi.wtf/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +semver@^7.3.7: + version "7.4.0" + resolved "https://registry.corgi.wtf/semver/-/semver-7.4.0.tgz#8481c92feffc531ab1e012a8ffc15bdd3a0f4318" + integrity sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.corgi.wtf/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.corgi.wtf/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.corgi.wtf/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.corgi.wtf/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks@^2.7.1: + version "2.7.1" + resolved "https://registry.corgi.wtf/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.corgi.wtf/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + +sqlstring@2.3.1: + version "2.3.1" + resolved "https://registry.corgi.wtf/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" + integrity sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ== + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.corgi.wtf/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.corgi.wtf/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.corgi.wtf/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.corgi.wtf/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.corgi.wtf/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.corgi.wtf/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.corgi.wtf/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.corgi.wtf/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.corgi.wtf/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.corgi.wtf/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.corgi.wtf/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.corgi.wtf/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typescript@^5.0.3: + version "5.0.4" + resolved "https://registry.corgi.wtf/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" + integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.corgi.wtf/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-parse@~1.5.10: + version "1.5.10" + resolved "https://registry.corgi.wtf/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.corgi.wtf/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.corgi.wtf/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.corgi.wtf/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.corgi.wtf/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.corgi.wtf/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.corgi.wtf/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.corgi.wtf/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.corgi.wtf/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==