Simp-O-Matic

Dumb Discord bot in TS.
git clone git://git.knutsen.co/Simp-O-Matic
Log | Files | Refs | README | LICENSE

commit 3c2acdaa01a935b244f66c7fd81a6cb736ba6333
parent 8bc6825b0d808bc86675ed826a49f959cdcadf62
Author: Demonstrandum <moi@knutsen.co>
Date:   Sun, 22 Mar 2020 21:16:34 +0000

Types for everything, multiple guilds, and version update.

Diffstat:
Mlib/commands/crabbing.ts | 4++--
Mlib/commands/help.ts | 2+-
Mlib/commands/kiss.ts | 4++--
Mlib/commands/pat.ts | 10+++++-----
Mlib/commands/ship.ts | 8++++----
Mlib/default.ts | 12+++++-------
Mlib/extensions.ts | 53+++++++++++++++++++++++++++++++++++++++++++++++++++--
Mlib/format_oed.ts | 4++--
Mlib/main.ts | 69+++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mlib/utils.ts | 13++++++++-----
Mpackage.json | 4++--
Myarn.lock | 70+++++++++++++++++++++++++++++++++++++++-------------------------------
12 files changed, 168 insertions(+), 85 deletions(-)

diff --git a/lib/commands/crabbing.ts b/lib/commands/crabbing.ts @@ -1,8 +1,8 @@ -import { Attachment } from 'discord.js'; +import { MessageAttachment } from 'discord.js'; export default (home_scope: HomeScope) => { const { message } = home_scope; - const attached = new Attachment( + const attached = new MessageAttachment( './lib/resources/crabbing.jpg', 'crabbing.jpg'); message.channel.send('Danny, having a jolly time.', attached); diff --git a/lib/commands/help.ts b/lib/commands/help.ts @@ -23,7 +23,7 @@ export default (home_scope: HomeScope) => { let command : string = args[0].trim(); if (command.head() === CONFIG.commands.prefix) command = command.tail(); - command = expand_alias(command, args).toLowerCase(); + command = expand_alias(command, args, message).toLowerCase(); const help_index = KNOWN_COMMANDS.indexOf(command); diff --git a/lib/commands/kiss.ts b/lib/commands/kiss.ts @@ -1,5 +1,5 @@ import { FORMATS } from '.././extensions'; -import { RichEmbed, Message } from 'discord.js'; +import { MessageEmbed, Message } from 'discord.js'; export default (home_scope: HomeScope) => { const { message, args } @@ -24,7 +24,7 @@ export default (home_scope: HomeScope) => { "https://i.imgur.com/8fcnQFS.gif", ]; - const embed = new RichEmbed() + const embed = new MessageEmbed() .setColor('#ba3d8a') .setTitle("Uh-oh... You're getting a kiss!") .setDescription(`${to.format(FORMATS.bold)}, you got a kissu from \ diff --git a/lib/commands/pat.ts b/lib/commands/pat.ts @@ -1,4 +1,4 @@ -import { Message, Attachment, RichEmbed } from 'discord.js'; +import { Message, MessageAttachment, MessageEmbed } from 'discord.js'; import { FORMATS } from '../extensions'; import Jimp from 'jimp'; @@ -43,17 +43,17 @@ export default (home_scope: HomeScope) => { return; } - const attachment = new Attachment(buffer, filename); - const embed = new RichEmbed() + const attachment = new MessageAttachment(buffer, filename); + const embed = new MessageEmbed() .setColor('#b943e8') .setTitle("Incoming pat") .setDescription(description) - .attachFile(attachment) + .attachFiles([attachment]) .setImage(`attachment://${filename}`); message.channel.send(embed); }); }; - pat(message.mentions.users.first().avatarURL); + pat(message.mentions.users.first().avatarURL()); }; diff --git a/lib/commands/ship.ts b/lib/commands/ship.ts @@ -1,7 +1,7 @@ import { createHash } from 'crypto'; import { FORMATS } from '../extensions'; -import { Message, Attachment, RichEmbed } from 'discord.js'; +import { Message, MessageAttachment, MessageEmbed } from 'discord.js'; import Jimp from 'jimp'; @@ -110,14 +110,14 @@ export default (home_scope : HomeScope) => { if (e && e.message) return error_msg(e); - const attachment = new Attachment(buffer, filename); - const embed = new RichEmbed() + const attachment = new MessageAttachment(buffer, filename); + const embed = new MessageEmbed() .setColor('#b943e8') .setTitle(`Love grade between \ ${users[0].username} & \ ${users[1].username}`.squeeze()) .setDescription(response) - .attachFile(attachment) + .attachFiles([attachment]) .setImage(`attachment://${filename}`); message.channel.send(embed); diff --git a/lib/default.ts b/lib/default.ts @@ -2,12 +2,7 @@ /// and to act as a reference to how the config shall be /// laid out. All fields are accounted for here. -export default { - name: "Simp'O'Matic", - tag: "#1634", - permissions: 8, - lang: 'en', - +const DEFAULT_GUILD_CONFIG : ConfigType = { pp_sizes: { '541761315887120399': 16 }, @@ -15,6 +10,7 @@ export default { weather_locations: { '541761315887120399': 'Moscow' }, + commands: { prefix: '!', max_history: 40, @@ -80,6 +76,7 @@ export default { response: 'desu' }, ], + trigger: [], // Blacklist (initially everyone can do everything, // except for those listed specifically on this list). blacklist: { @@ -131,5 +128,6 @@ export default { ] } } - }; + +export default DEFAULT_GUILD_CONFIG; diff --git a/lib/extensions.ts b/lib/extensions.ts @@ -5,8 +5,57 @@ declare global { HELP_SOURCE: string, HELP_KEY: string, GIT_URL: string, HELP_MESSAGES: string[], HELP_SECTIONS: string[] , ALL_HELP: string[], - CONFIG: any, SECRETS: any, KNOWN_COMMANDS: string[], - expand_alias: (operator: string, args: string[]) => string + CONFIG: ConfigType, SECRETS: any, KNOWN_COMMANDS: string[], + expand_alias: (operator: string, args: string[], message: Message) => string + }; + + type MatchType = { + match: string | RegExp, + response: string + }; + + type IgnoreType = { + commands?: boolean, + commands_elevated?: boolean, + speech?: boolean + }; + + type ConfigType = { + pp_sizes: { [key: string]: number } + weather_locations: { [key: string]: string }, + commands: { + prefix: string, + max_history: number, + not_understood: string, + aliases: { [key: string]: string }, + } + rules: { + respond: MatchType[], + reject: MatchType[], + replace: MatchType[], + trigger: MatchType[], + blacklist: { + channels: string[], + users: { + [key: string]: IgnoreType + }, + groups: { + [key: string]: IgnoreType + } + }, + whitelist: { + users: string[], + groups: string[] + } + } + }; + + type GlobalConfigType = { + name: string, + tag: string, + permissions: number, + lang: 'en' | 'en-us' | 'en-gb', + guilds: { [key: string]: ConfigType } }; interface Array<T> { diff --git a/lib/format_oed.ts b/lib/format_oed.ts @@ -1,4 +1,4 @@ -import { Attachment } from 'discord.js'; +import { MessageAttachment } from 'discord.js'; import { pp } from './utils'; // Mmm... spaghetti... @@ -56,7 +56,7 @@ export default (res, message) => { if (pron.audioFile) { msg += ` Audio file: ${pron.audioFile}\n`; has_sent_audio = !has_sent_audio; - const attach = new Attachment( + const attach = new MessageAttachment( pron.audioFile, pron.audioFile.split('/').slice(-1)[0] ); diff --git a/lib/main.ts b/lib/main.ts @@ -3,7 +3,7 @@ process.stdin.resume(); // Discord Bot API. import { Discord, On, Client } from '@typeit/discord'; -import { Message, Attachment, TextChannel } from 'discord.js'; +import { Message, MessageAttachment, TextChannel } from 'discord.js'; // System interaction modules. import { @@ -20,8 +20,8 @@ import { deep_merge, pp, compile_match, deep_copy, recursive_regex_to_string } from './utils'; import format_oed from './format_oed'; // O.E.D. JSON entry to markdown. -// Default bot configuration JSON. -import DEFAULT_CONFIG from './default'; +// Default bot configuration for a Guild, JSON. +import DEFAULT_GUILD_CONFIG from './default'; // API specific modules. import web_search from './api/google'; @@ -32,9 +32,16 @@ import { pastebin_latest, // Anything that hasn't been defined in `bot.json` // will be taken care of by the defaults. -let CONFIG = deep_merge( - DEFAULT_CONFIG, - JSON.parse(read_file('./bot.json', 'utf-8'))); +let GLOBAL_CONFIG : GlobalConfigType = { + name: "Simp'O'Matic", + tag: "#1634", + permissions: 8, + lang: 'en', + + guilds: { + "337815809097465856": deep_copy(DEFAULT_GUILD_CONFIG) + } +}; // Store secrets in an object, retrieved from shell's // environment variables. @@ -84,11 +91,12 @@ export class SimpOMatic { `${__dirname}/*Discord.ts` ); console.log('Secrets:', pp(SECRETS)); - console.log('Configured Variables:', pp(CONFIG)); console.log('Known commands:', pp(KNOWN_COMMANDS)); } - expand_alias(operator: string, args: string[]) { + expand_alias(operator: string, args: string[], message: Message) { + const CONFIG = GLOBAL_CONFIG.guilds[message.guild.id]; + const expander = (unexpanded: string) => { let expansion = unexpanded; if (CONFIG.commands.aliases.hasOwnProperty(unexpanded)) @@ -115,6 +123,8 @@ export class SimpOMatic { } process_command(message : Message) { + const CONFIG = GLOBAL_CONFIG.guilds[message.guild.id]; + if (message.content.startsWith('..')) return; const last_command = this._COMMAND_HISTORY.last(); @@ -151,7 +161,7 @@ export class SimpOMatic { let operator = words[0].toLowerCase(); // Expansion of aliases will expand aliases used within // the alias definition too. Yay. - operator = this.expand_alias(operator, args); + operator = this.expand_alias(operator, args, message); if (operator === 'CYCLIC_ALIAS') { message.reply('The command you just used has aliases that go' + ' 300 levels deep, or the alias is cyclically dependant.' @@ -344,7 +354,7 @@ export class SimpOMatic { oed_lookup({ word: query, - lang: CONFIG.lang, + lang: GLOBAL_CONFIG.lang, id: SECRETS.oxford.id, key: SECRETS.oxford.key }).then(res => { @@ -405,7 +415,7 @@ export class SimpOMatic { if (export_string.length < 1980) { message.channel.send("```json\n" + export_string + "\n```"); } - const attach = new Attachment(file_dest, file_name); + const attach = new MessageAttachment(file_dest, file_name); message.channel.send("**Export:**", attach); message.answer(`A copy of this export (\`export-${today}.json\`) \ @@ -440,6 +450,8 @@ export class SimpOMatic { } process_generic(message : Message) { + const CONFIG = GLOBAL_CONFIG.guilds[message.guild.id]; + const { content } = message; if (!content) return; // Message with no content (deleted)... for (const responder of CONFIG.rules.respond) { @@ -463,6 +475,7 @@ export class SimpOMatic { } async last_message(opts) : Promise<string> { + const CONFIG = GLOBAL_CONFIG.guilds[opts.guild.id]; const channel = opts.channel as TextChannel; if (!opts.offset) opts.offset = 1; @@ -487,8 +500,7 @@ export class SimpOMatic { let filter = m => m.content; if (opts.mention) filter = m => m.content && m.author.toString() === opts.mentioning; - - const messages = await channel.fetchMessages({ + const messages = await channel.messages.fetch({ limit: CONFIG.commands.max_history }); // Remember that the _latest_ message, is the one that @@ -510,7 +522,8 @@ export class SimpOMatic { if (expansions[i].length === 2) { // !! expansion expansions[i] = await this.last_message({ command: true, - channel: message.channel + channel: message.channel, + guild: message.guild }); continue; } @@ -539,10 +552,18 @@ export class SimpOMatic { @On("message") async on_message(message : Message, client : Client) { + const guild_id = message.guild.id; + + // Initialise completely new Guilds. + if (!GLOBAL_CONFIG.guilds.hasOwnProperty(guild_id)) + GLOBAL_CONFIG.guilds[guild_id] = deep_copy(DEFAULT_GUILD_CONFIG); + + const CONFIG = GLOBAL_CONFIG.guilds[guild_id]; // Ignore empty messages... if (!message.content) return; console.log('Message acknowledged.'); + console.log('Message from Guild ID:', guild_id); if (SimpOMatic._CLIENT.user.id === message.author.id) { return; } @@ -580,8 +601,8 @@ export class SimpOMatic { const on_termination = () => { // Back-up the resultant CONFIG to an external file. console.log('Cleaning up...'); - write_file(`${process.cwd()}/export-exit.json`, export_config(CONFIG, {})); - pastebin_update(export_config(CONFIG, {})); + write_file(`${process.cwd()}/export-exit.json`, export_config(GLOBAL_CONFIG, {})); + pastebin_update(export_config(GLOBAL_CONFIG, {})); // Make sure we saved ok. return new Promise(res => setTimeout(() => { res(null); @@ -592,13 +613,18 @@ const on_termination = () => { // CONFIG will eventually update to the online version. pastebin_latest().then(res => { - CONFIG = deep_merge(CONFIG, res); + GLOBAL_CONFIG = deep_merge(GLOBAL_CONFIG, res); // Remove any duplicates. - CONFIG = export_config(CONFIG, { ugly: true }); - CONFIG = JSON.parse(CONFIG); + const gc_string = export_config(GLOBAL_CONFIG, { ugly: true }); + GLOBAL_CONFIG = JSON.parse(gc_string); // Precompile all regular-expressions in known places. - ['respond', 'reject', 'replace'] - .each(name => CONFIG.rules[name].mut_map(compile_match)); + for(const guild in GLOBAL_CONFIG.guilds) + if (GLOBAL_CONFIG.guilds.hasOwnProperty(guild)) + ['respond', 'reject', 'replace'] + .each(name => + GLOBAL_CONFIG.guilds[guild].rules[name] + .mut_map(compile_match)); + // Start The Simp'O'Matic. SimpOMatic.start(); }).catch(console.warn); @@ -609,4 +635,3 @@ process.on('exit', on_termination); process.on('SIGINT', on_termination); process.on('SIGUSR1', on_termination); process.on('SIGUSR2', on_termination); -process.on('uncaughtException', on_termination); diff --git a/lib/utils.ts b/lib/utils.ts @@ -97,11 +97,14 @@ export const export_config = (obj, { ugly = false }) => { const o = recursive_regex_to_string(deep_clone(obj)); // Make sure all rules are unique, // i.e. eliminate duplicate rules. - ['respond', 'reject', 'replace'] - .forEach(name => o.rules[name] = o.rules[name] - .map(JSON.stringify) - .unique() - .map(JSON.parse)); + + for (const guild in obj.guilds) + if (obj.guilds.hasOwnProperty(guild)) + ['respond', 'reject', 'replace'] + .each(name => o.guilds[guild].rules[name] = o.guilds[guild].rules[name] + .map(JSON.stringify) + .unique() + .map(JSON.parse)); return JSON.stringify(o, null, ugly ? null : 4); }; diff --git a/package.json b/package.json @@ -34,13 +34,13 @@ }, "dependencies": { "@typeit/discord": "^1.0.3", - "@types/node": "^13.9.0", + "@types/node": "^13.9.3", "@types/node-fetch": "^2.5.5", "@types/ws": "^7.2.2", "better-pastebin": "^0.4.1", "cowsay": "^1.4.0", "deepcopy": "^2.0.0", - "discord.js": "11.6.1", + "discord.js": "12.0.2", "figlet": "^1.3.0", "figlet-cli": "^0.1.1", "fortune-teller": "^0.1.2", diff --git a/yarn.lock b/yarn.lock @@ -30,6 +30,11 @@ dependencies: regenerator-runtime "^0.13.4" +"@discordjs/collection@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.1.5.tgz#1781c620b4c88d619bd0373a1548e5a6025e3d3a" + integrity sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw== + "@jimp/bmp@^0.9.6": version "0.9.6" resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.9.6.tgz#379e261615d7c1f3b52af4d5a0f324666de53d7d" @@ -324,10 +329,10 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@^13.9.0": - version "13.9.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.2.tgz#ace1880c03594cc3e80206d96847157d8e7fa349" - integrity sha512-bnoqK579sAYrQbp73wwglccjJ4sfRdKU7WNEZ5FW4K2U6Kc0/eZ5kvXG0JKsEKFB50zrFmfFt52/cvBbZa7eXg== +"@types/node@*", "@types/node@^13.9.3": + version "13.9.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.3.tgz#6356df2647de9eac569f9a52eda3480fa9e70b4d" + integrity sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA== "@types/ws@^7.2.2": version "7.2.3" @@ -700,16 +705,19 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -discord.js@11.6.1: - version "11.6.1" - resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-11.6.1.tgz#be5a0e0fc8f91fa46d9cd265261268948bcf8dc5" - integrity sha512-UV7rMQL2xtHtbHAaGwRlAhEepHjz3V0UEEoWd89QbLMu3MV0D7+xkYCaAhlxnvuJWbhPO8p49Anx8qJ/SrcdwQ== +discord.js@12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-12.0.2.tgz#c4d68f1363d7fc05ed71a42dba6b930966ed8602" + integrity sha512-iZiEA4Y61gqq/EjFfLXnkRK9pLapnax/vTVDUhs/mAhyqozAy0GOlk/MZI9rSa1iIoKTWRq6P9CRKhLNT2wUnA== dependencies: - long "^4.0.0" - prism-media "^0.0.4" - snekfetch "^3.6.4" - tweetnacl "^1.0.0" - ws "^6.0.0" + "@discordjs/collection" "^0.1.5" + abort-controller "^3.0.0" + form-data "^3.0.0" + node-fetch "^2.6.0" + prism-media "^1.2.0" + setimmediate "^1.0.5" + tweetnacl "^1.0.3" + ws "^7.2.1" dom-serializer@0: version "0.2.2" @@ -1353,11 +1361,6 @@ lodash@^4.17.15: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - lru-cache@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -1569,10 +1572,10 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prism-media@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-0.0.4.tgz#df5ddc6463670c97ff0e9cbac3c3e0db18df326f" - integrity sha512-dG2w7WtovUa4SiYTdWn9H8Bd4JNdei2djtkP/Bk9fXq81j5Q15ZPHYSwhUVvBRbp5zMkGtu0Yk62HuMcly0pRw== +prism-media@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.2.1.tgz#168f323712bcaacb1d70ae613bf9d9dc44cf43d4" + integrity sha512-R3EbKwJiYlTvGwcG1DpUt+06DsxOGS5W4AMEHT7oVOjG93MjpdhGX1whHyjnqknylLMupKAsKMEXcTNRbPe6Vw== process@~0.5.1: version "0.5.2" @@ -1590,9 +1593,9 @@ punycode@^2.1.0, punycode@^2.1.1: integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== qs@^6.7.0: - version "6.9.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" - integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== + version "6.9.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.2.tgz#a27b695006544a04bf0e6c6a7e8120778926d5bd" + integrity sha512-2eQ6zajpK7HwqrY1rRtGw5IZvjgtELXzJECaEDuzDFo2jjnIXpJSimzd4qflWZq6bLLi+Zgfj5eDrAzl/lptyg== qs@~6.5.2: version "6.5.2" @@ -1697,10 +1700,10 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -snekfetch@^3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/snekfetch/-/snekfetch-3.6.4.tgz#d13e80a616d892f3d38daae4289f4d258a645120" - integrity sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw== +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= source-map@~0.6.1: version "0.6.1" @@ -1839,7 +1842,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -tweetnacl@^1.0.0: +tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== @@ -1961,13 +1964,18 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^6.0.0, ws@^6.1.0: +ws@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== dependencies: async-limiter "~1.0.0" +ws@^7.2.1: + version "7.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" + integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== + xhr@^2.0.1: version "2.5.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd"