diff --git a/config.example.yml b/config.example.yml index d3a9bfe..0c07a68 100644 --- a/config.example.yml +++ b/config.example.yml @@ -6,6 +6,8 @@ telegram: webhook: url: https://something.org:3002/webhook enabled: false +postgres: + uri: postgres://user:password@db/bot logger: level: info vk: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e175a50 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.4' +services: + db: + container_name: bot-db + image: postgres:11-alpine + ports: + - 5432:5432 + environment: + POSTGRES_USER: user + POSTGRES_PASSWORD: password + POSTGRES_DB: bot + volumes: + - bot-db:/var/lib/postgresql/data + - /etc/localtime:/etc/localtime:ro +volumes: + bot-db: {} diff --git a/package.json b/package.json index 0d8ce99..4f4b57d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "build": "rm -rf ./dist && tsc && copyfiles -f ./config*.yml ./dist && copyfiles ./templates/*.md ./dist" }, "dependencies": { - "@types/node": "^14.14.37", + "axios": "^0.21.1", + "cross-fetch": "^3.1.4", "express": "^4.17.1", "handlebars": "^4.7.7", "http": "^0.0.1-security", @@ -17,6 +18,7 @@ "morgan": "^1.10.0", "node-yaml-config": "^0.0.6", "path": "^0.12.7", + "pg": "^8.6.0", "ramda": "^0.27.1", "remark": "^13.0.0", "remark-extract-frontmatter": "^3.1.0", @@ -26,6 +28,7 @@ "socks-proxy-agent": "^5.0.0", "telegraf": "^4.3.0", "to-vfile": "^6.1.0", + "typeorm": "^0.2.32", "typescript": "^4.2.3", "unist-util-filter": "^3.0.0", "url": "^0.11.0", @@ -35,6 +38,8 @@ "yup": "^0.32.9" }, "devDependencies": { + "@types/axios": "^0.14.0", + "@types/node": "^14.14.37", "@types/express": "^4.17.11", "@types/handlebars": "^4.1.0", "@types/ramda": "^0.27.39", diff --git a/src/config/types.ts b/src/config/types.ts index 3da2ca7..9e242ac 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -2,6 +2,7 @@ import { TelegramConfig } from "../service/telegram/types"; import { VkConfig, VkEvent } from "../service/vk/types"; import { HttpConfig } from "../api/http/types"; import { LoggerConfig } from "../service/logger/types"; +import { PostgresConfig } from "../service/db/postgres/types"; export type TemplateConfig = Record; @@ -11,4 +12,5 @@ export interface Config extends Record { vk: VkConfig; logger?: LoggerConfig; templates?: TemplateConfig; + postgres?: PostgresConfig; } diff --git a/src/config/validate.ts b/src/config/validate.ts index f3a228b..2b1ab8f 100644 --- a/src/config/validate.ts +++ b/src/config/validate.ts @@ -4,6 +4,7 @@ import { Config } from "./types"; import { vkConfigSchema } from "../service/vk/validation"; import { telegramConfigSchema } from "../service/telegram/validation"; import { loggerConfigSchema } from "../service/logger/config"; +import { dbConfigValidatior } from "../service/db/postgres/validation"; const templateConfigSchema = object().shape({ message_new: string().required(), @@ -15,6 +16,7 @@ const configSchema = object().required().shape({ telegram: telegramConfigSchema, logger: loggerConfigSchema, templates: templateConfigSchema, + postgres: dbConfigValidatior, }); export const validateConfig = (config: Config) => diff --git a/src/index.ts b/src/index.ts index fbf4560..56c7d78 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,12 +4,17 @@ import logger from "./service/logger"; import { VkService } from "./service/vk"; import { TelegramApi } from "./api/telegram"; import { HttpApi } from "./api/http"; +import { PostgresDB } from "./service/db/postgres"; async function main() { try { const config = prepareConfig(); + + const db = new PostgresDB(config.postgres); + await db.connect(); + const telegram = new TelegramService(config.telegram); - const vkService = new VkService(config.vk, telegram, config.templates); + const vkService = new VkService(config.vk, telegram, config.templates, db); const telegramApi = new TelegramApi(telegram).listen(); await telegram.start(); diff --git a/src/service/db/index.ts b/src/service/db/index.ts new file mode 100644 index 0000000..4bc1a53 --- /dev/null +++ b/src/service/db/index.ts @@ -0,0 +1,37 @@ +import { VkEvent } from "../vk/types"; +import { Like } from "./postgres/entities/Like"; +import { Event } from "./postgres/entities/Event"; +import { Post } from "./postgres/entities/Post"; + +export interface Storage { + getEventByMessageId( + type: VkEvent, + tgMessageId: number, + groupId: number, + channel: string + ): Promise; + getEventById( + type: VkEvent, + eventId: number, + groupId: number, + channel: string + ): Promise; + createEvent( + type: VkEvent, + eventId: number, + groupId: number, + channel: string, + tgMessageId: number, + text: Record + ): Promise; + createOrUpdateLike( + messageId: number, + channel: string, + author: number, + text: string + ): Promise; + getLikesFor(channel: string, messageId: number): Promise; + getLikeBy(channel: string, messageId: number, author: number): Promise; + createPost(eventId: number, text: string): Promise; + findPostByEvent(eventId: number): Promise; +} diff --git a/src/service/db/postgres/entities/Event.ts b/src/service/db/postgres/entities/Event.ts new file mode 100644 index 0000000..9f84ba2 --- /dev/null +++ b/src/service/db/postgres/entities/Event.ts @@ -0,0 +1,30 @@ +import { + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from "typeorm"; +import { VkEvent } from "../../../vk/types"; + +@Entity() +export class Event { + @PrimaryGeneratedColumn() + id: number; + @Column() + type: VkEvent; + @Column() + vkEventId: number; + @Column() + vkGroupId: number; + @Column() + channel: string; + @Column() + tgMessageId: number; + @CreateDateColumn() + createdAt: Date; + @UpdateDateColumn() + updatedAt: Date; + @Column("simple-json", { default: {}, nullable: false }) + text: Record; +} diff --git a/src/service/db/postgres/entities/Like.ts b/src/service/db/postgres/entities/Like.ts new file mode 100644 index 0000000..ff1c2d3 --- /dev/null +++ b/src/service/db/postgres/entities/Like.ts @@ -0,0 +1,25 @@ +import { + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from "typeorm"; + +@Entity() +export class Like { + @PrimaryGeneratedColumn() + id: number; + @Column() + messageId: number; + @Column() + channel: string; + @Column({ type: "text" }) + text: string; + @Column() + author: number; + @CreateDateColumn() + createdAt: Date; + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/src/service/db/postgres/entities/Post.ts b/src/service/db/postgres/entities/Post.ts new file mode 100644 index 0000000..8e4ad86 --- /dev/null +++ b/src/service/db/postgres/entities/Post.ts @@ -0,0 +1,21 @@ +import { + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from "typeorm"; + +@Entity() +export class Post { + @PrimaryGeneratedColumn() + id: number; + @Column() + eventId: number; + @Column({ type: "text" }) + text: string; + @CreateDateColumn() + createdAt: Date; + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/src/service/db/postgres/index.ts b/src/service/db/postgres/index.ts new file mode 100644 index 0000000..0c29372 --- /dev/null +++ b/src/service/db/postgres/index.ts @@ -0,0 +1,123 @@ +import { Storage } from "../index"; +import { VkEvent } from "../../vk/types"; +import { PostgresConfig } from "./types"; +import { Connection, createConnection, Repository } from "typeorm"; +import logger from "../../logger"; +import path from "path"; +import { Like } from "./entities/Like"; +import { Event } from "./entities/Event"; +import { Post } from "./entities/Post"; + +const entities = [path.join(__dirname, "./entities/*")]; + +export class PostgresDB implements Storage { + private connection: Connection; + private events: Repository; + private likes: Repository; + private posts: Repository; + + constructor(private config: PostgresConfig) {} + + connect = async () => { + this.connection = await createConnection({ + type: "postgres", + url: this.config.uri, + entities, + logging: true, + synchronize: true, + }); + + await this.connection.synchronize(); + + this.events = this.connection.getRepository(Event); + this.likes = this.connection.getRepository(Like); + this.posts = this.connection.getRepository(Post); + + logger.info(`db connected to ${this.config.uri}`); + }; + + getEventByMessageId = async ( + type: VkEvent, + tgMessageId: number, + vkGroupId: number, + channel: string + ) => { + return await this.events.findOne({ + type, + tgMessageId, + vkGroupId, + channel, + }); + }; + + getEventById = async ( + type: VkEvent, + id: number, + vkGroupId: number, + channel: string + ) => { + return await this.events.findOne({ + type, + id, + vkGroupId, + channel, + }); + }; + + createEvent = async ( + type: VkEvent, + eventId: number, + groupId: number, + channel: string, + tgMessageId: number, + text: Record + ) => { + const event = this.events.create({ + type, + vkEventId: eventId, + vkGroupId: groupId, + channel, + tgMessageId, + text, + }); + + return await this.events.save(event); + }; + + getLikesFor = async (channel, messageId) => { + return await this.likes.find({ + where: { channel, messageId }, + }); + }; + + getLikeBy = async (channel, messageId, author) => { + return this.likes.findOne({ + channel, + messageId, + author, + }); + }; + + createOrUpdateLike = async (messageId, channel, author, text) => { + const like = await this.likes.findOne({ channel, author, messageId }); + + if (like) { + return await this.likes.save({ ...like, text }); + } else { + return this.likes.save({ + channel, + author, + text, + messageId, + }); + } + }; + + findPostByEvent = async (eventId: number) => { + return this.posts.findOne({ eventId }); + }; + + createPost = async (eventId: number, text: string) => { + return this.posts.save({ eventId, text }); + }; +} diff --git a/src/service/db/postgres/types.ts b/src/service/db/postgres/types.ts new file mode 100644 index 0000000..cbf5bff --- /dev/null +++ b/src/service/db/postgres/types.ts @@ -0,0 +1,3 @@ +export interface PostgresConfig { + uri: string; +} diff --git a/src/service/db/postgres/validation.ts b/src/service/db/postgres/validation.ts new file mode 100644 index 0000000..94e09c4 --- /dev/null +++ b/src/service/db/postgres/validation.ts @@ -0,0 +1,7 @@ +import { object, string } from "yup"; + +export const dbConfigValidatior = object().shape({ + uri: string() + .required() + .matches(/^postgres:/), +}); diff --git a/src/service/telegram/index.ts b/src/service/telegram/index.ts index fac6483..49fe728 100644 --- a/src/service/telegram/index.ts +++ b/src/service/telegram/index.ts @@ -85,7 +85,22 @@ export class TelegramService { extra?: ExtraReplyMessage ) => { logger.debug(`sending message "${message}" to chan "${channel}"`); - await this.bot.telegram.sendMessage(channel, message, extra); - return; + return await this.bot.telegram.sendMessage(channel, message, extra); + }; + + /** + * Sends simple message to channel + */ + public sendPhotoToChan = async ( + channel: string, + caption: string, + src: string, + extra?: ExtraReplyMessage + ) => { + logger.debug(`sending photo message "${caption}" to chan "${channel}"`); + return await this.bot.telegram.sendPhoto(channel, src, { + ...extra, + caption, + }); }; } diff --git a/src/service/vk/handlers/PostNewHandler.ts b/src/service/vk/handlers/PostNewHandler.ts index b5d23dd..da35894 100644 --- a/src/service/vk/handlers/PostNewHandler.ts +++ b/src/service/vk/handlers/PostNewHandler.ts @@ -4,7 +4,12 @@ import { NextMiddleware } from "middleware-io"; import { UsersUserFull } from "vk-io/lib/api/schemas/objects"; import { ConfigGroup } from "../types"; import { ExtraReplyMessage } from "telegraf/typings/telegram-types"; -import { InlineKeyboardButton, Update } from "typegram"; +import { + InlineKeyboardButton, + InlineKeyboardMarkup, + Message, + Update, +} from "typegram"; import { keys } from "ramda"; import { extractURLs } from "../../../utils/extract"; import logger from "../../logger"; @@ -13,7 +18,10 @@ import CallbackQueryUpdate = Update.CallbackQueryUpdate; type Button = "links" | "likes"; type UrlPrefix = string; -type ExtraGenerator = (text: string) => InlineKeyboardButton[]; +type ExtraGenerator = ( + text: string, + eventId?: number +) => Promise; interface Fields { image?: boolean; @@ -31,6 +39,8 @@ interface Values { type LikeCtx = Composer.Context & { match: string[] }; +const PHOTO_CAPTION_LIMIT = 1000; + export class PostNewHandler extends VkEventHandler { constructor(...props: any) { // @ts-ignore @@ -41,33 +51,65 @@ export class PostNewHandler extends VkEventHandler { private likes: string[] = ["👎", "👍"]; public execute = async (context: WallPostContext, next: NextMiddleware) => { + const id = context?.wall?.id; + if ( context.isRepost || - !PostNewHandler.isValidPostType(context?.wall?.postType) + !PostNewHandler.isValidPostType(context?.wall?.postType) || + !id ) { await next(); return; } + const exist = await this.getEventById(id); + if (exist) { + logger.warn( + `received duplicate entry for ${this.group.name}, ${this.type}, ${id}` + ); + await next(); + return; + } + const user = context.wall.signerId ? await this.getUserByID(String(context.wall.signerId)) : undefined; const text = context.wall.text.trim(); - const parsed = this.template.theme({ - user, - group: this.group, - text, - }); + const parsed = this.themeText(text, user); const extras: ExtraReplyMessage = { disable_web_page_preview: true, + reply_markup: await this.createKeyboard(text), }; - this.appendExtras(extras, text); + let msg: Message; - await this.telegram.sendMessageToChan(this.channel, parsed, extras); + const images = context.wall.getAttachments("photo"); + const hasThumb = + this.template.fields.image && + images.length && + images.some((img) => img.mediumSizeUrl); + + if (hasThumb) { + const thumb = await images.find((img) => img.mediumSizeUrl); + msg = await this.telegram.sendPhotoToChan( + this.channel, + this.trimTextForPhoto(text, user), + thumb.mediumSizeUrl, + extras + ); + } else { + msg = await this.telegram.sendMessageToChan(this.channel, parsed, extras); + } + + const event = await this.createEvent( + id, + msg.message_id, + context.wall.toJSON() + ); + await this.db.createPost(event.id, context.wall.text); await next(); }; @@ -82,29 +124,32 @@ export class PostNewHandler extends VkEventHandler { /** * Creates extras */ - private appendExtras = (extras: ExtraReplyMessage, text: string) => { + private createKeyboard = async ( + text: string, + eventId?: number + ): Promise => { const { buttons } = this.template.fields; + if (!buttons?.length) { return; } - const keyboard = buttons - .map((button) => this.extrasGenerators[button](text)) - .filter((el) => el && el.length); + const rows = await Promise.all( + buttons.map((button) => this.extrasGenerators[button](text, eventId)) + ); + const inline_keyboard = rows.filter((el) => el && el.length); - if (!keyboard.length) { + if (!inline_keyboard.length) { return; } - extras.reply_markup = { - inline_keyboard: keyboard, - }; + return { inline_keyboard }; }; /** * Generates link buttons for post */ - private generateLinks: ExtraGenerator = (text) => { + private generateLinks: ExtraGenerator = async (text) => { const links = this.template.fields.links; if (!links) { @@ -131,8 +176,25 @@ export class PostNewHandler extends VkEventHandler { /** * Generates like button */ - private generateLikes: ExtraGenerator = () => { - return this.likes.map((like, i) => ({ + private generateLikes: ExtraGenerator = async (text, eventId) => { + if (eventId) { + const event = await this.getEventById(eventId); + const likes = await this.db.getLikesFor(this.channel, event.tgMessageId); + const withCount = likes.reduce( + (acc, like) => ({ + ...acc, + [like.text]: acc[like.text] ? acc[like.text] + 1 : 1, + }), + {} as Record + ); + + return this.likes.map((like) => ({ + text: withCount[like] ? `${like} ${withCount[like]}` : like, + callback_data: `/like ${this.channel} ${like}`, + })); + } + + return this.likes.map((like) => ({ text: like, callback_data: `/like ${this.channel} ${like}`, })); @@ -164,14 +226,17 @@ export class PostNewHandler extends VkEventHandler { /** * Reacts to like button press */ - onLikeAction = async (ctx: LikeCtx, next) => { + private onLikeAction = async (ctx: LikeCtx, next) => { const id = ctx.update.callback_query.message.message_id; - const [_, channel, emo] = ctx.match; + const author = ctx.update.callback_query.from.id; + const [, channel, emo] = ctx.match; + const event = await this.getEventByTgMessageId(id); if ( !channel || !emo || !id || + !event || channel != this.channel || !this.likes.includes(emo) ) { @@ -179,8 +244,76 @@ export class PostNewHandler extends VkEventHandler { return; } - logger.warn( + const post = await this.db.findPostByEvent(event.id); + if (!post) { + await next(); + return; + } + + const like = await this.getLike(author, id); + if (like?.text === emo) { + await next(); + return; + } + + await this.createOrUpdateLike(author, event.tgMessageId, emo); + + const markup = await this.createKeyboard(post.text, event.id); + + await ctx.telegram.editMessageReplyMarkup( + ctx.chat.id, + id, + ctx.inlineMessageId, + markup + ); + + logger.info( `someone reacted with ${emo} to message ${id} on channel ${channel}` ); + + next(); + }; + + private createOrUpdateLike = async ( + author: number, + messageId: number, + emo: string + ) => { + return await this.db.createOrUpdateLike( + messageId, + this.channel, + author, + emo + ); + }; + + private getLike = async (author: number, messageId: number) => { + return await this.db.getLikeBy(this.channel, messageId, author); + }; + + /** + * Applies template theming to photos + */ + private themeText = (text: string, user?: UsersUserFull): string => { + return this.template.theme({ + user, + group: this.group, + text, + }); + }; + + /** + * Calculates, how much should we cut off the text to match photo caption limitations + */ + private trimTextForPhoto = (text: string, user: UsersUserFull): string => { + // Full markup + const full = this.themeText(text, user); + // Rest info except text + const others = this.themeText("", user); + + // How much rest markup takes + const diff = full.length - others.length; + + return full.slice(0, PHOTO_CAPTION_LIMIT - diff); }; } diff --git a/src/service/vk/handlers/VkEventHandler.ts b/src/service/vk/handlers/VkEventHandler.ts index db30c47..3335052 100644 --- a/src/service/vk/handlers/VkEventHandler.ts +++ b/src/service/vk/handlers/VkEventHandler.ts @@ -3,6 +3,8 @@ import { ConfigGroup, GroupInstance, VkEvent } from "../types"; import { VkService } from "../index"; import { TelegramService } from "../../telegram"; import { Template } from "../../template"; +import { Storage } from "../../db"; +import { Event } from "../../db/postgres/entities/Event"; export class VkEventHandler< F extends Record = any, @@ -15,7 +17,8 @@ export class VkEventHandler< protected instance: GroupInstance, protected vk: VkService, protected telegram: TelegramService, - protected template: Template + protected template: Template, + protected db: Storage ) {} public execute: ( @@ -44,4 +47,56 @@ export class VkEventHandler< */ protected makeDialogUrl = (groupId: number, userId: number): string => `https://vk.com/gim${groupId}?sel=${userId}`; + + /** + * Checks for duplicates + */ + getEventById = async (id?: number): Promise => { + if (!id) { + return undefined; + } + + return await this.db.getEventById( + this.type, + id, + this.group.id, + this.channel + ); + }; + + /** + * Checks for duplicates + */ + getEventByTgMessageId = async ( + tgMessageId?: number + ): Promise => { + if (!tgMessageId) { + return undefined; + } + + return await this.db.getEventByMessageId( + this.type, + tgMessageId, + this.group.id, + this.channel + ); + }; + + /** + * Creates event record in DB + */ + createEvent = async ( + id: number, + tgMessageId: number, + text: Record + ) => { + return await this.db.createEvent( + this.type, + id, + this.group.id, + this.channel, + tgMessageId, + text + ); + }; } diff --git a/src/service/vk/handlers/index.ts b/src/service/vk/handlers/index.ts index f1763cd..8e7f9fa 100644 --- a/src/service/vk/handlers/index.ts +++ b/src/service/vk/handlers/index.ts @@ -6,6 +6,7 @@ import { VkService } from "../index"; import { TelegramService } from "../../telegram"; import { Template } from "../../template"; import { PostNewHandler } from "./PostNewHandler"; +import { Storage } from "../../db"; interface Handler { new ( @@ -15,7 +16,8 @@ interface Handler { instance: GroupInstance, vk: VkService, telegram: TelegramService, - template: Template + template: Template, + db: Storage ): VkEventHandler; } diff --git a/src/service/vk/index.ts b/src/service/vk/index.ts index 731c0b6..9655482 100644 --- a/src/service/vk/index.ts +++ b/src/service/vk/index.ts @@ -9,6 +9,7 @@ import { vkEventToHandler } from "./handlers"; import { TelegramService } from "../telegram"; import { Template } from "../template"; import { TemplateConfig } from "../../config/types"; +import { Storage } from "../db"; /** * Service to handle VK to Telegram interactions @@ -21,7 +22,8 @@ export class VkService { constructor( private config: VkConfig, private telegram: TelegramService, - private templates: TemplateConfig + private templates: TemplateConfig, + private db: Storage ) { if (!config.groups.length) { throw new Error("No vk groups to handle. Specify them in config"); @@ -64,6 +66,7 @@ export class VkService { logger.debug(`received vk event`, { body }); const inst = this.instances[groupId] as GroupInstance; + inst.updates.getWebhookCallback(this.config.endpoint)(req, res, next); } catch (e) { next(e); @@ -122,7 +125,8 @@ export class VkService { instance, this, this.telegram, - template + template, + this.db ); return { ...acc, [event]: handler }; }, {} as Record[]) diff --git a/src/service/vk/types.ts b/src/service/vk/types.ts index 374b5af..6bbb3f6 100644 --- a/src/service/vk/types.ts +++ b/src/service/vk/types.ts @@ -14,7 +14,7 @@ export interface ConfigGroup { channels: GroupChannel[]; } -interface GroupChannel { +export interface GroupChannel { id: string; events: VkEvent[]; } diff --git a/templates/post_new.md b/templates/post_new.md index a4df2df..5b1dd3f 100644 --- a/templates/post_new.md +++ b/templates/post_new.md @@ -17,5 +17,5 @@ {{text}} {{#if user}} -[{{user.first_name}} {{user.last_name}}](https://vk.com/id{{user.id}}) +-- [{{user.first_name}} {{user.last_name}}](https://vk.com/id{{user.id}}) {{/if}} diff --git a/yarn.lock b/yarn.lock index 188f086..e3044ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,6 +18,18 @@ enabled "2.0.x" kuler "^2.0.0" +"@sqltools/formatter@^1.2.2": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" + integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== + +"@types/axios@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" + integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY= + dependencies: + axios "*" + "@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" @@ -140,6 +152,11 @@ resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.11.tgz#d654a112973f5e004bf8438122bd7e56a8e5cd7e" integrity sha512-9cwk3c87qQKZrT251EDoibiYRILjCmxBvvcb4meofCmx1vdnNcR9gyildy5vOHASpOKMsn42CugxUvcwK5eu1g== +"@types/zen-observable@^0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" + integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -162,18 +179,38 @@ agent-base@6: dependencies: debug "4" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + ansi-regex@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^4.0.0: +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +app-root-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" + integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -206,6 +243,13 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +axios@*, axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + bail@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" @@ -216,6 +260,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -265,11 +314,43 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + character-entities-legacy@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" @@ -285,6 +366,18 @@ character-reference-invalid@^1.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== +cli-highlight@^2.1.10: + version "2.1.11" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -399,6 +492,13 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cross-fetch@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -433,6 +533,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +dotenv@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -463,6 +568,11 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -536,6 +646,11 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce" integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q== +figlet@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.0.tgz#2db4d00a584e5155a96080632db919213c3e003c" + integrity sha512-ZQJM4aifMpz6H19AW1VqvZ7l4pOE9p7i/3LyxgO2kp+PO/VcDYNqIHEMtkccqIhTXMKci4kjueJr/iCQEaT/Ww== + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -554,6 +669,11 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== +follow-redirects@^1.10.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.0.tgz#f5d260f95c5f8c105894491feee5dc8993b402fe" + integrity sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg== + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -593,7 +713,7 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -glob@^7.0.5: +glob@^7.0.5, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -617,6 +737,18 @@ handlebars@*, handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -624,6 +756,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +highlight.js@^10.7.1: + version "10.7.2" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360" + integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg== + http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -658,6 +795,11 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -945,6 +1087,15 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nanoclone@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" @@ -965,7 +1116,7 @@ nlcst-to-string@^2.0.0: resolved "https://registry.yarnpkg.com/nlcst-to-string/-/nlcst-to-string-2.0.4.tgz#9315dfab80882bbfd86ddf1b706f53622dc400cc" integrity sha512-3x3jwTd6UPG7vi5k4GEzvxJ5rDA7hVUIRNHPblKuMVP9Z3xmlsd9cgLcpAMkc5uPOBna82EeshROFhsPkbnTZg== -node-fetch@^2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -994,6 +1145,11 @@ noms@0.0.0: inherits "^2.0.1" readable-stream "~1.0.31" +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -1025,6 +1181,16 @@ p-timeout@^4.1.0: resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-4.1.0.tgz#788253c0452ab0ffecf18a62dff94ff1bd09ca0a" integrity sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw== +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +parent-require@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" + integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= + parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -1046,6 +1212,23 @@ parse-latin@^4.0.0: unist-util-modify-children "^2.0.0" unist-util-visit-children "^1.0.0" +parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -1069,6 +1252,79 @@ path@^0.12.7: process "^0.11.1" util "^0.10.3" +pg-connection-string@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.3.0.tgz#12d5c7f65ea18a6e99ca9811bd18129071e562fc" + integrity sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg== + +pg-protocol@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.6.0.tgz#e222296b0b079b280cce106ea991703335487db2" + integrity sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.3.0" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + +pgpass@1.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.4.tgz#85eb93a83800b20f8057a2b029bf05abaf94ea9c" + integrity sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w== + dependencies: + split2 "^3.1.1" + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prettier@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" @@ -1145,7 +1401,7 @@ readable-stream@^2.3.7, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.4.0: +readable-stream@^3.0.0, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -1164,6 +1420,11 @@ readable-stream@~1.0.31: isarray "0.0.1" string_decoder "~0.10.x" +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" @@ -1258,7 +1519,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 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: +safe-buffer@^5.0.1, 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== @@ -1280,6 +1541,11 @@ sandwich-stream@^2.0.2: resolved "https://registry.yarnpkg.com/sandwich-stream/-/sandwich-stream-2.0.2.tgz#6d1feb6cf7e9fe9fadb41513459a72c2e84000fa" integrity sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ== +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -1314,6 +1580,14 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +sha.js@^2.4.11: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -1348,6 +1622,13 @@ source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -1391,6 +1672,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + strip-ansi@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" @@ -1398,6 +1686,18 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + telegraf@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/telegraf/-/telegraf-4.3.0.tgz#c9683192bdb81e7c7fbb04cf1ce750fb34de7149" @@ -1418,6 +1718,20 @@ text-hex@1.0.x: resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -1459,6 +1773,11 @@ ts-toolbelt@^6.15.1: resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83" integrity sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A== +tslib@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -1472,6 +1791,29 @@ typegram@^3.2.0: resolved "https://registry.yarnpkg.com/typegram/-/typegram-3.2.4.tgz#b16310822c23d41a1d552d3fdc974f2d1c231d42" integrity sha512-UkWgXIXZYwXK0q6zyZ4xtlETAmmgAt1Y4EFL5Ia87bIort1HHBw+RAMnO7eC1PYogCAKPSCeCSBAZVIoxQ/Dvw== +typeorm@^0.2.32: + version "0.2.32" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.32.tgz#544dbfdfe0cd0887548d9bcbd28527ea4f4b3c9b" + integrity sha512-LOBZKZ9As3f8KRMPCUT2H0JZbZfWfkcUnO3w/1BFAbL/X9+cADTF6bczDGGaKVENJ3P8SaKheKmBgpt5h1x+EQ== + dependencies: + "@sqltools/formatter" "^1.2.2" + app-root-path "^3.0.0" + buffer "^6.0.3" + chalk "^4.1.0" + cli-highlight "^2.1.10" + debug "^4.3.1" + dotenv "^8.2.0" + glob "^7.1.6" + js-yaml "^4.0.0" + mkdirp "^1.0.4" + reflect-metadata "^0.1.13" + sha.js "^2.4.11" + tslib "^2.1.0" + xml2js "^0.4.23" + yargonaut "^1.1.4" + yargs "^16.2.0" + zen-observable-ts "^1.0.0" + typescript@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" @@ -1684,6 +2026,19 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +xml2js@^0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -1699,12 +2054,21 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yargonaut@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" + integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== + dependencies: + chalk "^1.1.1" + figlet "^1.1.1" + parent-require "^1.0.0" + yargs-parser@^20.2.2: version "20.2.7" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== -yargs@^16.1.0: +yargs@^16.0.0, yargs@^16.1.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -1743,6 +2107,19 @@ yup@^0.32.9: property-expr "^2.0.4" toposort "^2.0.2" +zen-observable-ts@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.0.0.tgz#30d1202b81d8ba4c489e3781e8ca09abf0075e70" + integrity sha512-KmWcbz+9kKUeAQ8btY8m1SsEFgBcp7h/Uf3V5quhan7ZWdjGsf0JcGLULQiwOZibbFWnHkYq8Nn2AZbJabovQg== + dependencies: + "@types/zen-observable" "^0.8.2" + zen-observable "^0.8.15" + +zen-observable@^0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"