1
0
Fork 0
mirror of https://github.com/codex-team/codex.docs.git synced 2025-08-07 22:45:23 +02:00

implement mongodb driver

This commit is contained in:
Nikita Melnikov 2022-09-28 22:14:51 +08:00
parent f151fd7ca9
commit 74dd0eca7d
8 changed files with 422 additions and 185 deletions

View file

@ -35,6 +35,7 @@
"jsonwebtoken": "^8.5.1",
"mime": "^3.0.0",
"mkdirp": "^1.0.4",
"mongodb": "^4.10.0",
"morgan": "^1.10.0",
"multer": "^1.4.2",
"nedb": "^1.8.0",

View file

@ -19,6 +19,13 @@ const LocalDatabaseConfig = z.object({
})
})
const MongoDatabaseConfig = z.object({
driver: z.literal('mongodb'),
mongodb: z.object({
uri: z.string()
})
})
const AuthConfig = z.object({
secret: z.string() // Secret for JWT
})
@ -48,7 +55,7 @@ const AppConfig = z.object({
password: z.string(), // Password for admin panel
frontend: FrontendConfig, // Frontend configuration
auth: AuthConfig, // Auth configuration
database: LocalDatabaseConfig, // Database configuration
database: z.union([LocalDatabaseConfig, MongoDatabaseConfig]), // Database configuration
})
export type AppConfig = z.infer<typeof AppConfig>;

View file

@ -1,175 +1,16 @@
import Datastore from 'nedb';
import { AliasData } from '../../models/alias.js';
import { FileData } from '../../models/file.js';
import { PageData } from '../../models/page.js';
import { PageOrderData } from '../../models/pageOrder.js';
import initDb from './initDb.js';
import appConfig from "../appConfig.js";
import LocalDatabaseDriver from "./local.js";
import MongoDatabaseDriver from "./mongodb.js";
/**
* @typedef Options - optional params
* @param {boolean} multi - (false) allows to take action to several documents
* @param {boolean} upsert - (false) if true, upsert document with update fields.
* Method will return inserted doc or number of affected docs if doc hasn't been inserted
* @param {boolean} returnUpdatedDocs - (false) if true, returns affected docs
*/
interface Options {
multi?: boolean;
upsert?: boolean;
returnUpdatedDocs?: boolean;
}
interface ResolveFunction {
(value: any): void;
}
interface RejectFunction {
(reason?: unknown): void;
}
/**
* @class Database
* @classdesc Simple decorator class to work with nedb datastore
*
* @property {Datastore} db - nedb Datastore object
*/
export class Database<DocType> {
private db: Datastore;
/**
* @class
*
* @param {Object} nedbInstance - nedb Datastore object
*/
constructor(nedbInstance: Datastore) {
this.db = nedbInstance;
}
/**
* Insert new document into the database
*
* @see https://github.com/louischatriot/nedb#inserting-documents
*
* @param {Object} doc - object to insert
* @returns {Promise<Object|Error>} - inserted doc or Error object
*/
public async insert(doc: DocType): Promise<DocType> {
return new Promise((resolve, reject) => this.db.insert(doc, (err, newDoc) => {
if (err) {
reject(err);
}
resolve(newDoc);
}));
}
/**
* Find documents that match passed query
*
* @see https://github.com/louischatriot/nedb#finding-documents
*
* @param {Object} query - query object
* @param {Object} projection - projection object
* @returns {Promise<Array<Object>|Error>} - found docs or Error object
*/
public async find(query: Record<string, unknown>, projection?: DocType): Promise<Array<DocType>> {
const cbk = (resolve: ResolveFunction, reject: RejectFunction) => (err: Error | null, docs: DocType[]) => {
if (err) {
reject(err);
}
resolve(docs);
};
return new Promise((resolve, reject) => {
if (projection) {
this.db.find(query, projection, cbk(resolve, reject));
} else {
this.db.find(query, cbk(resolve, reject));
}
});
}
/**
* Find one document matches passed query
*
* @see https://github.com/louischatriot/nedb#finding-documents
*
* @param {Object} query - query object
* @param {Object} projection - projection object
* @returns {Promise<Object|Error>} - found doc or Error object
*/
public async findOne(query: Record<string, unknown>, projection?: DocType): Promise<DocType> {
const cbk = (resolve: ResolveFunction, reject: RejectFunction) => (err: Error | null, doc: DocType) => {
if (err) {
reject(err);
}
resolve(doc);
};
return new Promise((resolve, reject) => {
if (projection) {
this.db.findOne(query, projection, cbk(resolve, reject));
} else {
this.db.findOne(query, cbk(resolve, reject));
}
});
}
/**
* Update document matches query
*
* @see https://github.com/louischatriot/nedb#updating-documents
*
* @param {Object} query - query object
* @param {Object} update - fields to update
* @param {Options} options - optional params
* @returns {Promise<number|Object|Object[]|Error>} - number of updated rows or affected docs or Error object
*/
public async update(query: Record<string, unknown>, update: DocType, options: Options = {}): Promise<number|boolean|Array<DocType>> {
return new Promise((resolve, reject) => this.db.update(query, update, options, (err, result, affectedDocs) => {
if (err) {
reject(err);
}
switch (true) {
case options.returnUpdatedDocs:
resolve(affectedDocs);
break;
case options.upsert:
if (affectedDocs) {
resolve(affectedDocs);
}
resolve(result);
break;
default:
resolve(result);
}
}));
}
/**
* Remove document matches passed query
*
* @see https://github.com/louischatriot/nedb#removing-documents
*
* @param {Object} query - query object
* @param {Options} options - optional params
* @returns {Promise<number|Error>} - number of removed rows or Error object
*/
public async remove(query: Record<string, unknown>, options: Options = {}): Promise<number> {
return new Promise((resolve, reject) => this.db.remove(query, options, (err, result) => {
if (err) {
reject(err);
}
resolve(result);
}));
}
}
const Database = appConfig.database.driver === 'mongodb' ? MongoDatabaseDriver : LocalDatabaseDriver;
export default {
pages: new Database<PageData>(initDb('pages')),
aliases: new Database<AliasData>(initDb('aliases')),
pagesOrder: new Database<PageOrderData>(initDb('pagesOrder')),
files: new Database<FileData>(initDb('files')),
pages: new Database<PageData>('pages'),
aliases: new Database<AliasData>('aliases'),
pagesOrder: new Database<PageOrderData>('pagesOrder'),
files: new Database<FileData>('files'),
};

View file

@ -1,16 +0,0 @@
import Datastore from 'nedb';
import path from 'path';
import appConfig from "../appConfig.js";
/**
* Init function for nedb instance
*
* @param {string} name - name of the data file
* @returns {Datastore} db - nedb instance
*/
export default function initDb(name: string): Datastore {
return new Datastore({
filename: path.resolve(`${appConfig.database.local.path}/${name}.db`),
autoload: true,
});
}

View file

@ -0,0 +1,162 @@
import Datastore from "nedb";
import {DatabaseDriver, Options, RejectFunction, ResolveFunction} from "./types.js";
import path from "path";
import appConfig from "../appConfig.js";
/**
* Init function for nedb instance
*
* @param {string} name - name of the data file
* @returns {Datastore} db - nedb instance
*/
function initDb(name: string): Datastore {
const dbConfig = appConfig.database.driver === 'local' ? appConfig.database.local : null;
if (!dbConfig) {
throw new Error('Database config is not initialized');
}
return new Datastore({
filename: path.resolve(`${dbConfig.path}/${name}.db`),
autoload: true,
});
}
/**
* Simple decorator class to work with nedb datastore
*/
export default class LocalDatabaseDriver<DocType> implements DatabaseDriver<DocType> {
/**
* nedb Datastore object
*/
private db: Datastore;
/**
* @param collectionName - collection name for storing data
*/
constructor(collectionName: string) {
this.db = initDb(collectionName);
}
/**
* Insert new document into the database
*
* @see https://github.com/louischatriot/nedb#inserting-documents
*
* @param {Object} doc - object to insert
* @returns {Promise<Object|Error>} - inserted doc or Error object
*/
public async insert(doc: DocType): Promise<DocType> {
return new Promise((resolve, reject) => this.db.insert(doc, (err, newDoc) => {
if (err) {
reject(err);
}
resolve(newDoc);
}));
}
/**
* Find documents that match passed query
*
* @see https://github.com/louischatriot/nedb#finding-documents
*
* @param {Object} query - query object
* @param {Object} projection - projection object
* @returns {Promise<Array<Object>|Error>} - found docs or Error object
*/
public async find(query: Record<string, unknown>, projection?: DocType): Promise<Array<DocType>> {
const cbk = (resolve: ResolveFunction, reject: RejectFunction) => (err: Error | null, docs: DocType[]) => {
if (err) {
reject(err);
}
resolve(docs);
};
return new Promise((resolve, reject) => {
if (projection) {
this.db.find(query, projection, cbk(resolve, reject));
} else {
this.db.find(query, cbk(resolve, reject));
}
});
}
/**
* Find one document matches passed query
*
* @see https://github.com/louischatriot/nedb#finding-documents
*
* @param {Object} query - query object
* @param {Object} projection - projection object
* @returns {Promise<Object|Error>} - found doc or Error object
*/
public async findOne(query: Record<string, unknown>, projection?: DocType): Promise<DocType> {
const cbk = (resolve: ResolveFunction, reject: RejectFunction) => (err: Error | null, doc: DocType) => {
if (err) {
reject(err);
}
resolve(doc);
};
return new Promise((resolve, reject) => {
if (projection) {
this.db.findOne(query, projection, cbk(resolve, reject));
} else {
this.db.findOne(query, cbk(resolve, reject));
}
});
}
/**
* Update document matches query
*
* @see https://github.com/louischatriot/nedb#updating-documents
*
* @param {Object} query - query object
* @param {Object} update - fields to update
* @param {Options} options - optional params
* @returns {Promise<number|Object|Object[]|Error>} - number of updated rows or affected docs or Error object
*/
public async update(query: Record<string, unknown>, update: DocType, options: Options = {}): Promise<number|boolean|Array<DocType>> {
return new Promise((resolve, reject) => this.db.update(query, update, options, (err, result, affectedDocs) => {
if (err) {
reject(err);
}
switch (true) {
case options.returnUpdatedDocs:
resolve(affectedDocs);
break;
case options.upsert:
if (affectedDocs) {
resolve(affectedDocs);
}
resolve(result);
break;
default:
resolve(result);
}
}));
}
/**
* Remove document matches passed query
*
* @see https://github.com/louischatriot/nedb#removing-documents
*
* @param {Object} query - query object
* @param {Options} options - optional params
* @returns {Promise<number|Error>} - number of removed rows or Error object
*/
public async remove(query: Record<string, unknown>, options: Options = {}): Promise<number> {
return new Promise((resolve, reject) => this.db.remove(query, options, (err, result) => {
if (err) {
reject(err);
}
resolve(result);
}));
}
}

View file

@ -0,0 +1,112 @@
import {Collection, Filter, MongoClient, OptionalUnlessRequiredId, UpdateFilter} from 'mongodb';
import {DatabaseDriver, Options} from "./types.js";
import appConfig from "../appConfig.js";
const mongodbUri = appConfig.database.driver === 'mongodb' ? appConfig.database.mongodb.uri : null;
const mongodbClient = mongodbUri ? await MongoClient.connect(mongodbUri): null;
/**
* Simple decorator class to work with nedb datastore
*/
export default class MongoDatabaseDriver<DocType> implements DatabaseDriver<DocType> {
/**
* Mongo client instance
*/
private db: MongoClient;
private collection: Collection<DocType>;
constructor(collectionName: string) {
if (!mongodbClient) {
throw new Error('MongoDB client is not initialized');
}
this.db = mongodbClient;
this.collection = mongodbClient.db().collection(collectionName);
}
/**
* Insert new document into the database
*
* @param {Object} doc - object to insert
* @returns {Promise<Object|Error>} - inserted doc or Error object
*/
public async insert(doc: DocType): Promise<DocType> {
const result = await this.collection.insertOne(doc as OptionalUnlessRequiredId<DocType>);
return {
...doc,
_id: result.insertedId,
}
}
/**
* Find documents that match passed query
*
* @param {Object} query - query object
* @param {Object} projection - projection object
* @returns {Promise<Array<Object>|Error>} - found docs or Error object
*/
public async find(query: Record<string, unknown>, projection?: DocType): Promise<Array<DocType>> {
const cursor = this.collection.find(query as Filter<DocType>)
if (projection) {
cursor.project(projection);
}
const docs = await cursor.toArray();
return docs as unknown as Array<DocType>;
}
/**
* Find one document matches passed query
*
* @param {Object} query - query object
* @param {Object} projection - projection object
* @returns {Promise<Object|Error>} - found doc or Error object
*/
public async findOne(query: Record<string, unknown>, projection?: DocType): Promise<DocType> {
const doc = await this.collection.findOne(query as Filter<DocType>, {projection});
if (!doc) {
throw new Error('Document not found');
}
return doc as unknown as DocType;
}
/**
* Update document matches query
*
* @param {Object} query - query object
* @param {Object} update - fields to update
* @param {Options} options - optional params
* @returns {Promise<number|Object|Object[]|Error>} - number of updated rows or affected docs or Error object
*/
public async update(query: Record<string, unknown>, update: DocType, options: Options = {}): Promise<number|boolean|Array<DocType>> {
const updateDocument = {
$set: update
} as UpdateFilter<DocType>;
const result = await this.collection.updateMany(query as Filter<DocType>, updateDocument, options);
switch (true) {
case options.returnUpdatedDocs:
return result.modifiedCount
case options.upsert:
if (result.modifiedCount) {
return result.modifiedCount;
}
return result as DocType[]
default:
return result as DocType[]
}
}
/**
* Remove document matches passed query
*
* @param {Object} query - query object
* @param {Options} options - optional params
* @returns {Promise<number|Error>} - number of removed rows or Error object
*/
public async remove(query: Record<string, unknown>, options: Options = {}): Promise<number> {
const result = await this.collection.deleteMany(query as Filter<DocType>);
return result.deletedCount;
}
}

View file

@ -0,0 +1,28 @@
export interface DatabaseDriver<DocType> {
insert(doc: DocType): Promise<DocType>;
find(query: Record<string, unknown>, projection?: DocType): Promise<Array<DocType>>;
findOne(query: Record<string, unknown>, projection?: DocType): Promise<DocType>;
update(query: Record<string, unknown>, update: DocType, options: Options): Promise<number|boolean|Array<DocType>>
remove(query: Record<string, unknown>, options: Options): Promise<number>
}
/**
* @typedef Options - optional params
* @param {boolean} multi - (false) allows to take action to several documents
* @param {boolean} upsert - (false) if true, upsert document with update fields.
* Method will return inserted doc or number of affected docs if doc hasn't been inserted
* @param {boolean} returnUpdatedDocs - (false) if true, returns affected docs
*/
export interface Options {
multi?: boolean;
upsert?: boolean;
returnUpdatedDocs?: boolean;
}
export interface ResolveFunction {
(value: any): void;
}
export interface RejectFunction {
(reason?: unknown): void;
}

104
yarn.lock
View file

@ -1341,6 +1341,19 @@
version "1.12.9"
resolved "https://registry.yarnpkg.com/@types/twig/-/twig-1.12.9.tgz#76502345e4c85c303541dd6d700c3b86c4fed837"
"@types/webidl-conversions@*":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@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.yarnpkg.com/@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@^4.6.1":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276"
@ -1882,6 +1895,13 @@ bson@*:
dependencies:
buffer "^5.6.0"
bson@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/bson/-/bson-4.7.0.tgz#7874a60091ffc7a45c5dd2973b5cad7cded9718a"
integrity sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==
dependencies:
buffer "^5.6.0"
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
@ -2512,6 +2532,11 @@ delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
denque@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
depd@2.0.0, depd@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
@ -3564,6 +3589,11 @@ ip-regex@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@ -4116,6 +4146,11 @@ mem@^4.0.0:
mimic-fn "^2.0.0"
p-is-promise "^2.0.0"
memory-pager@^1.0.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
@ -4248,6 +4283,26 @@ module-dispatcher@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/module-dispatcher/-/module-dispatcher-2.0.0.tgz#67701ff90cca9b51d500be4782abb1014ccb2b10"
mongodb-connection-string-url@^2.5.3:
version "2.5.3"
resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz#c0c572b71570e58be2bd52b33dffd1330cfb6990"
integrity sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ==
dependencies:
"@types/whatwg-url" "^8.2.1"
whatwg-url "^11.0.0"
mongodb@^4.10.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.10.0.tgz#49fc509c928ff126577d628ab09aaf1e5855cd22"
integrity sha512-My2QxLTw0Cc1O9gih0mz4mqo145Jq4rLAQx0Glk/Ha9iYBzYpt4I2QFNRIh35uNFNfe8KFQcdwY1/HKxXBkinw==
dependencies:
bson "^4.7.0"
denque "^2.1.0"
mongodb-connection-string-url "^2.5.3"
socks "^2.7.0"
optionalDependencies:
saslprep "^1.0.3"
morgan@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7"
@ -5116,7 +5171,7 @@ pump@^3.0.0:
end-of-stream "^1.1.0"
once "^1.3.1"
punycode@^2.1.0:
punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@ -5414,6 +5469,13 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
saslprep@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226"
integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==
dependencies:
sparse-bitfield "^3.0.3"
schema-utils@^2.6.5:
version "2.7.1"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
@ -5567,6 +5629,19 @@ slice-ansi@^4.0.0:
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
socks@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.0.tgz#f9225acdb841e874dca25f870e9130990f3913d0"
integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==
dependencies:
ip "^2.0.0"
smart-buffer "^4.2.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
@ -5582,6 +5657,13 @@ source-map@^0.6.0, source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
sparse-bitfield@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==
dependencies:
memory-pager "^1.0.2"
spawn-command@^0.0.2-1:
version "0.0.2-1"
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0"
@ -5899,6 +5981,13 @@ token-types@^5.0.1:
"@tokenizer/token" "^0.3.0"
ieee754 "^1.2.1"
tr46@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9"
integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==
dependencies:
punycode "^2.1.1"
tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
@ -6126,6 +6215,11 @@ web-streams-polyfill@^3.0.3:
version "3.2.1"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
webidl-conversions@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"
integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
webpack-cli@^4.9.2:
version "4.10.0"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31"
@ -6183,6 +6277,14 @@ webpack@^5.70.0:
watchpack "^2.4.0"
webpack-sources "^3.2.3"
whatwg-url@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/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-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"