mirror of
https://github.com/chenasraf/venom.git
synced 2026-05-17 17:28:08 +00:00
feat(db): add mongodb connection
additionally implements command to add greetings for test
This commit is contained in:
@@ -17,6 +17,8 @@ At a minimum you need to provide the Discord bots Token, which can be found on t
|
||||
| DISCORD_BOT_TOKEN | Discord bots Token
|
||||
| NODE_ENV | What environment the bot is running in | `production`, `development` or `test` |
|
||||
| LOG_LEVEL | What level of logs should be displayed in console | `error`, `warn`, `info`, `verbose`, `debug` or `silly` |
|
||||
| MONGODB_URI | Full connection string for MongoDB database, include db_name if user is scoped to single database | mongodb://user:password@localhost:27017/venom_db |
|
||||
| MONGODB_DB_NAME | The name of the database to use for this project | venom_db |
|
||||
|
||||
### Bot commands
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
"discord.js": "~12.2.0",
|
||||
"dotenv": "~8.2.0",
|
||||
"inversify": "~5.0.1",
|
||||
"mongodb": "~3.6.0",
|
||||
"reflect-metadata": "~0.1.13",
|
||||
"winston": "~3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dotenv": "~8.2.0",
|
||||
"@types/mongodb": "~3.5.25",
|
||||
"@types/node": "~14.0.27",
|
||||
"@types/winston": "~2.4.4",
|
||||
"nodemon": "~2.0.4",
|
||||
@@ -35,4 +37,4 @@
|
||||
"tslint-react": "~5.0.0",
|
||||
"typescript": "~3.9.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
BOT_TRIGGER=!
|
||||
DISCORD_BOT_TOKEN=[replace with own token]
|
||||
MONGODB_URI=[mongo_connection_string]
|
||||
MONGODB_DB_NAME=[mongo_db_name]
|
||||
NODE_ENV=production
|
||||
LOG_LEVEL=error
|
||||
23
src/app.ts
23
src/app.ts
@@ -5,6 +5,7 @@ import container from './inversity.config';
|
||||
|
||||
import ConfigService from './core/services/config.service';
|
||||
import LoggerService from './core/services/logger.service';
|
||||
import MongoService from './core/services/mongo.service';
|
||||
|
||||
import ICommand from './bot/commands/ICommand';
|
||||
import rawCommands from './bot/commands';
|
||||
@@ -12,10 +13,18 @@ import rawCommands from './bot/commands';
|
||||
export default class App {
|
||||
private _configService: ConfigService = container.resolve<ConfigService>(ConfigService);
|
||||
private _loggerService: LoggerService = container.resolve<LoggerService>(LoggerService);
|
||||
private _dbService: MongoService = container.resolve<MongoService>(MongoService);
|
||||
|
||||
private _discordClient: Discord.Client;
|
||||
|
||||
public async init(): Promise<void> {
|
||||
try {
|
||||
await this._dbService.connect();
|
||||
} catch (err) {
|
||||
this._loggerService.log('error', 'Cannot connect to database, exiting.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
this._discordClient = new Discord.Client();
|
||||
const commandList = new Discord.Collection<string, ICommand>();
|
||||
|
||||
@@ -44,7 +53,7 @@ export default class App {
|
||||
};
|
||||
|
||||
try {
|
||||
await command.execute(message, args, prefix, commandList);
|
||||
await command.execute(message, args, prefix, commandList, this._dbService);
|
||||
} catch (error) {
|
||||
this._loggerService.log('error', error.message);
|
||||
message.reply('there was an error trying to follow that command!');
|
||||
@@ -57,11 +66,11 @@ export default class App {
|
||||
const greeting = greetings[Math.floor(Math.random() * greetings.length - 1)];
|
||||
// favor
|
||||
const flavors = [
|
||||
"As PROMISED, grab a free pie! Courtesy of {random}!",
|
||||
"The water is pure here! You should ask {random} for their water purified water for a sip!",
|
||||
"Home of the sane, the smart and {random}!"
|
||||
"As PROMISED, grab a free pie! Courtesy of {random}!",
|
||||
"The water is pure here! You should ask {random} for their water purified water for a sip!",
|
||||
"Home of the sane, the smart and {random}!"
|
||||
];
|
||||
const randomMember = member.guild.members.cache.random();
|
||||
const randomMember = member.guild.members.cache.random();
|
||||
const flavor = flavors[Math.floor(Math.random() * flavors.length - 1)];
|
||||
// result
|
||||
member.guild.systemChannel.send(greeting.replace('{name}', member.displayName) + " " + flavor.replace('{random}', randomMember.displayName));
|
||||
@@ -73,4 +82,8 @@ export default class App {
|
||||
exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
public exit() {
|
||||
this._dbService.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import Discord, { Collection } from 'discord.js';
|
||||
import MongoService from 'src/core/services/mongo.service';
|
||||
|
||||
export default interface ICommand {
|
||||
name: string;
|
||||
aliases?: string[];
|
||||
description: string;
|
||||
example?: string;
|
||||
execute: (message: Discord.Message, args: string[], prefix?: string, commands?: Collection<string, ICommand>) => Promise<void>,
|
||||
execute: (message: Discord.Message, args: string[], prefix?: string, commands?: Collection<string, ICommand>, dbService?: MongoService) => Promise<any>,
|
||||
}
|
||||
49
src/bot/commands/addgreeting.ts
Normal file
49
src/bot/commands/addgreeting.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import Discord, { Collection } from 'discord.js';
|
||||
|
||||
import MongoService from '../../core/services/mongo.service';
|
||||
import ConfigService from '../../core/services/config.service'
|
||||
|
||||
import container from '../../inversity.config';
|
||||
|
||||
import ICommand from './ICommand';
|
||||
|
||||
const prefix = container.resolve<ConfigService>(ConfigService).get('BOT_TRIGGER');
|
||||
|
||||
const command: ICommand = {
|
||||
name: 'addgreeting',
|
||||
aliases: ['ag'],
|
||||
description: 'Adds a string to the list greetings used when new users connect to server! Include `{name}` in your message to replace with the new users name.',
|
||||
example: `\`${prefix}addgreeting Welcome to the club {name}\``,
|
||||
async execute(message: Discord.Message, args: string[], prefix?: string, commands?: Collection<string, ICommand>, dbService?: MongoService) {
|
||||
// Only certain users can use this command
|
||||
// TODO: Better handling of permissions for commands in a generic way
|
||||
const permittedRoles = ['staff']
|
||||
const isPermitted = message.member.roles.cache.some(r => permittedRoles.indexOf(r.name) !== -1);
|
||||
|
||||
if (!isPermitted) {
|
||||
return message.author.send('Sorry but I can\'t let you add greetings!');
|
||||
}
|
||||
|
||||
// Can't do much without a message
|
||||
if (args.length === 0) {
|
||||
return message.author.send('When adding a greeting you need to also provide a message!');
|
||||
}
|
||||
|
||||
// Check for dupes
|
||||
const greetingStr = args.join(' ');
|
||||
const matchedMessages = await dbService.find(message.author.id, 'greetings', { message: greetingStr });
|
||||
if (matchedMessages.length > 0) {
|
||||
return message.author.send('That greeting has already been added!');
|
||||
}
|
||||
|
||||
const result = await dbService.insert(message.author.id, 'greetings', [{ message: greetingStr }]);
|
||||
|
||||
if (!result) {
|
||||
message.author.send('Uh-oh! Couldn\'t add that greeting!');
|
||||
}
|
||||
|
||||
message.author.send('I\'ve added the greeting you told me about!');
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
||||
@@ -2,10 +2,12 @@ import help from './help';
|
||||
import ping from './ping';
|
||||
import see from './see';
|
||||
import magicball from './8ball';
|
||||
import addgreeting from './addgreeting'
|
||||
|
||||
export default [
|
||||
help,
|
||||
ping,
|
||||
see,
|
||||
magicball
|
||||
magicball,
|
||||
addgreeting
|
||||
]
|
||||
@@ -33,6 +33,8 @@ export default class ConfigService {
|
||||
this.config = {
|
||||
BOT_TRIGGER: process.env.BOT_TRIGGER || '!',
|
||||
DISCORD_BOT_TOKEN: process.env.DISCORD_BOT_TOKEN,
|
||||
MONGODB_URI: process.env.MONGODB_URI || '',
|
||||
MONGODB_DB_NAME: process.env.MONGODB_DB_NAME || '',
|
||||
ENVIRONMENT: (process.env.NODE_ENV as Environment) || 'development',
|
||||
LOG_LEVEL: (process.env.LOG_LEVEL as LogLevel) || 'info',
|
||||
};
|
||||
|
||||
243
src/core/services/mongo.service.ts
Normal file
243
src/core/services/mongo.service.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
import mongodb from 'mongodb';
|
||||
import { injectable } from "inversify";
|
||||
import assert from 'assert';
|
||||
|
||||
import container from '../../inversity.config';
|
||||
|
||||
import ConfigService from './config.service';
|
||||
import LoggerService from './logger.service';
|
||||
|
||||
@injectable()
|
||||
export default class MongoService {
|
||||
private _configService: ConfigService = container.resolve<ConfigService>(ConfigService);
|
||||
private _loggerService: LoggerService = container.resolve<LoggerService>(LoggerService);
|
||||
|
||||
private _mongoClient: mongodb.MongoClient;
|
||||
public _db: mongodb.Db;
|
||||
|
||||
public async connect(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._mongoClient = new mongodb.MongoClient(this._configService.get('MONGODB_URI'), { useUnifiedTopology: true });
|
||||
|
||||
this._mongoClient.connect((err) => {
|
||||
if (err) {
|
||||
this._loggerService.log('error', 'Venom could not connect to MongoDB', err);
|
||||
reject();
|
||||
} else {
|
||||
this._loggerService.log('info', 'Venom is connected to MongoDB');
|
||||
|
||||
this._db = this._mongoClient.db(this._configService.get('MONGODB_DB_NAME'));
|
||||
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public disconnect() {
|
||||
if (this._mongoClient && this._mongoClient.isConnected) {
|
||||
this._loggerService.log('info', 'Closing connection to MongoDB');
|
||||
this._mongoClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the first document that matches the query
|
||||
*
|
||||
* @param collection String identifier for collection document belongs to
|
||||
* @param query key/value pairs of search conditions
|
||||
*
|
||||
* @returns Returns matched document
|
||||
*
|
||||
* @example findOne('123456', 'collectionName', { ident: 'generated-slug' })
|
||||
*/
|
||||
public async findOne(userId: string, collection: string, query: any) {
|
||||
try {
|
||||
this.verifyConnection();
|
||||
|
||||
const resp = await this._db.collection(collection).findOne(query);
|
||||
|
||||
this._loggerService.log('verbose', 'Fetched single document from MongoDB', {
|
||||
userId,
|
||||
collection,
|
||||
query,
|
||||
resp,
|
||||
});
|
||||
|
||||
return resp;
|
||||
} catch (err) {
|
||||
this._loggerService.log('error', 'Could not find document', {
|
||||
userId,
|
||||
error: err,
|
||||
collection,
|
||||
query,
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all documents that match the query
|
||||
*
|
||||
* @param collection String identifier for collection documents belong to
|
||||
* @param query key/value pairs of search conditions
|
||||
*
|
||||
* @returns Returns matched document
|
||||
*
|
||||
* @example find('123456', 'collectionName', { key: 'value' })
|
||||
*/
|
||||
public async find(userId: string, collection: string, query: any) {
|
||||
try {
|
||||
this.verifyConnection();
|
||||
|
||||
const resp = await this._db.collection(collection).find(query).toArray();
|
||||
|
||||
this._loggerService.log('verbose', 'Fetched documents matching query from MongoDB', {
|
||||
userId,
|
||||
collection,
|
||||
query,
|
||||
resp,
|
||||
});
|
||||
|
||||
return resp;
|
||||
} catch (err) {
|
||||
this._loggerService.log('error', 'Could not find documents', {
|
||||
userId,
|
||||
error: err,
|
||||
collection,
|
||||
query,
|
||||
});
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one or more documents to given collection
|
||||
*
|
||||
* @param collection String identifier for collection document is to be stored again
|
||||
* @param payload Array of objects containing the key/value pairs to be stored
|
||||
*
|
||||
* @returns Returns true for successful insert
|
||||
*
|
||||
* @example `insert('123456', 'collectionName', [{ body: 'This is a document!' }])`
|
||||
*/
|
||||
public async insert(userId: string, collection: string, payload: any[]) {
|
||||
try {
|
||||
this.verifyConnection();
|
||||
|
||||
const resp = await this._db.collection(collection).insert(payload);
|
||||
|
||||
if (resp.result.ok !== 1 || resp.insertedCount !== payload.length) {
|
||||
throw new Error(JSON.stringify(resp));
|
||||
}
|
||||
|
||||
this._loggerService.log('verbose', `Inserted ${resp.insertedCount} documents into ${collection}`, {
|
||||
userId,
|
||||
collection,
|
||||
payload,
|
||||
resp
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
this._loggerService.log('error', 'Could not insert documents to database', {
|
||||
userId,
|
||||
error: err,
|
||||
collection,
|
||||
payload
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update single document from MongoDB
|
||||
*
|
||||
* @param collection String identifier for collection documents belong to
|
||||
* @param query key/value pairs of search conditions
|
||||
* @param payload Objects containing the key/value pairs to be stored against existing documents
|
||||
*
|
||||
* @returns Returns true for successful update
|
||||
*
|
||||
* @example `updateMany('123456', 'collectionName', { ident: 'generated-slug' }, { secondKey: 'new data'})`
|
||||
*/
|
||||
public async updateMany(userId: string, collection: string, query: any, payload: any) {
|
||||
try {
|
||||
this.verifyConnection();
|
||||
|
||||
const resp = await this._db.collection(collection).updateMany(query, { $set: payload });
|
||||
|
||||
if (resp.result.ok !== 1) {
|
||||
throw new Error(JSON.stringify(resp));
|
||||
}
|
||||
|
||||
this._loggerService.log('verbose', `Updated documents into ${collection} with id ${resp.upsertedId}`, {
|
||||
userId,
|
||||
collection,
|
||||
query,
|
||||
payload,
|
||||
resp
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
this._loggerService.log('error', 'Could not update documents', {
|
||||
userId,
|
||||
collection,
|
||||
query,
|
||||
payload,
|
||||
err
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove documents from MongoDB matching query
|
||||
*
|
||||
* @param collection String identifier for collection documents belong to
|
||||
* @param query key/value pairs of search conditions
|
||||
*
|
||||
* @returns Returns true for successful delete
|
||||
*
|
||||
* @example `deleteMany('123456', 'collectionName', { ident: 'generated-slug' })`
|
||||
*/
|
||||
public async deleteMany(userId: string, collection: string, query: any) {
|
||||
try {
|
||||
this.verifyConnection();
|
||||
|
||||
const resp = await this._db.collection(collection).deleteMany(query);
|
||||
|
||||
if (resp.result.ok !== 1) {
|
||||
throw new Error(JSON.stringify(resp));
|
||||
}
|
||||
|
||||
this._loggerService.log('verbose', `Deleted documents from ${collection}`, {
|
||||
userId,
|
||||
collection,
|
||||
query,
|
||||
resp
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
this._loggerService.log('error', 'Could not delete documents', {
|
||||
userId,
|
||||
collection,
|
||||
query,
|
||||
err
|
||||
});
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private verifyConnection() {
|
||||
if (!this._mongoClient.isConnected) {
|
||||
this._loggerService.log('error', 'No database connection available');
|
||||
throw new Error('No database connection available');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import Environment from "./Environment";
|
||||
export default interface Config {
|
||||
BOT_TRIGGER: string;
|
||||
DISCORD_BOT_TOKEN: string;
|
||||
MONGODB_URI: string;
|
||||
MONGODB_DB_NAME: string;
|
||||
ENVIRONMENT: Environment;
|
||||
LOG_LEVEL: LogLevel;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ import { Container } from "inversify";
|
||||
|
||||
import ConfigService from "./core/services/config.service";
|
||||
import LoggerService from "./core/services/logger.service";
|
||||
import MongoService from "./core/services/mongo.service";
|
||||
|
||||
const container = new Container();
|
||||
container.bind<ConfigService>(ConfigService).toSelf();
|
||||
container.bind<LoggerService>(LoggerService).toSelf();
|
||||
container.bind<MongoService>(MongoService).toSelf();
|
||||
|
||||
export default container;
|
||||
19
src/main.ts
19
src/main.ts
@@ -7,6 +7,25 @@ const app = new App();
|
||||
|
||||
try {
|
||||
app.init();
|
||||
|
||||
function exitHandler() {
|
||||
// Cleans up the application
|
||||
app.exit();
|
||||
exit();
|
||||
}
|
||||
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler);
|
||||
|
||||
//catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler);
|
||||
|
||||
// catches "kill pid" (for example: nodemon restart)
|
||||
process.on('SIGUSR1', exitHandler);
|
||||
process.on('SIGUSR2', exitHandler);
|
||||
|
||||
//catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler);
|
||||
} catch (e) {
|
||||
exit(1);
|
||||
}
|
||||
92
yarn.lock
92
yarn.lock
@@ -58,6 +58,13 @@
|
||||
dependencies:
|
||||
defer-to-connect "^1.0.1"
|
||||
|
||||
"@types/bson@*":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.2.tgz#7accb85942fc39bbdb7515d4de437c04f698115f"
|
||||
integrity sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/color-name@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
||||
@@ -75,7 +82,15 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||
|
||||
"@types/node@~14.0.27":
|
||||
"@types/mongodb@~3.5.25":
|
||||
version "3.5.25"
|
||||
resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.5.25.tgz#ab187db04d79f8e3f15af236327dc9139d9d4736"
|
||||
integrity sha512-2H/Owt+pHCl9YmBOYnXc3VdnxejJEjVdH+QCWL5ZAfPehEn3evygKBX3/vKRv7aTwfNbUd0E5vjJdQklH/9a6w==
|
||||
dependencies:
|
||||
"@types/bson" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@~14.0.27":
|
||||
version "14.0.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1"
|
||||
integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==
|
||||
@@ -171,6 +186,14 @@ binary-extensions@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
|
||||
integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
|
||||
|
||||
bl@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
|
||||
integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
|
||||
dependencies:
|
||||
readable-stream "^2.3.5"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
boxen@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
|
||||
@@ -200,6 +223,11 @@ braces@~3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
bson@^1.1.4:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.5.tgz#2aaae98fcdf6750c0848b0cba1ddec3c73060a34"
|
||||
integrity sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
@@ -405,6 +433,11 @@ delayed-stream@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
denque@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
|
||||
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
@@ -801,6 +834,11 @@ make-error@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
|
||||
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==
|
||||
|
||||
mime-db@1.44.0:
|
||||
version "1.44.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
|
||||
@@ -837,6 +875,19 @@ mkdirp@^0.5.3:
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
mongodb@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.0.tgz#babd7172ec717e2ed3f85e079b3f1aa29dce4724"
|
||||
integrity sha512-/XWWub1mHZVoqEsUppE0GV7u9kanLvHxho6EvBxQbShXTKYF9trhZC2NzbulRGeG7xMJHD8IOWRcdKx5LPjAjQ==
|
||||
dependencies:
|
||||
bl "^2.2.0"
|
||||
bson "^1.1.4"
|
||||
denque "^1.4.1"
|
||||
require_optional "^1.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
optionalDependencies:
|
||||
saslprep "^1.0.0"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@@ -979,7 +1030,7 @@ rc@^1.2.8:
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
readable-stream@^2.3.7:
|
||||
readable-stream@^2.3.5, readable-stream@^2.3.7:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
@@ -1027,6 +1078,19 @@ registry-url@^5.0.0:
|
||||
dependencies:
|
||||
rc "^1.2.8"
|
||||
|
||||
require_optional@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
|
||||
integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==
|
||||
dependencies:
|
||||
resolve-from "^2.0.0"
|
||||
semver "^5.1.0"
|
||||
|
||||
resolve-from@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
|
||||
integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
|
||||
|
||||
resolve@^1.3.2:
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
|
||||
@@ -1041,15 +1105,22 @@ responselike@^1.0.2:
|
||||
dependencies:
|
||||
lowercase-keys "^1.0.0"
|
||||
|
||||
safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
saslprep@^1.0.0:
|
||||
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"
|
||||
|
||||
semver-diff@^3.1.1:
|
||||
version "3.1.1"
|
||||
@@ -1058,7 +1129,7 @@ semver-diff@^3.1.1:
|
||||
dependencies:
|
||||
semver "^6.3.0"
|
||||
|
||||
semver@^5.3.0, semver@^5.7.1:
|
||||
semver@^5.1.0, semver@^5.3.0, semver@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
@@ -1098,6 +1169,13 @@ source-map@^0.6.0:
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
sparse-bitfield@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
|
||||
integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE=
|
||||
dependencies:
|
||||
memory-pager "^1.0.2"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
|
||||
Reference in New Issue
Block a user