├── .github └── stale.yml ├── .gitignore ├── agent ├── Dockerfile ├── client.py ├── config │ └── __init__.py ├── db │ ├── __init__.py │ └── database.py ├── forwarder.py ├── readme.md ├── requirements.txt ├── server.py ├── session │ └── .keep └── utils │ ├── __init__.py │ ├── filter.py │ └── transformation.py ├── bot ├── .prettierrc ├── Dockerfile ├── bot.js ├── config │ └── index.js ├── controllers │ ├── activateRedirection.js │ ├── addFilter.js │ ├── addRedirection.js │ ├── addTransformation.js │ ├── deactivateRedirection.js │ ├── getFilter.js │ ├── getTransformations.js │ ├── message │ │ └── parser.js │ ├── removeRedirection.js │ ├── removeTransformation.js │ └── swapTransformationRank.js ├── db │ └── database.js ├── package-lock.json ├── package.json ├── readme.md ├── services │ ├── agent.js │ ├── database.js │ └── telegram.js └── wait-for.sh ├── docker-compose.yml ├── init.sql └── readme.md /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 30 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bot/node_modules 2 | 3 | agent/config/synaptic.py 4 | agent/.venv/ 5 | *.db-journal 6 | __pycache__ 7 | .env 8 | agent/session/* 9 | 10 | !.keep 11 | *.db 12 | -------------------------------------------------------------------------------- /agent/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-rc-buster 2 | 3 | RUN apt-get clean && \ 4 | rm -rf /var/lib/apt/lists/* && \ 5 | apt-get clean && \ 6 | apt-get update 7 | 8 | RUN apt-get install python-dev default-libmysqlclient-dev -y 9 | 10 | WORKDIR /telegram-python-agent 11 | 12 | COPY requirements.txt . 13 | 14 | RUN pip install -r requirements.txt 15 | 16 | COPY . . 17 | 18 | CMD ["python", "server.py"] -------------------------------------------------------------------------------- /agent/client.py: -------------------------------------------------------------------------------- 1 | from telethon import TelegramClient, events, sync 2 | from config import api_id, api_hash 3 | 4 | telegram_client = TelegramClient('session/telethon', api_id, api_hash) 5 | -------------------------------------------------------------------------------- /agent/config/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | API_PORT = os.environ['API_PORT'] 4 | 5 | # Telegram configs 6 | api_id = os.environ['TG_API_ID'] 7 | api_hash = os.environ['TG_HASH_ID'] 8 | 9 | # Database configs 10 | DB_HOST = os.environ.get('DB_HOST') or 'localhost' 11 | DB_SESSION_DBNAME = "telethonsession" 12 | 13 | # Telethon Session settings 14 | TELETHON_SESSION_ID = 'synapticSupport' 15 | session_name_forwarder = 'synapticSupportForwarder' -------------------------------------------------------------------------------- /agent/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityathebe/telegramForwarder/d72e2264704f15ee5a78a14e11d50dc6be06519a/agent/db/__init__.py -------------------------------------------------------------------------------- /agent/db/database.py: -------------------------------------------------------------------------------- 1 | import psycopg2 2 | from config import DB_HOST 3 | 4 | 5 | class Database: 6 | def __init__(self): 7 | self.db = psycopg2.connect( 8 | host=DB_HOST, 9 | database="telegram", 10 | user="postgres", 11 | password="mysecretpassword") 12 | 13 | def get_user(self, user_id): 14 | cursor = self.db.cursor() 15 | sql = f"SELECT * FROM users WHERE chat_id = '{user_id}'" 16 | cursor.execute(sql) 17 | result = cursor.fetchone() 18 | cursor.close() 19 | return result 20 | 21 | def get_active_redirections_of_source(self, source): 22 | cursor = self.db.cursor() 23 | sql = f"SELECT * FROM redirections WHERE source = '{source}' AND active = TRUE" 24 | cursor.execute(sql) 25 | result = cursor.fetchall() 26 | cursor.close() 27 | return result 28 | 29 | def get_redirection(self, redirection_id): 30 | """" 31 | Get redirection of given redirection id 32 | """ 33 | cursor = self.db.cursor() 34 | sql = f"SELECT * FROM redirections WHERE id = '{redirection_id}' AND active = 1" 35 | cursor.execute(sql) 36 | result = cursor.fetchall() 37 | cursor.close() 38 | return result 39 | 40 | def get_all_redirections(self): 41 | cursor = self.db.cursor() 42 | sql = "SELECT * FROM redirections;" 43 | cursor.execute(sql) 44 | result = cursor.fetchall() 45 | cursor.close() 46 | return result 47 | 48 | def get_filter(self, filter_id): 49 | cursor = self.db.cursor() 50 | sql = f"SELECT * FROM filters WHERE id = {filter_id}" 51 | cursor.execute(sql) 52 | result = cursor.fetchone() 53 | cursor.close() 54 | return result 55 | 56 | def get_transformations_of_redirection(self, redirection_id): 57 | cursor = self.db.cursor() 58 | sql = f"SELECT * FROM transformations WHERE redirection_id = {redirection_id} ORDER BY rank" 59 | cursor.execute(sql) 60 | result = cursor.fetchall() 61 | cursor.close() 62 | return result 63 | -------------------------------------------------------------------------------- /agent/forwarder.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | from client import telegram_client 4 | from db.database import Database 5 | from utils.filter import MessageFilter 6 | from utils.transformation import MessageTransformation 7 | 8 | 9 | logger = logging.getLogger('Forwarder') 10 | database = Database() 11 | 12 | 13 | async def forwarder_event_handler(event): 14 | # Ignore Outgoing Message Updates 15 | if (event.out): 16 | return 17 | 18 | is_group = event.is_group 19 | is_channel = event.is_channel 20 | is_private = event.is_private 21 | message = event.message.message 22 | has_media = event.media 23 | sender_id = None 24 | 25 | if is_channel: 26 | logger.info('Channel Message Received') 27 | sender_id = event.message.to_id.channel_id 28 | 29 | elif is_group: 30 | logger.info('Group Message Received') 31 | sender_id = event.message.to_id.chat_id 32 | 33 | elif is_private: 34 | logger.info('Private Message Received') 35 | sender_id = event.from_id if has_media else event.original_update.user_id 36 | 37 | else: 38 | logger.info('Invalid Sender Type', event) 39 | 40 | logger.info(f'Message : {message}') 41 | logger.info(f'Sender : {sender_id}') 42 | 43 | # Mark as read (Optional) 44 | user_entity = await telegram_client.get_input_entity(sender_id) 45 | await telegram_client.send_read_acknowledge(user_entity, max_id=event.original_update.pts) 46 | 47 | # Get all Receivers of given userid 48 | try: 49 | redirections = database.get_active_redirections_of_source(sender_id) 50 | logger.info(f"Active Redirections: {json.dumps(redirections)}") 51 | for redirection in redirections: 52 | redirection_id = redirection[0] 53 | author_id = int(redirection[1]) 54 | source = int(redirection[2]) 55 | destination = int(redirection[3]) 56 | 57 | if source != sender_id: 58 | logger.info("Source != Sender") 59 | continue 60 | 61 | # Get User from database 62 | user = database.get_user(author_id) 63 | is_user_premium = user[4] 64 | 65 | # Allow premium users only 66 | if is_user_premium == 1: 67 | should_filter = MessageFilter.filter_msg(redirection_id, event) 68 | if should_filter: 69 | return 70 | 71 | if has_media: 72 | await telegram_client.send_file(destination, event.media, caption=message) 73 | else: 74 | transformed_message = MessageTransformation.get_transformed_msg( 75 | event, redirection_id) 76 | await telegram_client.send_message(destination, transformed_message) 77 | 78 | else: 79 | await telegram_client.forward_messages(destination, event.message.id, sender_id) 80 | logger.info(f'Message sent to {destination}') 81 | 82 | except Exception as err: 83 | logger.error(err) 84 | -------------------------------------------------------------------------------- /agent/readme.md: -------------------------------------------------------------------------------- 1 | # Getting Entity 2 | 3 | Entity can be a username or an invitation link. Possible scenarios 4 | 5 | #### 1. Invite Link : 6 | - [Error] The invite hash is invalid 7 | - [Error] Cannot get entity from a channel (or group) that you are not part of. Join the group and retry 8 | - [OK] Entity Detail Dictionary 9 | #### 2. Username : 10 | - [Error] No user has as username 11 | - [OK] Entity Detail Dictionary 12 | 13 | # Joining a source / destination 14 | 15 | ### Posible Source / destination 16 | 17 | - Bot 18 | - Private 19 | - Channel 20 | - [x] Public (username) 21 | - [x] Private (Invitation Link) 22 | - Group 23 | - [x] Public (username) 24 | - [x] Private (Invitation Link) 25 | 26 | ### Required functions 27 | 28 | - **ImportChatInviteRequest** : Join group / channel with invitation link 29 | - **JoinChannelRequest** : Join group / channel with username 30 | 31 | 32 | ### Procedure 33 | 34 | Example command 35 | ``` 36 | /add 37 | ``` 38 | 39 | #### 1. Check the entity format. 40 | - Usernames must start with '@" 41 | - Invitation links must start with 'https://t.me/joinchat' or 't.me/joinchat' 42 | - Should return a dictionary 43 | 44 | *Example Response* 45 | 46 | ```python 47 | # Response for username 48 | { 49 | 'username': 'adityathebe', 50 | } 51 | 52 | # Response for invitation link 53 | { 54 | 'hash': 'xyzjskdl123' 55 | } 56 | 57 | # If neither 58 | { 59 | 'error': 'Invalid hash' 60 | } 61 | 62 | ``` 63 | 64 | #### 2. Get both the entities from the API 65 | 66 | ```python 67 | client.get_entity(entity) 68 | ``` 69 | 70 | Need to make sure the entities are valid before we send a join request to them. 71 | 72 | > **NOTE:** This check is important because a request to join an entity where the agent is already a participant of will result in an error < *telethon.errors.rpcerrorlist.UserAlreadyParticipantError* >. 73 | 74 | #### 3. Send Join Request 75 | 76 | ```python 77 | # Private Entity 78 | client(ImportChatInviteRequest(hash)) 79 | 80 | # Public Entity 81 | client(JoinChannelRequest(entity)) 82 | ``` 83 | 84 | -------------------------------------------------------------------------------- /agent/requirements.txt: -------------------------------------------------------------------------------- 1 | Quart==0.13.0 2 | Telethon==1.16.2 3 | psycopg2==2.8.5 -------------------------------------------------------------------------------- /agent/server.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import telethon 3 | import hypercorn.asyncio 4 | from quart import Quart, request, render_template_string 5 | from telethon import TelegramClient, events 6 | from telethon.tl.functions.messages import ImportChatInviteRequest 7 | from telethon.tl.functions.channels import JoinChannelRequest 8 | from client import telegram_client 9 | from config import API_PORT 10 | from forwarder import forwarder_event_handler 11 | 12 | format_str = '[%(levelname)s] %(filename)s:%(lineno)s -- %(message)s' 13 | logging.basicConfig(level=logging.INFO, format=format_str) 14 | 15 | 16 | # Create Flask application instance 17 | app = Quart(__name__) 18 | 19 | 20 | @app.route('/') 21 | def index(): 22 | return "Telethon API is up and running" 23 | 24 | 25 | @app.route('/joinPublicUserEntity') 26 | async def joinPublicUserEntity(): 27 | """ 28 | Join Private Users 29 | """ 30 | entity = request.args.get('entity') 31 | 32 | app.logger.info('[/joinPublicUserEntity] :: Entity Name {}'.format(entity)) 33 | try: 34 | msg = '/start' 35 | result = await telegram_client.get_entity(entity) 36 | return result.to_dict() 37 | except Exception as exception: 38 | return {'error': str(exception)} 39 | 40 | 41 | @app.route('/joinPublicEntity') 42 | async def joinPublicEntity(): 43 | """ 44 | Join Public Groups & Channels 45 | """ 46 | entity = request.args.get('entity') 47 | app.logger.info('[/joinPublicEntity] :: Entity Name {}'.format(entity)) 48 | try: 49 | result = await telegram_client(JoinChannelRequest(entity)) 50 | return result.chats[0].to_dict() 51 | except telethon.errors.rpcerrorlist.UserAlreadyParticipantError: 52 | return {'success': 'ok'} 53 | except Exception as exception: 54 | return {'error': str(exception)} 55 | 56 | 57 | @app.route('/joinPrivateEntity') 58 | async def joinPrivateEntity(): 59 | """ 60 | Join Invation Link 61 | """ 62 | hash = request.args.get('hash') 63 | app.logger.info('[/joinPrivateEntity] :: Hash {}'.format(hash)) 64 | try: 65 | result = await telegram_client(ImportChatInviteRequest(hash)) 66 | return result.chats[0].to_dict() 67 | except telethon.errors.rpcerrorlist.UserAlreadyParticipantError: 68 | return {'succes': 'ok'} 69 | except Exception as exception: 70 | app.logger.error(exception) 71 | return {'error': str(exception)} 72 | 73 | 74 | @app.route('/getentity', methods=['GET']) 75 | async def getEntity(): 76 | entity = request.args.get('entity') 77 | is_entity_id = request.args.get('is_id') or '0' 78 | 79 | if (is_entity_id == '1'): 80 | entity = int(entity) 81 | 82 | app.logger.info('[/getentity] :: Entity Name {}'.format(entity)) 83 | try: 84 | result = await telegram_client.get_entity(entity) 85 | return result.to_dict() 86 | except Exception as exception: 87 | app.logger.error(exception) 88 | return {'error': str(exception)} 89 | 90 | 91 | @app.before_serving 92 | async def startup(): 93 | await telegram_client.connect() 94 | if await telegram_client.is_user_authorized(): 95 | user = await telegram_client.get_me() 96 | app.logger.info(f'Logged in as @{user.username}') 97 | 98 | 99 | @app.after_serving 100 | async def cleanup(): 101 | await telegram_client.disconnect() 102 | 103 | BASE_TEMPLATE = ''' 104 | 105 | 106 | 107 | 108 | Telethon + Quart 109 | 110 | {{ content | safe }} 111 | 112 | ''' 113 | 114 | PHONE_FORM = ''' 115 |
116 | Phone (international format): 117 | 118 |
119 | ''' 120 | 121 | CODE_FORM = ''' 122 |
123 | Telegram code: 124 | 125 |
126 | ''' 127 | 128 | phone = None 129 | @app.route('/login', methods=['GET', 'POST']) 130 | async def root(): 131 | # We want to update the global phone variable to remember it 132 | global phone 133 | 134 | # Check form parameters (phone/code) 135 | form = await request.form 136 | if 'phone' in form: 137 | phone = form['phone'] 138 | await telegram_client.send_code_request(phone) 139 | 140 | if 'code' in form: 141 | await telegram_client.sign_in(code=form['code']) 142 | 143 | # If we're logged in, show them some messages from their first dialog 144 | if await telegram_client.is_user_authorized(): 145 | user = await telegram_client.get_me() 146 | return f'Logged in as @{user.username}' 147 | 148 | # Ask for the phone if we don't know it yet 149 | if phone is None: 150 | return await render_template_string(BASE_TEMPLATE, content=PHONE_FORM) 151 | 152 | # We have the phone, but we're not logged in, so ask for the code 153 | return await render_template_string(BASE_TEMPLATE, content=CODE_FORM) 154 | 155 | 156 | async def main(): 157 | hypercorn_config = hypercorn.Config() 158 | hypercorn_config.bind = [f"0.0.0.0:{API_PORT}"] 159 | await hypercorn.asyncio.serve(app, hypercorn_config) 160 | 161 | 162 | if __name__ == "__main__": 163 | telegram_client.on(events.NewMessage)(forwarder_event_handler) 164 | telegram_client.loop.run_until_complete(main()) 165 | -------------------------------------------------------------------------------- /agent/session/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityathebe/telegramForwarder/d72e2264704f15ee5a78a14e11d50dc6be06519a/agent/session/.keep -------------------------------------------------------------------------------- /agent/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityathebe/telegramForwarder/d72e2264704f15ee5a78a14e11d50dc6be06519a/agent/utils/__init__.py -------------------------------------------------------------------------------- /agent/utils/filter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from db.database import Database 3 | 4 | logger = logging.getLogger('Filter') 5 | database = Database() 6 | 7 | 8 | class MessageFilter: 9 | 10 | @staticmethod 11 | def get_filter(filter_id): 12 | filter = database.get_filter(filter_id) 13 | if filter is None: 14 | return False 15 | 16 | filter_dict = { 17 | 'id': filter[0], 18 | 'audio': filter[1], 19 | 'video': filter[2], 20 | 'photo': filter[3], 21 | 'sticker': filter[4], 22 | 'document': filter[5], 23 | 'hashtag': filter[6], 24 | 'link': filter[7], 25 | 'contain': filter[8], 26 | 'notcontain': filter[9] 27 | } 28 | return filter_dict 29 | 30 | @staticmethod 31 | def get_active_filters(filter_dict): 32 | """ 33 | Takes in a filter dictionary 34 | Returns a list of active filter names 35 | Example: ('photo', 'audio') 36 | """ 37 | if not isinstance(filter_dict, dict): 38 | raise ValueError('Provide a dictionary') 39 | 40 | active_filter_list = [] 41 | for key, value in filter_dict.items(): 42 | if value != 0 and value is not None: 43 | if key != 'id': 44 | active_filter_list.append(key) 45 | 46 | return active_filter_list 47 | 48 | @staticmethod 49 | def get_message_type(event): 50 | 51 | # Photos Messages 52 | if hasattr(event.media, 'photo'): 53 | return 'photo' 54 | 55 | # Look for links and hashtags in event.entities 56 | if event.entities is not None: 57 | for entity in event.entities: 58 | entity_name = type(entity).__name__ 59 | 60 | if entity_name == 'MessageEntityHashtag': 61 | return 'hashtag' 62 | 63 | if entity_name == 'MessageEntityUrl': 64 | return 'link' 65 | 66 | # Text Messages 67 | if event.media == None: 68 | return 'text' 69 | 70 | # Documents (audio, video, sticker, files) 71 | mime_type = event.media.document.mime_type 72 | if 'audio' in mime_type: 73 | return 'audio' 74 | if 'video' in mime_type: 75 | return 'video' 76 | if 'image/webp' in mime_type: 77 | return 'sticker' 78 | 79 | # Anything else is a file 80 | return 'document' 81 | 82 | @staticmethod 83 | def filter_msg(filter_id, message_event): 84 | """ 85 | Function that decides if a message should be forwarded or not 86 | Returns Boolean 87 | """ 88 | 89 | # Get Filter dictionary from database 90 | filter_dict = MessageFilter.get_filter(filter_id) 91 | if filter_dict == False: 92 | logger.info('No filters for id : {}'.format(filter_id)) 93 | return False 94 | 95 | # Get Active Filter list 96 | filter_list = MessageFilter.get_active_filters(filter_dict) 97 | 98 | # Get Message Types 99 | msg_type = MessageFilter.get_message_type(message_event) 100 | msg_text = message_event.message.text.lower() 101 | 102 | if msg_type in filter_list: 103 | logger.info(f'Filter caught :: {msg_type}') 104 | return True 105 | 106 | if 'contain' not in filter_list and 'notcontain' not in filter_list: 107 | logger.info('All filters passed.') 108 | return False 109 | 110 | # Assume message does not contain the required word 111 | contains_required_word = False 112 | if 'contain' in filter_list: 113 | # Look for text messages only 114 | if message_event.media is not None: 115 | return False 116 | keywords = filter_dict['contain'].split('') 117 | for keyword in keywords: 118 | if keyword in msg_text: 119 | contains_required_word = True 120 | break 121 | 122 | # Assume message does contain the blacklist word 123 | contains_blacklist_word = False 124 | if 'notcontain' in filter_list: 125 | # Look for text messages only 126 | if message_event.media is not None: 127 | return False 128 | keywords = filter_dict['notcontain'].split('') 129 | for keyword in keywords: 130 | if keyword in msg_text: 131 | contains_blacklist_word = True 132 | break 133 | 134 | logger.info('Contains word :: {} && Contains Blacklist :: {}'.format( 135 | contains_required_word, contains_blacklist_word)) 136 | return (not contains_required_word) or contains_blacklist_word 137 | -------------------------------------------------------------------------------- /agent/utils/transformation.py: -------------------------------------------------------------------------------- 1 | from db.database import Database 2 | 3 | # Connect to database 4 | database = Database() 5 | 6 | 7 | class MessageTransformation: 8 | 9 | @staticmethod 10 | def get_transformed_msg(message_event, redirection_id): 11 | transformations = database.get_transformations_of_redirection( 12 | redirection_id) 13 | 14 | # Apply Transformation 15 | msg_entities = message_event.message.entities 16 | msg_txt = message_event.message.message 17 | 18 | for transformation in transformations: 19 | old_phrase = transformation[2] 20 | new_phrase = transformation[3] 21 | msg_txt = msg_txt.replace(old_phrase, new_phrase) 22 | 23 | return msg_txt 24 | 25 | 26 | if __name__ == "__main__": 27 | msg = 'hi there. I love violin' 28 | resp = MessageTransformation.get_transformed_msg(msg, 41) 29 | print(resp) 30 | -------------------------------------------------------------------------------- /bot/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "trailingComma": "es5", 6 | "printWidth": 120, 7 | "arrowParens": "avoid" 8 | } 9 | -------------------------------------------------------------------------------- /bot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-jessie 2 | 3 | RUN apt-get update 4 | 5 | RUN apt-get install -y netcat 6 | 7 | WORKDIR /usr/src/telegram-forwarder/bot 8 | 9 | COPY package*.json ./ 10 | 11 | RUN npm install 12 | 13 | COPY . . 14 | 15 | CMD ["node", "bot.js"] -------------------------------------------------------------------------------- /bot/bot.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const pino = require('pino'); 3 | const { v4: uuidv4 } = require('uuid'); 4 | const EventEmitter = require('events').EventEmitter; 5 | 6 | const db = require('./db/database'); 7 | const bot = require('./services/telegram'); 8 | const MessageParser = require('./controllers/message/parser'); 9 | 10 | // Controllers 11 | const addFilter = require('./controllers/addFilter'); 12 | const getFilter = require('./controllers/getFilter'); 13 | const addRedirection = require('./controllers/addRedirection'); 14 | const activateRedirection = require('./controllers/activateRedirection'); 15 | const removeRedirection = require('./controllers/removeRedirection'); 16 | const deactivateRedirection = require('./controllers/deactivateRedirection'); 17 | const addTransformation = require('./controllers/addTransformation'); 18 | // const swapTransformationRank = require('../swapTransformationRank'); 19 | const getTransformations = require('./controllers/getTransformations'); 20 | const removeTransformation = require('./controllers/removeTransformation'); 21 | 22 | const logger = pino({ level: process.env.LOG_LEVEL || 'info' }); 23 | class CommandHandler extends EventEmitter {} 24 | const commandHandler = new CommandHandler(); 25 | 26 | bot.onText(new RegExp('^/start$'), async msgEvent => { 27 | let reply = 'Welcome to MultiFeed Bot! 🔥\n\n'; 28 | reply += 'Send /help to get usage instructions'; 29 | bot.sendMessage(msgEvent.chat.id, reply).catch(logger.error); 30 | 31 | // Store User to Database 32 | try { 33 | await db.saveUser(msgEvent.chat.id, msgEvent.from.username, uuidv4()); 34 | } catch (err) { 35 | logger.error(err); 36 | } 37 | }); 38 | 39 | bot.onText(new RegExp('^/help$'), msgEvent => { 40 | let reply = 'Typical workflow in the bot:\n\n'; 41 | reply += '1. You have two links:\n'; 42 | reply += '- `SOURCE` - link to the channel to forward messages FROM'; 43 | reply += '(no admin permissions required)\n'; 44 | reply += '- `DESTINATION` - link to the channel to forward messages TO'; 45 | reply += '(you can add new admins there)\n\n'; 46 | reply += '2. You use `/add` command to create a new redirection from '; 47 | reply += '`SOURCE` channel to your `DESTINATION` channel\n\n'; 48 | reply += '3. You give posting permissions in `DESTINATION` channel TO THE '; 49 | reply += 'ACCOUNT that was specified after successful execution of step #2'; 50 | reply += '\n\n'; 51 | reply += '4. You activate the newly created redirection using `/activate` '; 52 | reply += 'command\n\n'; 53 | reply += 'Having all 4 steps completed, you can enjoy automatic messages '; 54 | reply += 'forwarding from `SOURCE` to `DESTINATION` 🔥'; 55 | return bot 56 | .sendMessage(msgEvent.chat.id, reply, { 57 | parse_mode: 'Markdown', 58 | }) 59 | .catch(console.error); 60 | }); 61 | 62 | bot.on('message', msgEvent => { 63 | if (msgEvent.chat.type == 'private') { 64 | // Parse Command 65 | // Check Commands with MessageParser 66 | const isValidCommand = MessageParser.isValidCommand(msgEvent.text); 67 | if (!isValidCommand) { 68 | const reply = '❌ Command does not exist.\n\nType /help'; 69 | return bot.sendMessage(msgEvent.chat.id, reply).catch(console.error); 70 | } 71 | 72 | const command = MessageParser.getCommand(msgEvent.text); 73 | 74 | // Commands that are handled elsewhere 75 | const reservedCommands = ['/help', '/start']; 76 | if (reservedCommands.includes(command)) return; 77 | 78 | const parser = MessageParser.hashMap()[command]; 79 | const parsedMsg = parser(msgEvent.text, msgEvent); 80 | 81 | if (parsedMsg.error) { 82 | const reply = `❌ Error in command : ${parsedMsg.command}\n\n**${parsedMsg.error}**`; 83 | return bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'Markdown' }).catch(console.error); 84 | } 85 | 86 | commandHandler.emit(command, parsedMsg, msgEvent); 87 | } 88 | }); 89 | 90 | commandHandler.on('/add', async (data, msgEvent) => { 91 | console.log('Adding redirection'); 92 | try { 93 | const { error } = await addRedirection(msgEvent.chat.id, data.source, data.destination); 94 | if (error) { 95 | return bot 96 | .sendMessage(msgEvent.chat.id, error, { 97 | parse_mode: 'HTML', 98 | }) 99 | .catch(e => console.error(e.message)); 100 | } 101 | const reply = `✔ New Redirection added`; 102 | return bot.sendMessage(msgEvent.chat.id, reply, { 103 | parse_mode: 'HTML', 104 | }); 105 | } catch (err) { 106 | console.error(err); 107 | const reply = err.message || err || 'Some error occured'; 108 | bot 109 | .sendMessage(msgEvent.chat.id, '❌ ' + reply, { 110 | parse_mode: 'HTML', 111 | }) 112 | .catch(console.error); 113 | } 114 | }); 115 | 116 | commandHandler.on('/activate', async (data, msgEvent) => { 117 | console.log('Activating redirection'); 118 | try { 119 | await activateRedirection(msgEvent.chat.id, data.redirectionId); 120 | const reply = `Redirection activated [${data.redirectionId}]`; 121 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 122 | } catch (err) { 123 | const reply = err.message || err || 'Some error occured'; 124 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 125 | } 126 | }); 127 | 128 | commandHandler.on('/list', async (data, msgEvent) => { 129 | try { 130 | const redirections = await db.getRedirections(msgEvent.chat.id); 131 | if (redirections.length === 0) { 132 | return bot 133 | .sendMessage(msgEvent.chat.id, 'You have no redirections', { parse_mode: 'HTML' }) 134 | .catch(err => console.log(err)); 135 | } 136 | 137 | let reply = ''; 138 | redirections.forEach(redirection => { 139 | let state = redirection.active == 1 ? '🔵' : '🔴'; 140 | reply += `--- ${state} [${redirection.id}] ${redirection.source_title} => ${redirection.destination_title}\n`; 141 | }); 142 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(err => console.log(err)); 143 | } catch (err) { 144 | console.log(err); 145 | bot.sendMessage(msgEvent.chat.id, err, { parse_mode: 'HTML' }); 146 | } 147 | }); 148 | 149 | commandHandler.on('/deactivate', async (data, msgEvent) => { 150 | try { 151 | await deactivateRedirection(msgEvent.chat.id, data.redirectionId); 152 | const reply = `Redirection deactivated [${data.redirectionId}]`; 153 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 154 | } catch (err) { 155 | const reply = err.message || err || 'Some error occured'; 156 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 157 | } 158 | }); 159 | 160 | commandHandler.on('/remove', async (data, msgEvent) => { 161 | try { 162 | await removeRedirection(msgEvent.chat.id, data.redirectionId); 163 | const reply = `Redirection removed [${data.redirectionId}]`; 164 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 165 | } catch (err) { 166 | const reply = err.message || err || 'Some error occured'; 167 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 168 | } 169 | }); 170 | 171 | commandHandler.on('/filter', async (data, msgEvent) => { 172 | try { 173 | const { error, filterData } = await addFilter(msgEvent.chat.id, data); 174 | if (error) { 175 | bot.sendMessage(msgEvent.chat.id, error).catch(logger.error); 176 | return; 177 | } 178 | let reply = `✅ Command Success.\n\n`; 179 | reply += `- Redirection id : [${filterData.redirectionId}]\n`; 180 | reply += `- Filter Name : ${filterData.name}\n`; 181 | reply += `- Filter State : ${filterData.state}`; 182 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 183 | } catch (err) { 184 | const reply = err.message || err || 'Some error occured'; 185 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(console.error); 186 | } 187 | }); 188 | 189 | commandHandler.on('/filters', async (data, msgEvent) => { 190 | try { 191 | const { filter, error } = await getFilter(msgEvent.chat.id, data.filterId); 192 | if (error) { 193 | bot.sendMessage(msgEvent.chat.id, error, { parse_mode: 'HTML' }).catch(err => logger.error(err)); 194 | return; 195 | } 196 | 197 | let reply = `✅ Filters for redirection [${filter.id}]\n\n`; 198 | reply += ''; 199 | reply += `- ${filter.audio ? '🔵' : '🔴'} audio\n`; 200 | reply += `- ${filter.video ? '🔵' : '🔴'} video\n`; 201 | reply += `- ${filter.photo ? '🔵' : '🔴'} photo\n`; 202 | reply += `- ${filter.sticker ? '🔵' : '🔴'} sticker\n`; 203 | reply += `- ${filter.document ? '🔵' : '🔴'} document\n`; 204 | reply += `- ${filter.hashtag ? '🔵' : '🔴'} hashtag\n`; 205 | reply += `- ${filter.link ? '🔵' : '🔴'} link\n`; 206 | reply += `- ${filter.contain ? '🔵' : '🔴'} contain = ${ 207 | filter.contain ? filter.contain.replace(//g, ', ') : null 208 | }\n`; 209 | reply += `- ${filter.notcontain ? '🔵' : '🔴'} notcontain = ${ 210 | filter.notcontain ? filter.notcontain.replace('', ', ') : null 211 | }`; 212 | reply += ''; 213 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(err => logger.error(err)); 214 | } catch (err) { 215 | logger.error(err); 216 | bot.sendMessage(msgEvent.chat.id, '❌ Some error occured').catch(err => logger.error(err)); 217 | } 218 | }); 219 | 220 | commandHandler.on('/transform', async (data, msgEvent) => { 221 | try { 222 | const response = await addTransformation(msgEvent.chat.id, data.redirectionId, data.oldPhrase, data.newPhrase); 223 | const reply = `New transformation added with id ${response.transformationId}`; 224 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(err => logger.error(err)); 225 | } catch (err) { 226 | logger.error(err); 227 | bot.sendMessage(msgEvent.chat.id, `❌ ${err}`).catch(err => logger.error(err)); 228 | } 229 | }); 230 | 231 | commandHandler.on('/transforms', async (data, msgEvent) => { 232 | try { 233 | const transformations = await getTransformations(msgEvent.chat.id, data.redirectionId); 234 | if (transformations.length == 0) { 235 | const reply = 'No transformation found.'; 236 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(err => logger.error(err)); 237 | } else { 238 | let reply = `Transformations for redirection [${data.redirectionId}]\n\n`; 239 | reply += 'ID | Rank | Old Phrase | New Phrase\n'; 240 | transformations.forEach(transformation => { 241 | reply += `${transformation.id}. [${transformation.rank}] ${transformation.old_phrase} ==> ${transformation.new_phrase}\n`; 242 | }); 243 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(err => logger.error(err)); 244 | } 245 | } catch (err) { 246 | logger.error(err); 247 | bot.sendMessage(msgEvent.chat.id, `❌ ${err}`).catch(err => logger.error(err)); 248 | } 249 | }); 250 | 251 | commandHandler.on('/transformremove', async (data, msgEvent) => { 252 | try { 253 | await removeTransformation(msgEvent.chat.id, data.transformationId); 254 | const reply = `✔ Transformation removed ${data.transformationId}`; 255 | bot.sendMessage(msgEvent.chat.id, reply, { parse_mode: 'HTML' }).catch(err => logger.error(err)); 256 | } catch (err) { 257 | logger.error(err); 258 | bot.sendMessage(msgEvent.chat.id, `❌ ${err}`).catch(err => logger.error(err)); 259 | } 260 | }); 261 | 262 | // } else if (command === '/transformrank') { 263 | // try { 264 | // await swapTransformationRank( 265 | // sender, 266 | // parsedMsg.redirectionId, 267 | // parsedMsg.rank1, 268 | // parsedMsg.rank2 269 | // ); 270 | // let reply = `Transformation rank swapped for redirection id \`${parsedMsg.redirectionId}\`\n\n`; 271 | // reply += `\`${parsedMsg.rank1} <==> ${parsedMsg.rank2}\``; 272 | // bot 273 | // .send_message(sender, reply, 'markdown') 274 | // .catch(err => console.log(err)); 275 | // } catch (err) { 276 | // const reply = err.message || err || 'Some error occured'; 277 | // bot.send_message(sender, reply).catch(err => console.log(err)); 278 | // } 279 | 280 | if (require.main === module) { 281 | bot.on('message', msg => logger.info(msg)); 282 | bot.on('polling_error', err => logger.error(err)); 283 | bot.startPolling(); 284 | } 285 | -------------------------------------------------------------------------------- /bot/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | PORT: process.env.PORT || 3000, 3 | DB_HOST: process.env.DB_HOST || 'localhost', 4 | AGENT_HOSTNAME: process.env.AGENT_HOSTNAME || 'localhost', 5 | AGENT_PORT: process.env.AGENT_PORT || 3000, 6 | TG: { 7 | TG_API_KEY: process.env.TG_API_KEY, 8 | TG_BOT_USERNAME: process.env.TG_BOT_USERNAME, 9 | }, 10 | APP: { 11 | FREE_USER: { 12 | QUOTA_LIMIT: 10, 13 | }, 14 | PREMIUM_USER: { 15 | QUOTA_LIMIT: 0, 16 | }, 17 | }, 18 | }; 19 | 20 | module.exports = config; 21 | -------------------------------------------------------------------------------- /bot/controllers/activateRedirection.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | const ForwardAgent = require('../services/agent'); 3 | const { TG_BOT_USERNAME } = require('../config').TG; 4 | 5 | /** 6 | * Activates a redirection 7 | * @param {String} sender Chat id of the owner 8 | * @param {String} redirectionId Redirection Id 9 | */ 10 | const activateRedirection = async (sender, redirectionId) => { 11 | ///////////////////////////////////////////// 12 | // Sender must be the owner of redirection // 13 | ///////////////////////////////////////////// 14 | const redirections = await database.getRedirections(sender); 15 | let redirectionOfInterest = redirections.filter(redirection => redirection.id == redirectionId); 16 | if (redirectionOfInterest.length === 0) { 17 | throw new Error('Redirection does not exist'); 18 | } 19 | 20 | ///////////////////////////////////////////// 21 | // If destination is Channel or Supergroup // 22 | // Should have admin rights // 23 | ///////////////////////////////////////////// 24 | const destId = redirectionOfInterest[0].destination; 25 | const entity = await ForwardAgent.getEntity(destId, { is_id: true }); 26 | if (entity.entity.type === 'channel' && entity.entity.megagroup === false) { 27 | if (!entity.entity.adminRights) { 28 | const errMsg = `Please provide admin rights to ${TG_BOT_USERNAME} on ${redirectionOfInterest[0].destination_title}`; 29 | throw new Error(errMsg); 30 | } 31 | } 32 | 33 | //////////////////////// 34 | // Update to database // 35 | //////////////////////// 36 | await database.activateRedirection(redirectionId); 37 | }; 38 | 39 | module.exports = activateRedirection; 40 | -------------------------------------------------------------------------------- /bot/controllers/addFilter.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | /** 4 | * Activates a redirection 5 | * @param {String} sender Chat id of the owner 6 | * @param {String} filterData.redirectionId Redirection Id 7 | * @param {String} filterData.name Filter name 8 | * @param {String} filterData.state Filter state 9 | * @param {Array} filterData.keywords Keywords if filter is contain or notcontain 10 | * @typedef {Object} AddFilterResponse 11 | * @property {string} error - Error Message 12 | * @property {Object} filterData - Filter Object 13 | * @returns {AddFilterResponse} 14 | */ 15 | const addFilter = async (sender, filterData) => { 16 | ///////////////////////////////////////////// 17 | // Sender must be the owner of redirection // 18 | ///////////////////////////////////////////// 19 | const redirections = await database.getRedirections(sender); 20 | let redirectionOfInterest = redirections.filter(redirection => redirection.id == filterData.redirectionId); 21 | if (redirectionOfInterest.length === 0) return { error: '⚠ Redirection doesnot exist' }; 22 | 23 | //////////////////////////////////////////// 24 | // If Filtername is contain or notcontain // 25 | //////////////////////////////////////////// 26 | if (filterData.name === 'contain' || filterData.name === 'notcontain') { 27 | const keywords = filterData.keywords ? filterData.keywords.join('') : null; 28 | await database.saveFilter(filterData.redirectionId, filterData.name, keywords); 29 | return { filterData }; 30 | } else { 31 | const filterState = filterData.state === 'on' ? 1 : 0; 32 | await database.saveFilter(filterData.redirectionId, filterData.name, filterState); 33 | return { filterData }; 34 | } 35 | }; 36 | 37 | module.exports = addFilter; 38 | 39 | if (require.main === module) { 40 | addFilter('451722605', { 41 | redirectionId: 41, 42 | state: 'on', 43 | keywords: ['hi', 'there', 'how are you ?'], 44 | name: 'contain', 45 | }) 46 | .then(x => console.log(x)) 47 | .catch(x => console.log(x)); 48 | } 49 | -------------------------------------------------------------------------------- /bot/controllers/addRedirection.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | const ForwardAgent = require('../services/agent'); 3 | const QUOTA_LIMIT = require('../config/').APP.FREE_USER.QUOTA_LIMIT; 4 | 5 | /** 6 | * Verifies that the source/destination is in one of the two valid formats 7 | * -- If it's a public entity (username), it should start with "@" 8 | * -- If it's a private entity (invitation link), it should start with t.me/joinchat/ 9 | * @param {string} entity username or invitation link 10 | * @returns {Object} 11 | */ 12 | const checkSourcePattern = entity => { 13 | if (entity.indexOf('@') === 0) return { username: entity }; 14 | if (entity.indexOf('t.me/joinchat/') === 0) return { hash: entity.replace('t.me/joinchat/', '') }; 15 | if (entity.indexOf('https://t.me/joinchat/') === 0) return { hash: entity.replace('https://t.me/joinchat/', '') }; 16 | throw new Error('Invalid format'); 17 | }; 18 | 19 | /** 20 | * Adds a redirection 21 | * @param {String} sender Chat id of the owner 22 | * @param {String} source Username / Link of Source 23 | * @param {String} destination Username / Link of Destination 24 | */ 25 | const addRedirection = async (sender, source, destination) => { 26 | ///////////////////////////////////////////////// 27 | // Validate and get Source && Destination type // 28 | ///////////////////////////////////////////////// 29 | let sourceType, destinationType; 30 | try { 31 | sourceType = checkSourcePattern(source); 32 | destinationType = checkSourcePattern(destination); 33 | } catch (error) { 34 | console.log(error); 35 | if (error) return { error: error.message }; 36 | } 37 | 38 | ///////////////// 39 | // Quota Check // 40 | ///////////////// 41 | const userRecord = await database.getUser(sender); 42 | if (!userRecord) { 43 | return { 44 | error: 'You are not registered. Please send /start to register', 45 | }; 46 | } 47 | const userIsPremium = userRecord.premium == '1' ? true : false; 48 | if (!userIsPremium) { 49 | if (userRecord.quota >= QUOTA_LIMIT) { 50 | return { 51 | error: 'You have reached your quota limit. Please upgrade your account.', 52 | }; 53 | } 54 | } 55 | 56 | /////////////////////////////////////// 57 | // Get Entities // 58 | // If not joinable, will throw Error // 59 | /////////////////////////////////////// 60 | let sourceEntity = await ForwardAgent.getEntity(source); 61 | let destinationEntity = await ForwardAgent.getEntity(destination); 62 | 63 | ////////////////////////// 64 | // Join agent to source // 65 | ////////////////////////// 66 | let joinSrcRequestResponse = null; 67 | if (sourceType.username) { 68 | if (sourceEntity.entity.type === 'user') { 69 | joinSrcRequestResponse = await ForwardAgent.joinPublicUserEntity(sourceType.username); 70 | } else { 71 | joinSrcRequestResponse = await ForwardAgent.joinPublicEntity(sourceType.username); 72 | } 73 | } else if (sourceType.hash) { 74 | joinSrcRequestResponse = await ForwardAgent.joinPrivateEntity(sourceType.hash); 75 | } 76 | if (joinSrcRequestResponse.error) return { error: joinSrcRequestResponse.error }; 77 | 78 | /////////////////////////////// 79 | // Join agent to destination // 80 | /////////////////////////////// 81 | let joinDestRequestResponse = null; 82 | if (destinationType.username) { 83 | if (destinationEntity.entity.type === 'user') { 84 | joinDestRequestResponse = await ForwardAgent.joinPublicUserEntity(destinationType.username); 85 | } else { 86 | joinDestRequestResponse = await ForwardAgent.joinPublicEntity(destinationType.username); 87 | } 88 | } else if (destinationType.hash) { 89 | joinDestRequestResponse = await ForwardAgent.joinPrivateEntity(destinationType.hash); 90 | } 91 | if (joinDestRequestResponse.error) return { error: joinDestRequestResponse.error }; 92 | 93 | ///////////////////////////////////////////////////////////////// 94 | // We cannot get entity from an invitation link before joining // 95 | // Now that we have joined, we can get the entity // 96 | ///////////////////////////////////////////////////////////////// 97 | if (sourceEntity.entity === null) { 98 | sourceEntity = await ForwardAgent.getEntity(source); 99 | } 100 | if (destinationEntity.entity === null) { 101 | destinationEntity = await ForwardAgent.getEntity(destination); 102 | } 103 | ////////////////////////// 104 | // No Duplicate Entries // 105 | // No Circular Entries // 106 | ////////////////////////// 107 | const allRedirections = await database.getRedirections(sender); 108 | for (const redirection of allRedirections) { 109 | const source = redirection.source; 110 | const destination = redirection.destination; 111 | 112 | if (source == sourceEntity.entity.chatId && destination == destinationEntity.entity.chatId) { 113 | return { error: `Redirection already exists with id [${redirection.id}] ` }; 114 | } 115 | 116 | if (source == destinationEntity.entity.chatId && destination == sourceEntity.entity.chatId) { 117 | return { error: `Circular redirection is not allowed [${redirection.id}]` }; 118 | } 119 | } 120 | 121 | /////////////////////// 122 | // Store to database // 123 | // Increase Quota // 124 | /////////////////////// 125 | const srcId = sourceEntity.entity.chatId; 126 | const destId = destinationEntity.entity.chatId; 127 | const srcTitle = sourceEntity.entity.title; 128 | const destTitle = destinationEntity.entity.title; 129 | await database.saveRedirection(sender, srcId, destId, srcTitle, destTitle); 130 | await database.changeUserQuota(sender); 131 | return { success: true }; 132 | }; 133 | 134 | module.exports = addRedirection; 135 | -------------------------------------------------------------------------------- /bot/controllers/addTransformation.js: -------------------------------------------------------------------------------- 1 | const pino = require('pino'); 2 | 3 | const database = require('../db/database'); 4 | const logger = pino({ level: process.env.LOG_LEVEL || 'info' }); 5 | 6 | const addTransformation = async (sender, redirectionId, oldPhrase, newPhrase) => { 7 | ///////////////////////////////////////////// 8 | // Sender must be the owner of redirection // 9 | ///////////////////////////////////////////// 10 | const redirections = await database.getRedirections(sender); 11 | let redirectionOfInterest = redirections.filter(redirection => redirection.id == redirectionId); 12 | if (redirectionOfInterest.length === 0) throw Error('Redirection does not exist'); 13 | 14 | ///////////////////////////////////////////////// 15 | // Fetch Transformations for given redirection // 16 | // To determine the rank of transformation // 17 | ///////////////////////////////////////////////// 18 | const transformations = await database.getTransformationsOfRedirection(redirectionId); 19 | const currentHighestRank = transformations.reduce((prevVal, curVal, curIndex) => { 20 | return curVal.rank > prevVal ? curVal.rank : prevVal; 21 | }, -1); 22 | const rankOfNewTransformation = currentHighestRank + 1; 23 | 24 | ///////////////////// 25 | // Update database // 26 | ///////////////////// 27 | console.log({ redirectionId, oldPhrase, newPhrase, rankOfNewTransformation, sender }); 28 | const dbResponse = await database.saveTransformation(redirectionId, oldPhrase, newPhrase, rankOfNewTransformation); 29 | return { redirectionId, transformationId: dbResponse.rows[0].id }; 30 | }; 31 | 32 | module.exports = addTransformation; 33 | -------------------------------------------------------------------------------- /bot/controllers/deactivateRedirection.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | /** 4 | * Activates a redirection 5 | * @param {String} sender Chat id of the owner 6 | * @param {String} redirectionId Redirection Id 7 | */ 8 | const deactivateRedirection = (sender, redirectionId) => { 9 | return new Promise(async (resolve, reject) => { 10 | try { 11 | ///////////////////////////////////////////// 12 | // Sender must be the owner of redirection // 13 | ///////////////////////////////////////////// 14 | const redirections = await database.getRedirections(sender); 15 | let redirectionOfInterest = redirections.filter((redirection) => redirection.id == redirectionId) 16 | if (redirectionOfInterest.length === 0) throw Error('Redirection doesnot exist'); 17 | 18 | //////////////////////// 19 | // Update to database // 20 | //////////////////////// 21 | const dbResponse = await database.deactivateRedirection(redirectionId); 22 | return resolve({ redirection: redirectionOfInterest[0], dbResponse }); 23 | } catch (err) { 24 | reject(err); 25 | } 26 | }) 27 | } 28 | 29 | module.exports = deactivateRedirection; 30 | 31 | if (require.main === module) { 32 | deactivateRedirection('451722605', '39') 33 | .then(x => console.log(x)) 34 | .catch(x => console.log(x)) 35 | } -------------------------------------------------------------------------------- /bot/controllers/getFilter.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | /** 4 | * @param {String} sender Sender Chat id 5 | * @param {String} filterId Filter Id 6 | * @typedef {Object} GetFilterResponse 7 | * @property {string} error - Error Message 8 | * @property {Object} filter - Filter Object 9 | * @returns {GetFilterResponse} 10 | */ 11 | const getFilter = async (sender, filterId) => { 12 | ///////////////////////////////////////////// 13 | // Sender must be the owner of redirection // 14 | // Linked with the given filter // 15 | ///////////////////////////////////////////// 16 | const redirections = await database.getRedirections(sender); 17 | const redirectionOfInterest = redirections.filter(redirection => redirection.id == filterId); 18 | if (redirectionOfInterest.length === 0) return { error: '⚠ Filter does not exist' }; 19 | 20 | //////////////// 21 | // Get Filter // 22 | //////////////// 23 | const filter = await database.getFilter(filterId); 24 | if (!filter) return { error: '⚠ You have no filters' }; 25 | return { filter }; 26 | }; 27 | 28 | module.exports = getFilter; 29 | -------------------------------------------------------------------------------- /bot/controllers/getTransformations.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | const getTransformations = async (sender, redirectionId) => { 4 | ///////////////////////////////////////////// 5 | // Sender must be the owner of redirection // 6 | // Linked with the given transformations // 7 | ///////////////////////////////////////////// 8 | const redirections = await database.getRedirections(sender); 9 | const redirectionOfInterest = redirections.filter(redirection => redirection.id == redirectionId); 10 | if (redirectionOfInterest.length === 0) throw Error('Redirection does not exist'); 11 | 12 | ///////////////////////// 13 | // Get transformations // 14 | ///////////////////////// 15 | return await database.getTransformationsOfRedirection(redirectionId); 16 | }; 17 | 18 | module.exports = getTransformations; 19 | -------------------------------------------------------------------------------- /bot/controllers/message/parser.js: -------------------------------------------------------------------------------- 1 | const validCommands = [ 2 | '/add', 3 | '/remove', 4 | '/list', 5 | '/activate', 6 | '/deactivate', 7 | '/help', 8 | '/ref', 9 | '/filters', 10 | '/filter', 11 | '/transform', 12 | '/start', 13 | '/transforms', 14 | '/transformrank', 15 | '/transformremove', 16 | ]; 17 | 18 | // Command Error Constructor Function 19 | const commandError = (command, errorMsg) => { 20 | return { 21 | command, 22 | error: errorMsg, 23 | }; 24 | }; 25 | 26 | const addMessageEntities = messageEvent => { 27 | const entities = messageEvent.entities; 28 | let msgText = messageEvent.text; 29 | let addedOffset = 0; 30 | 31 | entities.forEach(entity => { 32 | const entityType = entity.type; 33 | let offset = entity.offset + addedOffset; 34 | let length = offset + entity.length; 35 | 36 | if (entityType === 'pre') { 37 | msgText = msgText.slice(0, offset) + '```' + msgText.slice(offset); 38 | length += 3; 39 | msgText = msgText.slice(0, length) + '```' + msgText.slice(length); 40 | addedOffset += 6; 41 | } else if (entityType === 'bold') { 42 | msgText = msgText.slice(0, offset) + '**' + msgText.slice(offset); 43 | length += 2; 44 | msgText = msgText.slice(0, length) + '**' + msgText.slice(length); 45 | addedOffset += 4; 46 | } else if (entityType === 'italic') { 47 | msgText = msgText.slice(0, offset) + '__' + msgText.slice(offset); 48 | length += 2; 49 | msgText = msgText.slice(0, length) + '__' + msgText.slice(length); 50 | addedOffset += 4; 51 | } else if (entityType === 'code') { 52 | msgText = msgText.slice(0, offset) + '`' + msgText.slice(offset); 53 | length += 1; 54 | msgText = msgText.slice(0, length) + '`' + msgText.slice(length); 55 | addedOffset += 2; 56 | } 57 | }); 58 | 59 | return msgText; 60 | }; 61 | 62 | ///////////////////////////// 63 | // Transformations Command // 64 | ///////////////////////////// 65 | 66 | // Remove Transformation 67 | const parseCommandTransformRemove = message => { 68 | const msgArr = message.trim().split(' '); 69 | if (msgArr.length !== 2) { 70 | let errMsg = 'Should contain 1 parameter.\n\n'; 71 | errMsg += '`/transformremove \n`'; 72 | return commandError(msgArr[0], errMsg); 73 | } 74 | return { 75 | transformationId: msgArr[1], 76 | }; 77 | }; 78 | 79 | // List Transformations 80 | const parseCommandTransforms = message => { 81 | const msgArr = message.trim().split(' '); 82 | if (msgArr.length !== 2) { 83 | let errMsg = 'Should contain 1 parameter.\n\n'; 84 | errMsg += '`/transforms \n`'; 85 | return commandError(msgArr[0], errMsg); 86 | } 87 | return { 88 | redirectionId: msgArr[1], 89 | }; 90 | }; 91 | 92 | // Add Transformation 93 | const parseCommandTransform = (message, messageEvent) => { 94 | message = addMessageEntities(messageEvent); 95 | const msgArrOfLines = message.trim().split('\n'); 96 | const msgArr = msgArrOfLines[0].trim().replace(/\n/g, '').split(' '); 97 | if (msgArrOfLines.length !== 3 || msgArr.length !== 2) { 98 | let errMsg = 'Should contain 3 parameters.\n\n'; 99 | errMsg += '`/transform \n`'; 100 | errMsg += '`\n`\n\n'; 101 | errMsg += 'Example: \n\n'; 102 | errMsg += '`/transform 1\njustin bieber\nFreddie Mercury`'; 103 | return commandError(msgArr[0], errMsg); 104 | } 105 | return { 106 | redirectionId: msgArr[1], 107 | oldPhrase: msgArrOfLines[1], 108 | newPhrase: msgArrOfLines[2], 109 | }; 110 | }; 111 | 112 | // Swap rank of transformations 113 | const parseCommandTransformRank = message => { 114 | const msgArr = message.trim().split(' '); 115 | if (msgArr.length !== 4) { 116 | let errMsg = 'Should contain 3 parameters.\n\n'; 117 | errMsg += '`/transformrank \n\n`'; 118 | errMsg += 'Example: \n\n'; 119 | errMsg += '`/transform 100 2 3`'; 120 | return commandError(msgArr[0], errMsg); 121 | } 122 | 123 | return { 124 | redirectionId: msgArr[1], 125 | rank1: msgArr[2], 126 | rank2: msgArr[3], 127 | }; 128 | }; 129 | 130 | ////////////////////////// 131 | // Redirection commands // 132 | ////////////////////////// 133 | 134 | // Add Redirection 135 | const parseCommandAdd = message => { 136 | const msgArr = message.trim().split(' '); 137 | let errMsg = 'Should contain 2 parameters.\n\n'; 138 | errMsg += '`/add @youtube @google\n/add https://t.me/joinchat @facebook`'; 139 | if (msgArr.length !== 3) return commandError(msgArr[0], errMsg); 140 | return { 141 | source: msgArr[1], 142 | destination: msgArr[2], 143 | }; 144 | }; 145 | 146 | // Remove Redirection 147 | const parseCommandRemove = message => { 148 | const msgArr = message.trim().split(' '); 149 | let errMsg = 'Should contain 1 parameter.\n\n'; 150 | errMsg += '`/remove `'; 151 | if (msgArr.length !== 2) return commandError(msgArr[0], errMsg); 152 | return { redirectionId: msgArr[1] }; 153 | }; 154 | 155 | // List Redirections 156 | const parseCommandList = message => { 157 | const msgArr = message.trim().split(' '); 158 | if (msgArr.length !== 1) return commandError(msgArr[0], 'Should not have any parameter'); 159 | return true; 160 | }; 161 | 162 | // Activate Redirection 163 | const parseCommandActivate = message => { 164 | const msgArr = message.trim().split(' '); 165 | if (msgArr.length !== 2) return commandError(msgArr[0], 'Should contain 1 parameter\n\n`/activate `'); 166 | 167 | const redirectionId = msgArr[1]; 168 | if (isNaN(Number(redirectionId))) { 169 | return commandError(msgArr[0], `redirection id should be a number`); 170 | } 171 | 172 | return { redirectionId }; 173 | }; 174 | 175 | // Deactivate Redirection 176 | const parseCommandDeactivate = message => { 177 | const msgArr = message.trim().split(' '); 178 | if (msgArr.length !== 2) { 179 | return commandError(msgArr[0], 'Should contain 1 parameter\n\n`/deactivate `'); 180 | } 181 | 182 | const redirectionId = msgArr[1]; 183 | if (isNaN(Number(redirectionId))) { 184 | return commandError(msgArr[0], `redirection id should be a number`); 185 | } 186 | 187 | return { redirectionId: msgArr[1] }; 188 | }; 189 | 190 | ///////////////////// 191 | // Filter Commands // 192 | ///////////////////// 193 | 194 | // Add Filter 195 | const parseCommandFilter = message => { 196 | let parsedResponse = {}; 197 | const msgArr = message.trim().split(' '); 198 | if (msgArr.length < 4) { 199 | let reply = 'Should contain at least 3 parameters.\n\n'; 200 | reply += '`/filter `\n\n'; 201 | reply += 'Example : \n\n'; 202 | reply += '`/filter photo 152 on`'; 203 | return commandError(msgArr[0], reply); 204 | } 205 | 206 | const validFilters = ['photo', 'video', 'audio', 'sticker', 'document', 'hashtag', 'link', 'contain', 'notcontain']; 207 | const validStates = ['on', 'off']; 208 | 209 | const filterName = msgArr[1]; 210 | const redirectionId = msgArr[2]; 211 | const filterState = msgArr[3].split(/\n/g)[0]; 212 | 213 | //////////////////// 214 | // Valid filter ? // 215 | //////////////////// 216 | if (validFilters.indexOf(filterName) < 0) { 217 | const errMsg = `Invalid filter name. Available filters :\n\n- ${validFilters.join('\n- ')}`; 218 | return commandError(msgArr[0], errMsg); 219 | } 220 | 221 | /////////////////// 222 | // Valid state ? // 223 | /////////////////// 224 | if (validStates.indexOf(filterState.toLowerCase()) < 0) { 225 | const errMsg = `Invalid State. Available states :\n\n- ${validStates.join('\n- ')}`; 226 | return commandError(msgArr[0], errMsg); 227 | } 228 | 229 | ///////////////////////////////////////////////////////////////// 230 | // If filter name is contain or notcontain gather the keywords // 231 | // Keywords are only required if filterstate = 'on' // 232 | ///////////////////////////////////////////////////////////////// 233 | if (filterState === 'on') { 234 | if (filterName === 'contain' || filterName === 'notcontain') { 235 | const msgArrLine = message.trim().split('\n'); 236 | const filterKeywords = msgArrLine.splice(1, msgArrLine.length).filter(x => x !== ''); 237 | parsedResponse.keywords = filterKeywords; 238 | 239 | if (filterKeywords.length === 0) { 240 | let errMsg = 'Please provide keywords.\n\n Example: \n'; 241 | errMsg += '`/filter contain 1 on\nqueen\nBohemian Rhapsody`'; 242 | return commandError(msgArr[0], errMsg); 243 | } 244 | } 245 | } 246 | 247 | parsedResponse.name = filterName; 248 | parsedResponse.state = filterState; 249 | parsedResponse.redirectionId = redirectionId; 250 | return parsedResponse; 251 | }; 252 | 253 | // List Filters 254 | const parseCommandFilters = message => { 255 | const msgArr = message.trim().split(' '); 256 | let errMsg = 'Should contain 1 parameter\n\n'; 257 | errMsg += '`/filters `'; 258 | if (msgArr.length !== 2) return commandError(msgArr[0], errMsg); 259 | return { filterId: msgArr[1] }; 260 | }; 261 | 262 | class MessageParser { 263 | /** 264 | * Takes in message and checks if there is a valid command 265 | * @param {String} message Telegram Message 266 | * @returns {Boolean} 267 | */ 268 | static isValidCommand(message) { 269 | const firstWord = message.trim().split(' ')[0]; 270 | return validCommands.indexOf(firstWord) >= 0; 271 | } 272 | 273 | static hashMap() { 274 | return { 275 | '/add': parseCommandAdd, 276 | '/remove': parseCommandRemove, 277 | '/list': parseCommandList, 278 | '/activate': parseCommandActivate, 279 | '/deactivate': parseCommandDeactivate, 280 | '/filter': parseCommandFilter, 281 | '/filters': parseCommandFilters, 282 | '/transform': parseCommandTransform, 283 | '/transforms': parseCommandTransforms, 284 | '/transformrank': parseCommandTransformRank, 285 | '/transformremove': parseCommandTransformRemove, 286 | }; 287 | } 288 | 289 | /** 290 | * Takes in message and returns command. 291 | * Should only be called after making sure there is a valid command using isValidCommand() 292 | * @param {String} message Telegram Message 293 | * @returns {String} returns command name 294 | */ 295 | static getCommand(message) { 296 | return message.trim().split(' ')[0]; 297 | } 298 | } 299 | 300 | module.exports = MessageParser; 301 | 302 | if (require.main === module) { 303 | let message = '/list '; 304 | const isValid = MessageParser.isValidCommand(message); 305 | if (isValid) { 306 | const command = MessageParser.getCommand(message); 307 | const parser = hashMap[command]; 308 | const response = parser(message); 309 | 310 | if (response.error) { 311 | return console.log(response); 312 | } 313 | 314 | if (command === '/add') { 315 | console.log(`Source: ${response.source} && Destination: ${response.destination}`); 316 | } else if (command === '/remove') { 317 | console.log(`Redirection ID: ${response.redirectionId}`); 318 | } 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /bot/controllers/removeRedirection.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | const removeRedirection = async (sender, redirectionId) => { 4 | return new Promise(async (resolve, reject) => { 5 | try { 6 | ///////////////////////////////////////////// 7 | // Sender must be the owner of redirection // 8 | ///////////////////////////////////////////// 9 | const redirections = await database.getRedirections(sender); 10 | let redirectionOfInterest = redirections.filter((redirection) => redirection.id == redirectionId) 11 | if (redirectionOfInterest.length === 0) throw Error('Redirection does not exist'); 12 | 13 | //////////////////////// 14 | // Update to database // 15 | //////////////////////// 16 | const dbResponse = await database.removeRedirection(redirectionId); 17 | await database.changeUserQuota(sender, -1); 18 | return resolve({ dbResponse }); 19 | } catch (err) { 20 | console.log(`[Error removeRedirection.js] :: ${err}`); 21 | return reject(err); 22 | } 23 | }) 24 | } 25 | 26 | module.exports = removeRedirection; 27 | -------------------------------------------------------------------------------- /bot/controllers/removeTransformation.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | const removeTransformation = (sender, transformationId) => { 4 | return new Promise(async (resolve, reject) => { 5 | try { 6 | ///////////////////////////////////////////// 7 | // Sender must be the owner of redirection // 8 | // Linked with the given transformations // 9 | ///////////////////////////////////////////// 10 | const transformation = await database.getTransformation(transformationId); 11 | if (transformation === undefined) throw new Error('Transformation does not exist'); 12 | 13 | const redirections = await database.getRedirections(sender); 14 | const isOwner = redirections.filter(r => r.id == transformation['redirection_id']).length > 0; 15 | if (!isOwner) throw new Error('You are not the owner of the transformation.'); 16 | 17 | /////////////////////////// 18 | // Delete transformation // 19 | /////////////////////////// 20 | await database.removeTransformation(transformationId); 21 | 22 | return resolve({ transformationId }); 23 | } catch (err) { 24 | console.log(`[ERROR removeTransformation.js] : ${err}`); 25 | return reject(err); 26 | } 27 | }); 28 | }; 29 | 30 | module.exports = removeTransformation; 31 | -------------------------------------------------------------------------------- /bot/controllers/swapTransformationRank.js: -------------------------------------------------------------------------------- 1 | const database = require('../db/database'); 2 | 3 | const swapTransformationRank = (sender, redirectionId, rank1, rank2) => { 4 | return new Promise( async(resolve, reject) => { 5 | try { 6 | 7 | ///////////////////////////////////////////// 8 | // Sender must be the owner of redirection // 9 | ///////////////////////////////////////////// 10 | const redirections = await database.getRedirections(sender); 11 | let redirectionOfInterest = redirections.filter((redirection) => redirection.id == redirectionId) 12 | if (redirectionOfInterest.length === 0) throw Error('Redirection doesnot exist'); 13 | 14 | ///////////////////////////////////////////// 15 | // Both transformation ranks should exists // 16 | ///////////////////////////////////////////// 17 | const transformations = await database.getTransformationsOfRedirection(redirectionId); 18 | const requiredTransformations = transformations.filter((tranformation) => { 19 | return tranformation.rank == rank1 || tranformation.rank == rank2; 20 | }); 21 | if (requiredTransformations.length !== 2) throw new Error('The transformation does not exist'); 22 | 23 | //////////////// 24 | // Swap ranks // 25 | //////////////// 26 | await database.changeTransformationRank(requiredTransformations[0].id, requiredTransformations[1].rank); 27 | await database.changeTransformationRank(requiredTransformations[1].id, requiredTransformations[0].rank); 28 | 29 | return resolve({ redirectionId }) 30 | 31 | } catch (err) { 32 | console.log(`ERROR: [swapTransformationRank()] ${err}`) 33 | reject(err); 34 | } 35 | }) 36 | } 37 | 38 | module.exports = swapTransformationRank; 39 | -------------------------------------------------------------------------------- /bot/db/database.js: -------------------------------------------------------------------------------- 1 | const knex = require('../services/database'); 2 | 3 | class Database { 4 | constructor() {} 5 | 6 | /////////// 7 | // USERS // 8 | /////////// 9 | getUser(chatId) { 10 | return knex('users').select('*').where({ chat_id: chatId }).first(); 11 | } 12 | 13 | getAllUsers() { 14 | return knex('users').select('*'); 15 | } 16 | 17 | saveUser(chatId, username, refCode) { 18 | return knex('users').insert({ chat_id: chatId, username: username, ref_code: refCode }); 19 | } 20 | 21 | changeUserQuota(chatId, change = 1) { 22 | const sql = `UPDATE users SET quota = quota + ? WHERE chat_id = ?`; 23 | return knex.raw(sql, [change, chatId]); 24 | } 25 | 26 | getUserQuota(chatId) { 27 | return knex('user').select('quote').where({ chat_id: chatId }); 28 | } 29 | 30 | ////////////////// 31 | // REDIRECTIONS // 32 | ////////////////// 33 | getRedirections(userId) { 34 | return knex('redirections').select('*').where({ owner: userId }); 35 | } 36 | 37 | saveRedirection(owner, source, destination, srcTitle, destTitle) { 38 | return knex('redirections').insert({ 39 | owner, 40 | source, 41 | destination, 42 | source_title: srcTitle, 43 | destination_title: destTitle, 44 | }); 45 | } 46 | 47 | removeRedirection(redirectionId) { 48 | return knex.raw('DELETE FROM redirections WHERE id = ?', [redirectionId]); 49 | } 50 | 51 | activateRedirection(redirectionId) { 52 | return knex.raw('UPDATE redirections SET active = ? WHERE id = ?', [1, redirectionId]); 53 | } 54 | 55 | deactivateRedirection(redirectionId) { 56 | return knex.raw('UPDATE redirections SET active = ? WHERE id = ?', [0, redirectionId]); 57 | } 58 | 59 | ///////////// 60 | // FILTERS // 61 | ///////////// 62 | 63 | /** 64 | * @param {Number} redirectionId 65 | * @param {String} filterName One of specific filter names 66 | * @param {} data filter state or filter keywords 67 | */ 68 | saveFilter(redirectionId, filterName, data) { 69 | return knex.raw( 70 | `INSERT INTO filters (id, ${filterName}) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET ${filterName} = ?`, 71 | [redirectionId, data, data] 72 | ); 73 | } 74 | 75 | getFilter(redirectionId) { 76 | return knex('filters').select('*').where({ id: redirectionId }).first(); 77 | } 78 | 79 | ///////////////////// 80 | // Transformations // 81 | ///////////////////// 82 | saveTransformation(redirectionId, oldPhrase, newPhrase, rank) { 83 | return knex.raw( 84 | `INSERT INTO transformations (redirection_id, old_phrase, new_phrase, rank) VALUES (?, ?, ?, ?) RETURNING id`, 85 | [redirectionId, oldPhrase, newPhrase, rank] 86 | ); 87 | } 88 | 89 | getTransformation(transformationId) { 90 | return knex('transformations').select('*').where({ id: transformationId }).first(); 91 | } 92 | 93 | getTransformationsOfRedirection(redirectionId) { 94 | return knex('transformations').select('*').where({ redirection_id: redirectionId }); 95 | } 96 | 97 | changeTransformationRank(transformationId, newRank) { 98 | return new Promise((resolve, reject) => { 99 | const sql = 'UPDATE transformations SET rank = ? Where id = ?'; 100 | this.connection.query(sql, [newRank, transformationId], (error, results) => { 101 | if (error) return reject(error); 102 | resolve(results); 103 | }); 104 | }); 105 | } 106 | 107 | removeTransformation(transformationId) { 108 | return knex.raw('DELETE FROM transformations WHERE id = ?', [transformationId]); 109 | } 110 | } 111 | 112 | // Single Ton 113 | module.exports = new Database(); 114 | 115 | if (require.main === module) { 116 | const db = new Database(); 117 | // db.changeUserQuota('xxx', 100).then(console.log).catch(console.error); 118 | // db.getUser('xxx').then(console.log); 119 | } 120 | -------------------------------------------------------------------------------- /bot/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telegram-forwarder-bot-agent", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@sindresorhus/is": { 8 | "version": "0.14.0", 9 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", 10 | "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", 11 | "dev": true 12 | }, 13 | "@szmarczak/http-timer": { 14 | "version": "1.1.2", 15 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", 16 | "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", 17 | "dev": true, 18 | "requires": { 19 | "defer-to-connect": "^1.0.1" 20 | } 21 | }, 22 | "@types/color-name": { 23 | "version": "1.1.1", 24 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", 25 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", 26 | "dev": true 27 | }, 28 | "abbrev": { 29 | "version": "1.1.1", 30 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 31 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 32 | "dev": true 33 | }, 34 | "ajv": { 35 | "version": "6.12.4", 36 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", 37 | "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", 38 | "requires": { 39 | "fast-deep-equal": "^3.1.1", 40 | "fast-json-stable-stringify": "^2.0.0", 41 | "json-schema-traverse": "^0.4.1", 42 | "uri-js": "^4.2.2" 43 | } 44 | }, 45 | "ansi-align": { 46 | "version": "3.0.0", 47 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", 48 | "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", 49 | "dev": true, 50 | "requires": { 51 | "string-width": "^3.0.0" 52 | }, 53 | "dependencies": { 54 | "string-width": { 55 | "version": "3.1.0", 56 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 57 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 58 | "dev": true, 59 | "requires": { 60 | "emoji-regex": "^7.0.1", 61 | "is-fullwidth-code-point": "^2.0.0", 62 | "strip-ansi": "^5.1.0" 63 | } 64 | } 65 | } 66 | }, 67 | "ansi-regex": { 68 | "version": "4.1.0", 69 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 70 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 71 | "dev": true 72 | }, 73 | "ansi-styles": { 74 | "version": "4.2.1", 75 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", 76 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", 77 | "dev": true, 78 | "requires": { 79 | "@types/color-name": "^1.1.1", 80 | "color-convert": "^2.0.1" 81 | } 82 | }, 83 | "anymatch": { 84 | "version": "3.1.1", 85 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 86 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 87 | "dev": true, 88 | "requires": { 89 | "normalize-path": "^3.0.0", 90 | "picomatch": "^2.0.4" 91 | } 92 | }, 93 | "arr-diff": { 94 | "version": "4.0.0", 95 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", 96 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" 97 | }, 98 | "arr-flatten": { 99 | "version": "1.1.0", 100 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 101 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" 102 | }, 103 | "arr-union": { 104 | "version": "3.1.0", 105 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 106 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" 107 | }, 108 | "array-each": { 109 | "version": "1.0.1", 110 | "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", 111 | "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" 112 | }, 113 | "array-slice": { 114 | "version": "1.1.0", 115 | "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", 116 | "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" 117 | }, 118 | "array-unique": { 119 | "version": "0.3.2", 120 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", 121 | "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" 122 | }, 123 | "array.prototype.findindex": { 124 | "version": "2.1.0", 125 | "resolved": "https://registry.npmjs.org/array.prototype.findindex/-/array.prototype.findindex-2.1.0.tgz", 126 | "integrity": "sha512-25kJHCjXltdtljjwcyKvCTywmbUAeTJVB2ADVe0oP4jcefsd+K9pJJ3IdHPahLICoszcCLoNF+evWpEduzBlng==", 127 | "requires": { 128 | "define-properties": "^1.1.3", 129 | "es-abstract": "^1.17.4" 130 | } 131 | }, 132 | "asn1": { 133 | "version": "0.2.4", 134 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 135 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 136 | "requires": { 137 | "safer-buffer": "~2.1.0" 138 | } 139 | }, 140 | "assert-plus": { 141 | "version": "1.0.0", 142 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 143 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 144 | }, 145 | "assign-symbols": { 146 | "version": "1.0.0", 147 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 148 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" 149 | }, 150 | "asynckit": { 151 | "version": "0.4.0", 152 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 153 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 154 | }, 155 | "atob": { 156 | "version": "2.1.2", 157 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", 158 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" 159 | }, 160 | "atomic-sleep": { 161 | "version": "1.0.0", 162 | "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", 163 | "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" 164 | }, 165 | "aws-sign2": { 166 | "version": "0.7.0", 167 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 168 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 169 | }, 170 | "aws4": { 171 | "version": "1.10.1", 172 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", 173 | "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" 174 | }, 175 | "balanced-match": { 176 | "version": "1.0.0", 177 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 178 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 179 | "dev": true 180 | }, 181 | "base": { 182 | "version": "0.11.2", 183 | "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", 184 | "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", 185 | "requires": { 186 | "cache-base": "^1.0.1", 187 | "class-utils": "^0.3.5", 188 | "component-emitter": "^1.2.1", 189 | "define-property": "^1.0.0", 190 | "isobject": "^3.0.1", 191 | "mixin-deep": "^1.2.0", 192 | "pascalcase": "^0.1.1" 193 | }, 194 | "dependencies": { 195 | "define-property": { 196 | "version": "1.0.0", 197 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 198 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 199 | "requires": { 200 | "is-descriptor": "^1.0.0" 201 | } 202 | }, 203 | "is-accessor-descriptor": { 204 | "version": "1.0.0", 205 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 206 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 207 | "requires": { 208 | "kind-of": "^6.0.0" 209 | } 210 | }, 211 | "is-data-descriptor": { 212 | "version": "1.0.0", 213 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 214 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 215 | "requires": { 216 | "kind-of": "^6.0.0" 217 | } 218 | }, 219 | "is-descriptor": { 220 | "version": "1.0.2", 221 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 222 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 223 | "requires": { 224 | "is-accessor-descriptor": "^1.0.0", 225 | "is-data-descriptor": "^1.0.0", 226 | "kind-of": "^6.0.2" 227 | } 228 | } 229 | } 230 | }, 231 | "bcrypt-pbkdf": { 232 | "version": "1.0.2", 233 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 234 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 235 | "requires": { 236 | "tweetnacl": "^0.14.3" 237 | } 238 | }, 239 | "binary-extensions": { 240 | "version": "2.1.0", 241 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", 242 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", 243 | "dev": true 244 | }, 245 | "bl": { 246 | "version": "1.2.3", 247 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", 248 | "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", 249 | "requires": { 250 | "readable-stream": "^2.3.5", 251 | "safe-buffer": "^5.1.1" 252 | } 253 | }, 254 | "bluebird": { 255 | "version": "3.7.2", 256 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 257 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" 258 | }, 259 | "boxen": { 260 | "version": "4.2.0", 261 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", 262 | "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", 263 | "dev": true, 264 | "requires": { 265 | "ansi-align": "^3.0.0", 266 | "camelcase": "^5.3.1", 267 | "chalk": "^3.0.0", 268 | "cli-boxes": "^2.2.0", 269 | "string-width": "^4.1.0", 270 | "term-size": "^2.1.0", 271 | "type-fest": "^0.8.1", 272 | "widest-line": "^3.1.0" 273 | } 274 | }, 275 | "brace-expansion": { 276 | "version": "1.1.11", 277 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 278 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 279 | "dev": true, 280 | "requires": { 281 | "balanced-match": "^1.0.0", 282 | "concat-map": "0.0.1" 283 | } 284 | }, 285 | "braces": { 286 | "version": "2.3.2", 287 | "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", 288 | "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", 289 | "requires": { 290 | "arr-flatten": "^1.1.0", 291 | "array-unique": "^0.3.2", 292 | "extend-shallow": "^2.0.1", 293 | "fill-range": "^4.0.0", 294 | "isobject": "^3.0.1", 295 | "repeat-element": "^1.1.2", 296 | "snapdragon": "^0.8.1", 297 | "snapdragon-node": "^2.0.1", 298 | "split-string": "^3.0.2", 299 | "to-regex": "^3.0.1" 300 | }, 301 | "dependencies": { 302 | "extend-shallow": { 303 | "version": "2.0.1", 304 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 305 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 306 | "requires": { 307 | "is-extendable": "^0.1.0" 308 | } 309 | } 310 | } 311 | }, 312 | "buffer-writer": { 313 | "version": "2.0.0", 314 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 315 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" 316 | }, 317 | "cache-base": { 318 | "version": "1.0.1", 319 | "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", 320 | "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", 321 | "requires": { 322 | "collection-visit": "^1.0.0", 323 | "component-emitter": "^1.2.1", 324 | "get-value": "^2.0.6", 325 | "has-value": "^1.0.0", 326 | "isobject": "^3.0.1", 327 | "set-value": "^2.0.0", 328 | "to-object-path": "^0.3.0", 329 | "union-value": "^1.0.0", 330 | "unset-value": "^1.0.0" 331 | } 332 | }, 333 | "cacheable-request": { 334 | "version": "6.1.0", 335 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", 336 | "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", 337 | "dev": true, 338 | "requires": { 339 | "clone-response": "^1.0.2", 340 | "get-stream": "^5.1.0", 341 | "http-cache-semantics": "^4.0.0", 342 | "keyv": "^3.0.0", 343 | "lowercase-keys": "^2.0.0", 344 | "normalize-url": "^4.1.0", 345 | "responselike": "^1.0.2" 346 | }, 347 | "dependencies": { 348 | "get-stream": { 349 | "version": "5.2.0", 350 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 351 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 352 | "dev": true, 353 | "requires": { 354 | "pump": "^3.0.0" 355 | } 356 | }, 357 | "lowercase-keys": { 358 | "version": "2.0.0", 359 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", 360 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", 361 | "dev": true 362 | }, 363 | "pump": { 364 | "version": "3.0.0", 365 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 366 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 367 | "dev": true, 368 | "requires": { 369 | "end-of-stream": "^1.1.0", 370 | "once": "^1.3.1" 371 | } 372 | } 373 | } 374 | }, 375 | "camelcase": { 376 | "version": "5.3.1", 377 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 378 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 379 | "dev": true 380 | }, 381 | "caseless": { 382 | "version": "0.12.0", 383 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 384 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 385 | }, 386 | "chalk": { 387 | "version": "3.0.0", 388 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", 389 | "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", 390 | "dev": true, 391 | "requires": { 392 | "ansi-styles": "^4.1.0", 393 | "supports-color": "^7.1.0" 394 | }, 395 | "dependencies": { 396 | "has-flag": { 397 | "version": "4.0.0", 398 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 399 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 400 | "dev": true 401 | }, 402 | "supports-color": { 403 | "version": "7.1.0", 404 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", 405 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", 406 | "dev": true, 407 | "requires": { 408 | "has-flag": "^4.0.0" 409 | } 410 | } 411 | } 412 | }, 413 | "chokidar": { 414 | "version": "3.4.2", 415 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", 416 | "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", 417 | "dev": true, 418 | "requires": { 419 | "anymatch": "~3.1.1", 420 | "braces": "~3.0.2", 421 | "fsevents": "~2.1.2", 422 | "glob-parent": "~5.1.0", 423 | "is-binary-path": "~2.1.0", 424 | "is-glob": "~4.0.1", 425 | "normalize-path": "~3.0.0", 426 | "readdirp": "~3.4.0" 427 | }, 428 | "dependencies": { 429 | "braces": { 430 | "version": "3.0.2", 431 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 432 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 433 | "dev": true, 434 | "requires": { 435 | "fill-range": "^7.0.1" 436 | } 437 | }, 438 | "fill-range": { 439 | "version": "7.0.1", 440 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 441 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 442 | "dev": true, 443 | "requires": { 444 | "to-regex-range": "^5.0.1" 445 | } 446 | }, 447 | "is-number": { 448 | "version": "7.0.0", 449 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 450 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 451 | "dev": true 452 | }, 453 | "to-regex-range": { 454 | "version": "5.0.1", 455 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 456 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 457 | "dev": true, 458 | "requires": { 459 | "is-number": "^7.0.0" 460 | } 461 | } 462 | } 463 | }, 464 | "ci-info": { 465 | "version": "2.0.0", 466 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", 467 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", 468 | "dev": true 469 | }, 470 | "class-utils": { 471 | "version": "0.3.6", 472 | "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", 473 | "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", 474 | "requires": { 475 | "arr-union": "^3.1.0", 476 | "define-property": "^0.2.5", 477 | "isobject": "^3.0.0", 478 | "static-extend": "^0.1.1" 479 | }, 480 | "dependencies": { 481 | "define-property": { 482 | "version": "0.2.5", 483 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 484 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 485 | "requires": { 486 | "is-descriptor": "^0.1.0" 487 | } 488 | } 489 | } 490 | }, 491 | "cli-boxes": { 492 | "version": "2.2.0", 493 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", 494 | "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", 495 | "dev": true 496 | }, 497 | "clone-response": { 498 | "version": "1.0.2", 499 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", 500 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", 501 | "dev": true, 502 | "requires": { 503 | "mimic-response": "^1.0.0" 504 | } 505 | }, 506 | "collection-visit": { 507 | "version": "1.0.0", 508 | "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", 509 | "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", 510 | "requires": { 511 | "map-visit": "^1.0.0", 512 | "object-visit": "^1.0.0" 513 | } 514 | }, 515 | "color-convert": { 516 | "version": "2.0.1", 517 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 518 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 519 | "dev": true, 520 | "requires": { 521 | "color-name": "~1.1.4" 522 | } 523 | }, 524 | "color-name": { 525 | "version": "1.1.4", 526 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 527 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 528 | "dev": true 529 | }, 530 | "colorette": { 531 | "version": "1.1.0", 532 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz", 533 | "integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==" 534 | }, 535 | "combined-stream": { 536 | "version": "1.0.8", 537 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 538 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 539 | "requires": { 540 | "delayed-stream": "~1.0.0" 541 | } 542 | }, 543 | "commander": { 544 | "version": "4.1.1", 545 | "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 546 | "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" 547 | }, 548 | "component-emitter": { 549 | "version": "1.3.0", 550 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 551 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" 552 | }, 553 | "concat-map": { 554 | "version": "0.0.1", 555 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 556 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 557 | "dev": true 558 | }, 559 | "configstore": { 560 | "version": "5.0.1", 561 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", 562 | "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", 563 | "dev": true, 564 | "requires": { 565 | "dot-prop": "^5.2.0", 566 | "graceful-fs": "^4.1.2", 567 | "make-dir": "^3.0.0", 568 | "unique-string": "^2.0.0", 569 | "write-file-atomic": "^3.0.0", 570 | "xdg-basedir": "^4.0.0" 571 | } 572 | }, 573 | "copy-descriptor": { 574 | "version": "0.1.1", 575 | "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", 576 | "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" 577 | }, 578 | "core-util-is": { 579 | "version": "1.0.2", 580 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 581 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 582 | }, 583 | "crypto-random-string": { 584 | "version": "2.0.0", 585 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", 586 | "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", 587 | "dev": true 588 | }, 589 | "dashdash": { 590 | "version": "1.14.1", 591 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 592 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 593 | "requires": { 594 | "assert-plus": "^1.0.0" 595 | } 596 | }, 597 | "debug": { 598 | "version": "4.1.1", 599 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 600 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 601 | "requires": { 602 | "ms": "^2.1.1" 603 | } 604 | }, 605 | "decode-uri-component": { 606 | "version": "0.2.0", 607 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 608 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" 609 | }, 610 | "decompress-response": { 611 | "version": "3.3.0", 612 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", 613 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", 614 | "dev": true, 615 | "requires": { 616 | "mimic-response": "^1.0.0" 617 | } 618 | }, 619 | "deep-extend": { 620 | "version": "0.6.0", 621 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 622 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 623 | "dev": true 624 | }, 625 | "defer-to-connect": { 626 | "version": "1.1.3", 627 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", 628 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", 629 | "dev": true 630 | }, 631 | "define-properties": { 632 | "version": "1.1.3", 633 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 634 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 635 | "requires": { 636 | "object-keys": "^1.0.12" 637 | } 638 | }, 639 | "define-property": { 640 | "version": "2.0.2", 641 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", 642 | "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", 643 | "requires": { 644 | "is-descriptor": "^1.0.2", 645 | "isobject": "^3.0.1" 646 | }, 647 | "dependencies": { 648 | "is-accessor-descriptor": { 649 | "version": "1.0.0", 650 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 651 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 652 | "requires": { 653 | "kind-of": "^6.0.0" 654 | } 655 | }, 656 | "is-data-descriptor": { 657 | "version": "1.0.0", 658 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 659 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 660 | "requires": { 661 | "kind-of": "^6.0.0" 662 | } 663 | }, 664 | "is-descriptor": { 665 | "version": "1.0.2", 666 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 667 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 668 | "requires": { 669 | "is-accessor-descriptor": "^1.0.0", 670 | "is-data-descriptor": "^1.0.0", 671 | "kind-of": "^6.0.2" 672 | } 673 | } 674 | } 675 | }, 676 | "delayed-stream": { 677 | "version": "1.0.0", 678 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 679 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 680 | }, 681 | "depd": { 682 | "version": "1.1.2", 683 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 684 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 685 | }, 686 | "detect-file": { 687 | "version": "1.0.0", 688 | "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", 689 | "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" 690 | }, 691 | "dot-prop": { 692 | "version": "5.2.0", 693 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", 694 | "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", 695 | "dev": true, 696 | "requires": { 697 | "is-obj": "^2.0.0" 698 | } 699 | }, 700 | "duplexer3": { 701 | "version": "0.1.4", 702 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 703 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", 704 | "dev": true 705 | }, 706 | "ecc-jsbn": { 707 | "version": "0.1.2", 708 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 709 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 710 | "requires": { 711 | "jsbn": "~0.1.0", 712 | "safer-buffer": "^2.1.0" 713 | } 714 | }, 715 | "emoji-regex": { 716 | "version": "7.0.3", 717 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 718 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 719 | "dev": true 720 | }, 721 | "end-of-stream": { 722 | "version": "1.4.4", 723 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 724 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 725 | "requires": { 726 | "once": "^1.4.0" 727 | } 728 | }, 729 | "es-abstract": { 730 | "version": "1.17.6", 731 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", 732 | "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", 733 | "requires": { 734 | "es-to-primitive": "^1.2.1", 735 | "function-bind": "^1.1.1", 736 | "has": "^1.0.3", 737 | "has-symbols": "^1.0.1", 738 | "is-callable": "^1.2.0", 739 | "is-regex": "^1.1.0", 740 | "object-inspect": "^1.7.0", 741 | "object-keys": "^1.1.1", 742 | "object.assign": "^4.1.0", 743 | "string.prototype.trimend": "^1.0.1", 744 | "string.prototype.trimstart": "^1.0.1" 745 | } 746 | }, 747 | "es-to-primitive": { 748 | "version": "1.2.1", 749 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 750 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 751 | "requires": { 752 | "is-callable": "^1.1.4", 753 | "is-date-object": "^1.0.1", 754 | "is-symbol": "^1.0.2" 755 | } 756 | }, 757 | "escape-goat": { 758 | "version": "2.1.1", 759 | "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", 760 | "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", 761 | "dev": true 762 | }, 763 | "esm": { 764 | "version": "3.2.25", 765 | "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", 766 | "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" 767 | }, 768 | "eventemitter3": { 769 | "version": "3.1.2", 770 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", 771 | "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" 772 | }, 773 | "expand-brackets": { 774 | "version": "2.1.4", 775 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", 776 | "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", 777 | "requires": { 778 | "debug": "^2.3.3", 779 | "define-property": "^0.2.5", 780 | "extend-shallow": "^2.0.1", 781 | "posix-character-classes": "^0.1.0", 782 | "regex-not": "^1.0.0", 783 | "snapdragon": "^0.8.1", 784 | "to-regex": "^3.0.1" 785 | }, 786 | "dependencies": { 787 | "debug": { 788 | "version": "2.6.9", 789 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 790 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 791 | "requires": { 792 | "ms": "2.0.0" 793 | } 794 | }, 795 | "define-property": { 796 | "version": "0.2.5", 797 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 798 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 799 | "requires": { 800 | "is-descriptor": "^0.1.0" 801 | } 802 | }, 803 | "extend-shallow": { 804 | "version": "2.0.1", 805 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 806 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 807 | "requires": { 808 | "is-extendable": "^0.1.0" 809 | } 810 | }, 811 | "ms": { 812 | "version": "2.0.0", 813 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 814 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 815 | } 816 | } 817 | }, 818 | "expand-tilde": { 819 | "version": "2.0.2", 820 | "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", 821 | "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", 822 | "requires": { 823 | "homedir-polyfill": "^1.0.1" 824 | } 825 | }, 826 | "extend": { 827 | "version": "3.0.2", 828 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 829 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 830 | }, 831 | "extend-shallow": { 832 | "version": "3.0.2", 833 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 834 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", 835 | "requires": { 836 | "assign-symbols": "^1.0.0", 837 | "is-extendable": "^1.0.1" 838 | }, 839 | "dependencies": { 840 | "is-extendable": { 841 | "version": "1.0.1", 842 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 843 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 844 | "requires": { 845 | "is-plain-object": "^2.0.4" 846 | } 847 | } 848 | } 849 | }, 850 | "extglob": { 851 | "version": "2.0.4", 852 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", 853 | "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", 854 | "requires": { 855 | "array-unique": "^0.3.2", 856 | "define-property": "^1.0.0", 857 | "expand-brackets": "^2.1.4", 858 | "extend-shallow": "^2.0.1", 859 | "fragment-cache": "^0.2.1", 860 | "regex-not": "^1.0.0", 861 | "snapdragon": "^0.8.1", 862 | "to-regex": "^3.0.1" 863 | }, 864 | "dependencies": { 865 | "define-property": { 866 | "version": "1.0.0", 867 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 868 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 869 | "requires": { 870 | "is-descriptor": "^1.0.0" 871 | } 872 | }, 873 | "extend-shallow": { 874 | "version": "2.0.1", 875 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 876 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 877 | "requires": { 878 | "is-extendable": "^0.1.0" 879 | } 880 | }, 881 | "is-accessor-descriptor": { 882 | "version": "1.0.0", 883 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 884 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 885 | "requires": { 886 | "kind-of": "^6.0.0" 887 | } 888 | }, 889 | "is-data-descriptor": { 890 | "version": "1.0.0", 891 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 892 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 893 | "requires": { 894 | "kind-of": "^6.0.0" 895 | } 896 | }, 897 | "is-descriptor": { 898 | "version": "1.0.2", 899 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 900 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 901 | "requires": { 902 | "is-accessor-descriptor": "^1.0.0", 903 | "is-data-descriptor": "^1.0.0", 904 | "kind-of": "^6.0.2" 905 | } 906 | } 907 | } 908 | }, 909 | "extsprintf": { 910 | "version": "1.3.0", 911 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 912 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 913 | }, 914 | "fast-deep-equal": { 915 | "version": "3.1.3", 916 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 917 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 918 | }, 919 | "fast-json-stable-stringify": { 920 | "version": "2.1.0", 921 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 922 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 923 | }, 924 | "fast-redact": { 925 | "version": "2.0.0", 926 | "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-2.0.0.tgz", 927 | "integrity": "sha512-zxpkULI9W9MNTK2sJ3BpPQrTEXFNESd2X6O1tXMFpK/XM0G5c5Rll2EVYZH2TqI3xRGK/VaJ+eEOt7pnENJpeA==" 928 | }, 929 | "fast-safe-stringify": { 930 | "version": "2.0.7", 931 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", 932 | "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" 933 | }, 934 | "file-type": { 935 | "version": "3.9.0", 936 | "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", 937 | "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" 938 | }, 939 | "fill-range": { 940 | "version": "4.0.0", 941 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", 942 | "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", 943 | "requires": { 944 | "extend-shallow": "^2.0.1", 945 | "is-number": "^3.0.0", 946 | "repeat-string": "^1.6.1", 947 | "to-regex-range": "^2.1.0" 948 | }, 949 | "dependencies": { 950 | "extend-shallow": { 951 | "version": "2.0.1", 952 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 953 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 954 | "requires": { 955 | "is-extendable": "^0.1.0" 956 | } 957 | } 958 | } 959 | }, 960 | "findup-sync": { 961 | "version": "3.0.0", 962 | "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", 963 | "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", 964 | "requires": { 965 | "detect-file": "^1.0.0", 966 | "is-glob": "^4.0.0", 967 | "micromatch": "^3.0.4", 968 | "resolve-dir": "^1.0.1" 969 | } 970 | }, 971 | "fined": { 972 | "version": "1.2.0", 973 | "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", 974 | "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", 975 | "requires": { 976 | "expand-tilde": "^2.0.2", 977 | "is-plain-object": "^2.0.3", 978 | "object.defaults": "^1.1.0", 979 | "object.pick": "^1.2.0", 980 | "parse-filepath": "^1.0.1" 981 | } 982 | }, 983 | "flagged-respawn": { 984 | "version": "1.0.1", 985 | "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", 986 | "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" 987 | }, 988 | "flatstr": { 989 | "version": "1.0.12", 990 | "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", 991 | "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" 992 | }, 993 | "for-in": { 994 | "version": "1.0.2", 995 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 996 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" 997 | }, 998 | "for-own": { 999 | "version": "1.0.0", 1000 | "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", 1001 | "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", 1002 | "requires": { 1003 | "for-in": "^1.0.1" 1004 | } 1005 | }, 1006 | "forever-agent": { 1007 | "version": "0.6.1", 1008 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 1009 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 1010 | }, 1011 | "form-data": { 1012 | "version": "2.3.3", 1013 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 1014 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 1015 | "requires": { 1016 | "asynckit": "^0.4.0", 1017 | "combined-stream": "^1.0.6", 1018 | "mime-types": "^2.1.12" 1019 | } 1020 | }, 1021 | "fragment-cache": { 1022 | "version": "0.2.1", 1023 | "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", 1024 | "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", 1025 | "requires": { 1026 | "map-cache": "^0.2.2" 1027 | } 1028 | }, 1029 | "fsevents": { 1030 | "version": "2.1.3", 1031 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 1032 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 1033 | "dev": true, 1034 | "optional": true 1035 | }, 1036 | "function-bind": { 1037 | "version": "1.1.1", 1038 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1039 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 1040 | }, 1041 | "get-stream": { 1042 | "version": "4.1.0", 1043 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 1044 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 1045 | "dev": true, 1046 | "requires": { 1047 | "pump": "^3.0.0" 1048 | }, 1049 | "dependencies": { 1050 | "pump": { 1051 | "version": "3.0.0", 1052 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1053 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1054 | "dev": true, 1055 | "requires": { 1056 | "end-of-stream": "^1.1.0", 1057 | "once": "^1.3.1" 1058 | } 1059 | } 1060 | } 1061 | }, 1062 | "get-value": { 1063 | "version": "2.0.6", 1064 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", 1065 | "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" 1066 | }, 1067 | "getopts": { 1068 | "version": "2.2.5", 1069 | "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz", 1070 | "integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==" 1071 | }, 1072 | "getpass": { 1073 | "version": "0.1.7", 1074 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 1075 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 1076 | "requires": { 1077 | "assert-plus": "^1.0.0" 1078 | } 1079 | }, 1080 | "glob-parent": { 1081 | "version": "5.1.1", 1082 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 1083 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 1084 | "dev": true, 1085 | "requires": { 1086 | "is-glob": "^4.0.1" 1087 | } 1088 | }, 1089 | "global-dirs": { 1090 | "version": "2.0.1", 1091 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", 1092 | "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", 1093 | "dev": true, 1094 | "requires": { 1095 | "ini": "^1.3.5" 1096 | } 1097 | }, 1098 | "global-modules": { 1099 | "version": "1.0.0", 1100 | "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", 1101 | "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", 1102 | "requires": { 1103 | "global-prefix": "^1.0.1", 1104 | "is-windows": "^1.0.1", 1105 | "resolve-dir": "^1.0.0" 1106 | } 1107 | }, 1108 | "global-prefix": { 1109 | "version": "1.0.2", 1110 | "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", 1111 | "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", 1112 | "requires": { 1113 | "expand-tilde": "^2.0.2", 1114 | "homedir-polyfill": "^1.0.1", 1115 | "ini": "^1.3.4", 1116 | "is-windows": "^1.0.1", 1117 | "which": "^1.2.14" 1118 | } 1119 | }, 1120 | "got": { 1121 | "version": "9.6.0", 1122 | "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", 1123 | "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", 1124 | "dev": true, 1125 | "requires": { 1126 | "@sindresorhus/is": "^0.14.0", 1127 | "@szmarczak/http-timer": "^1.1.2", 1128 | "cacheable-request": "^6.0.0", 1129 | "decompress-response": "^3.3.0", 1130 | "duplexer3": "^0.1.4", 1131 | "get-stream": "^4.1.0", 1132 | "lowercase-keys": "^1.0.1", 1133 | "mimic-response": "^1.0.1", 1134 | "p-cancelable": "^1.0.0", 1135 | "to-readable-stream": "^1.0.0", 1136 | "url-parse-lax": "^3.0.0" 1137 | } 1138 | }, 1139 | "graceful-fs": { 1140 | "version": "4.2.4", 1141 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 1142 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", 1143 | "dev": true 1144 | }, 1145 | "har-schema": { 1146 | "version": "2.0.0", 1147 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 1148 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 1149 | }, 1150 | "har-validator": { 1151 | "version": "5.1.5", 1152 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", 1153 | "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", 1154 | "requires": { 1155 | "ajv": "^6.12.3", 1156 | "har-schema": "^2.0.0" 1157 | } 1158 | }, 1159 | "has": { 1160 | "version": "1.0.3", 1161 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1162 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1163 | "requires": { 1164 | "function-bind": "^1.1.1" 1165 | } 1166 | }, 1167 | "has-flag": { 1168 | "version": "3.0.0", 1169 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1170 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1171 | "dev": true 1172 | }, 1173 | "has-symbols": { 1174 | "version": "1.0.1", 1175 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 1176 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" 1177 | }, 1178 | "has-value": { 1179 | "version": "1.0.0", 1180 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", 1181 | "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", 1182 | "requires": { 1183 | "get-value": "^2.0.6", 1184 | "has-values": "^1.0.0", 1185 | "isobject": "^3.0.0" 1186 | } 1187 | }, 1188 | "has-values": { 1189 | "version": "1.0.0", 1190 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", 1191 | "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", 1192 | "requires": { 1193 | "is-number": "^3.0.0", 1194 | "kind-of": "^4.0.0" 1195 | }, 1196 | "dependencies": { 1197 | "kind-of": { 1198 | "version": "4.0.0", 1199 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", 1200 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", 1201 | "requires": { 1202 | "is-buffer": "^1.1.5" 1203 | } 1204 | } 1205 | } 1206 | }, 1207 | "has-yarn": { 1208 | "version": "2.1.0", 1209 | "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", 1210 | "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", 1211 | "dev": true 1212 | }, 1213 | "homedir-polyfill": { 1214 | "version": "1.0.3", 1215 | "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", 1216 | "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", 1217 | "requires": { 1218 | "parse-passwd": "^1.0.0" 1219 | } 1220 | }, 1221 | "http-cache-semantics": { 1222 | "version": "4.1.0", 1223 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", 1224 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", 1225 | "dev": true 1226 | }, 1227 | "http-signature": { 1228 | "version": "1.2.0", 1229 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 1230 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 1231 | "requires": { 1232 | "assert-plus": "^1.0.0", 1233 | "jsprim": "^1.2.2", 1234 | "sshpk": "^1.7.0" 1235 | } 1236 | }, 1237 | "ignore-by-default": { 1238 | "version": "1.0.1", 1239 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 1240 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", 1241 | "dev": true 1242 | }, 1243 | "import-lazy": { 1244 | "version": "2.1.0", 1245 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", 1246 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", 1247 | "dev": true 1248 | }, 1249 | "imurmurhash": { 1250 | "version": "0.1.4", 1251 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1252 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 1253 | "dev": true 1254 | }, 1255 | "inherits": { 1256 | "version": "2.0.4", 1257 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1258 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1259 | }, 1260 | "ini": { 1261 | "version": "1.3.8", 1262 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 1263 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 1264 | }, 1265 | "interpret": { 1266 | "version": "2.2.0", 1267 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", 1268 | "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" 1269 | }, 1270 | "is-absolute": { 1271 | "version": "1.0.0", 1272 | "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", 1273 | "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", 1274 | "requires": { 1275 | "is-relative": "^1.0.0", 1276 | "is-windows": "^1.0.1" 1277 | } 1278 | }, 1279 | "is-accessor-descriptor": { 1280 | "version": "0.1.6", 1281 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 1282 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 1283 | "requires": { 1284 | "kind-of": "^3.0.2" 1285 | }, 1286 | "dependencies": { 1287 | "kind-of": { 1288 | "version": "3.2.2", 1289 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1290 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1291 | "requires": { 1292 | "is-buffer": "^1.1.5" 1293 | } 1294 | } 1295 | } 1296 | }, 1297 | "is-binary-path": { 1298 | "version": "2.1.0", 1299 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1300 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1301 | "dev": true, 1302 | "requires": { 1303 | "binary-extensions": "^2.0.0" 1304 | } 1305 | }, 1306 | "is-buffer": { 1307 | "version": "1.1.6", 1308 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1309 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 1310 | }, 1311 | "is-callable": { 1312 | "version": "1.2.0", 1313 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", 1314 | "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" 1315 | }, 1316 | "is-ci": { 1317 | "version": "2.0.0", 1318 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", 1319 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", 1320 | "dev": true, 1321 | "requires": { 1322 | "ci-info": "^2.0.0" 1323 | } 1324 | }, 1325 | "is-core-module": { 1326 | "version": "2.3.0", 1327 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.3.0.tgz", 1328 | "integrity": "sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==", 1329 | "requires": { 1330 | "has": "^1.0.3" 1331 | } 1332 | }, 1333 | "is-data-descriptor": { 1334 | "version": "0.1.4", 1335 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 1336 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 1337 | "requires": { 1338 | "kind-of": "^3.0.2" 1339 | }, 1340 | "dependencies": { 1341 | "kind-of": { 1342 | "version": "3.2.2", 1343 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1344 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1345 | "requires": { 1346 | "is-buffer": "^1.1.5" 1347 | } 1348 | } 1349 | } 1350 | }, 1351 | "is-date-object": { 1352 | "version": "1.0.2", 1353 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 1354 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" 1355 | }, 1356 | "is-descriptor": { 1357 | "version": "0.1.6", 1358 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 1359 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 1360 | "requires": { 1361 | "is-accessor-descriptor": "^0.1.6", 1362 | "is-data-descriptor": "^0.1.4", 1363 | "kind-of": "^5.0.0" 1364 | }, 1365 | "dependencies": { 1366 | "kind-of": { 1367 | "version": "5.1.0", 1368 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 1369 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" 1370 | } 1371 | } 1372 | }, 1373 | "is-extendable": { 1374 | "version": "0.1.1", 1375 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1376 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" 1377 | }, 1378 | "is-extglob": { 1379 | "version": "2.1.1", 1380 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1381 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" 1382 | }, 1383 | "is-fullwidth-code-point": { 1384 | "version": "2.0.0", 1385 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1386 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1387 | "dev": true 1388 | }, 1389 | "is-glob": { 1390 | "version": "4.0.1", 1391 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1392 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1393 | "requires": { 1394 | "is-extglob": "^2.1.1" 1395 | } 1396 | }, 1397 | "is-installed-globally": { 1398 | "version": "0.3.2", 1399 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", 1400 | "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", 1401 | "dev": true, 1402 | "requires": { 1403 | "global-dirs": "^2.0.1", 1404 | "is-path-inside": "^3.0.1" 1405 | } 1406 | }, 1407 | "is-npm": { 1408 | "version": "4.0.0", 1409 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", 1410 | "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", 1411 | "dev": true 1412 | }, 1413 | "is-number": { 1414 | "version": "3.0.0", 1415 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 1416 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 1417 | "requires": { 1418 | "kind-of": "^3.0.2" 1419 | }, 1420 | "dependencies": { 1421 | "kind-of": { 1422 | "version": "3.2.2", 1423 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1424 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1425 | "requires": { 1426 | "is-buffer": "^1.1.5" 1427 | } 1428 | } 1429 | } 1430 | }, 1431 | "is-obj": { 1432 | "version": "2.0.0", 1433 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", 1434 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", 1435 | "dev": true 1436 | }, 1437 | "is-path-inside": { 1438 | "version": "3.0.2", 1439 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", 1440 | "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", 1441 | "dev": true 1442 | }, 1443 | "is-plain-object": { 1444 | "version": "2.0.4", 1445 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 1446 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 1447 | "requires": { 1448 | "isobject": "^3.0.1" 1449 | } 1450 | }, 1451 | "is-regex": { 1452 | "version": "1.1.1", 1453 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", 1454 | "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", 1455 | "requires": { 1456 | "has-symbols": "^1.0.1" 1457 | } 1458 | }, 1459 | "is-relative": { 1460 | "version": "1.0.0", 1461 | "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", 1462 | "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", 1463 | "requires": { 1464 | "is-unc-path": "^1.0.0" 1465 | } 1466 | }, 1467 | "is-symbol": { 1468 | "version": "1.0.3", 1469 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 1470 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 1471 | "requires": { 1472 | "has-symbols": "^1.0.1" 1473 | } 1474 | }, 1475 | "is-typedarray": { 1476 | "version": "1.0.0", 1477 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 1478 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 1479 | }, 1480 | "is-unc-path": { 1481 | "version": "1.0.0", 1482 | "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", 1483 | "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", 1484 | "requires": { 1485 | "unc-path-regex": "^0.1.2" 1486 | } 1487 | }, 1488 | "is-windows": { 1489 | "version": "1.0.2", 1490 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 1491 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" 1492 | }, 1493 | "is-yarn-global": { 1494 | "version": "0.3.0", 1495 | "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", 1496 | "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", 1497 | "dev": true 1498 | }, 1499 | "isarray": { 1500 | "version": "1.0.0", 1501 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1502 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1503 | }, 1504 | "isexe": { 1505 | "version": "2.0.0", 1506 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1507 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 1508 | }, 1509 | "isobject": { 1510 | "version": "3.0.1", 1511 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 1512 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" 1513 | }, 1514 | "isstream": { 1515 | "version": "0.1.2", 1516 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 1517 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 1518 | }, 1519 | "jsbn": { 1520 | "version": "0.1.1", 1521 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 1522 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 1523 | }, 1524 | "json-buffer": { 1525 | "version": "3.0.0", 1526 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", 1527 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", 1528 | "dev": true 1529 | }, 1530 | "json-schema": { 1531 | "version": "0.2.3", 1532 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 1533 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 1534 | }, 1535 | "json-schema-traverse": { 1536 | "version": "0.4.1", 1537 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1538 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 1539 | }, 1540 | "json-stringify-safe": { 1541 | "version": "5.0.1", 1542 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 1543 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 1544 | }, 1545 | "jsprim": { 1546 | "version": "1.4.1", 1547 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 1548 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 1549 | "requires": { 1550 | "assert-plus": "1.0.0", 1551 | "extsprintf": "1.3.0", 1552 | "json-schema": "0.2.3", 1553 | "verror": "1.10.0" 1554 | } 1555 | }, 1556 | "keyv": { 1557 | "version": "3.1.0", 1558 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", 1559 | "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", 1560 | "dev": true, 1561 | "requires": { 1562 | "json-buffer": "3.0.0" 1563 | } 1564 | }, 1565 | "kind-of": { 1566 | "version": "6.0.3", 1567 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 1568 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" 1569 | }, 1570 | "knex": { 1571 | "version": "0.20.15", 1572 | "resolved": "https://registry.npmjs.org/knex/-/knex-0.20.15.tgz", 1573 | "integrity": "sha512-WHmvgfQfxA5v8pyb9zbskxCS1L1WmYgUbwBhHojlkmdouUOazvroUWlCr6KIKMQ8anXZh1NXOOtIUMnxENZG5Q==", 1574 | "requires": { 1575 | "colorette": "1.1.0", 1576 | "commander": "^4.1.1", 1577 | "debug": "4.1.1", 1578 | "esm": "^3.2.25", 1579 | "getopts": "2.2.5", 1580 | "inherits": "~2.0.4", 1581 | "interpret": "^2.0.0", 1582 | "liftoff": "3.1.0", 1583 | "lodash": "^4.17.15", 1584 | "mkdirp": "^0.5.1", 1585 | "pg-connection-string": "2.1.0", 1586 | "tarn": "^2.0.0", 1587 | "tildify": "2.0.0", 1588 | "uuid": "^7.0.1", 1589 | "v8flags": "^3.1.3" 1590 | }, 1591 | "dependencies": { 1592 | "uuid": { 1593 | "version": "7.0.3", 1594 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", 1595 | "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" 1596 | } 1597 | } 1598 | }, 1599 | "latest-version": { 1600 | "version": "5.1.0", 1601 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", 1602 | "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", 1603 | "dev": true, 1604 | "requires": { 1605 | "package-json": "^6.3.0" 1606 | } 1607 | }, 1608 | "liftoff": { 1609 | "version": "3.1.0", 1610 | "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", 1611 | "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", 1612 | "requires": { 1613 | "extend": "^3.0.0", 1614 | "findup-sync": "^3.0.0", 1615 | "fined": "^1.0.1", 1616 | "flagged-respawn": "^1.0.0", 1617 | "is-plain-object": "^2.0.4", 1618 | "object.map": "^1.0.0", 1619 | "rechoir": "^0.6.2", 1620 | "resolve": "^1.1.7" 1621 | } 1622 | }, 1623 | "lodash": { 1624 | "version": "4.17.21", 1625 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1626 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 1627 | }, 1628 | "lowercase-keys": { 1629 | "version": "1.0.1", 1630 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 1631 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", 1632 | "dev": true 1633 | }, 1634 | "make-dir": { 1635 | "version": "3.1.0", 1636 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 1637 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 1638 | "dev": true, 1639 | "requires": { 1640 | "semver": "^6.0.0" 1641 | }, 1642 | "dependencies": { 1643 | "semver": { 1644 | "version": "6.3.0", 1645 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1646 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1647 | "dev": true 1648 | } 1649 | } 1650 | }, 1651 | "make-iterator": { 1652 | "version": "1.0.1", 1653 | "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", 1654 | "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", 1655 | "requires": { 1656 | "kind-of": "^6.0.2" 1657 | } 1658 | }, 1659 | "map-cache": { 1660 | "version": "0.2.2", 1661 | "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", 1662 | "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" 1663 | }, 1664 | "map-visit": { 1665 | "version": "1.0.0", 1666 | "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", 1667 | "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", 1668 | "requires": { 1669 | "object-visit": "^1.0.0" 1670 | } 1671 | }, 1672 | "micromatch": { 1673 | "version": "3.1.10", 1674 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", 1675 | "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", 1676 | "requires": { 1677 | "arr-diff": "^4.0.0", 1678 | "array-unique": "^0.3.2", 1679 | "braces": "^2.3.1", 1680 | "define-property": "^2.0.2", 1681 | "extend-shallow": "^3.0.2", 1682 | "extglob": "^2.0.4", 1683 | "fragment-cache": "^0.2.1", 1684 | "kind-of": "^6.0.2", 1685 | "nanomatch": "^1.2.9", 1686 | "object.pick": "^1.3.0", 1687 | "regex-not": "^1.0.0", 1688 | "snapdragon": "^0.8.1", 1689 | "to-regex": "^3.0.2" 1690 | } 1691 | }, 1692 | "mime": { 1693 | "version": "1.6.0", 1694 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1695 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 1696 | }, 1697 | "mime-db": { 1698 | "version": "1.43.0", 1699 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", 1700 | "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" 1701 | }, 1702 | "mime-types": { 1703 | "version": "2.1.26", 1704 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", 1705 | "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", 1706 | "requires": { 1707 | "mime-db": "1.43.0" 1708 | } 1709 | }, 1710 | "mimic-response": { 1711 | "version": "1.0.1", 1712 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 1713 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", 1714 | "dev": true 1715 | }, 1716 | "minimatch": { 1717 | "version": "3.0.4", 1718 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1719 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1720 | "dev": true, 1721 | "requires": { 1722 | "brace-expansion": "^1.1.7" 1723 | } 1724 | }, 1725 | "minimist": { 1726 | "version": "1.2.5", 1727 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 1728 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 1729 | }, 1730 | "mixin-deep": { 1731 | "version": "1.3.2", 1732 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", 1733 | "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", 1734 | "requires": { 1735 | "for-in": "^1.0.2", 1736 | "is-extendable": "^1.0.1" 1737 | }, 1738 | "dependencies": { 1739 | "is-extendable": { 1740 | "version": "1.0.1", 1741 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 1742 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 1743 | "requires": { 1744 | "is-plain-object": "^2.0.4" 1745 | } 1746 | } 1747 | } 1748 | }, 1749 | "mkdirp": { 1750 | "version": "0.5.5", 1751 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 1752 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 1753 | "requires": { 1754 | "minimist": "^1.2.5" 1755 | } 1756 | }, 1757 | "ms": { 1758 | "version": "2.1.2", 1759 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1760 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1761 | }, 1762 | "nanomatch": { 1763 | "version": "1.2.13", 1764 | "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", 1765 | "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", 1766 | "requires": { 1767 | "arr-diff": "^4.0.0", 1768 | "array-unique": "^0.3.2", 1769 | "define-property": "^2.0.2", 1770 | "extend-shallow": "^3.0.2", 1771 | "fragment-cache": "^0.2.1", 1772 | "is-windows": "^1.0.2", 1773 | "kind-of": "^6.0.2", 1774 | "object.pick": "^1.3.0", 1775 | "regex-not": "^1.0.0", 1776 | "snapdragon": "^0.8.1", 1777 | "to-regex": "^3.0.1" 1778 | } 1779 | }, 1780 | "node-telegram-bot-api": { 1781 | "version": "0.40.0", 1782 | "resolved": "https://registry.npmjs.org/node-telegram-bot-api/-/node-telegram-bot-api-0.40.0.tgz", 1783 | "integrity": "sha512-kDVCU1Y0L7hDnkm8oosO7cKIRyftPOvIGMvDbj7CU/FDIqqkC13VytRieHb/pFgTfFmiCpBTzAeK66YLHIfchQ==", 1784 | "requires": { 1785 | "array.prototype.findindex": "^2.0.2", 1786 | "bl": "^1.2.1", 1787 | "bluebird": "^3.5.1", 1788 | "debug": "^3.1.0", 1789 | "depd": "^1.1.1", 1790 | "eventemitter3": "^3.0.0", 1791 | "file-type": "^3.9.0", 1792 | "mime": "^1.6.0", 1793 | "pump": "^2.0.0", 1794 | "request": "^2.83.0", 1795 | "request-promise": "^4.2.2" 1796 | }, 1797 | "dependencies": { 1798 | "debug": { 1799 | "version": "3.2.6", 1800 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1801 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 1802 | "requires": { 1803 | "ms": "^2.1.1" 1804 | } 1805 | } 1806 | } 1807 | }, 1808 | "nodemon": { 1809 | "version": "2.0.4", 1810 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", 1811 | "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", 1812 | "dev": true, 1813 | "requires": { 1814 | "chokidar": "^3.2.2", 1815 | "debug": "^3.2.6", 1816 | "ignore-by-default": "^1.0.1", 1817 | "minimatch": "^3.0.4", 1818 | "pstree.remy": "^1.1.7", 1819 | "semver": "^5.7.1", 1820 | "supports-color": "^5.5.0", 1821 | "touch": "^3.1.0", 1822 | "undefsafe": "^2.0.2", 1823 | "update-notifier": "^4.0.0" 1824 | }, 1825 | "dependencies": { 1826 | "debug": { 1827 | "version": "3.2.6", 1828 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1829 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 1830 | "dev": true, 1831 | "requires": { 1832 | "ms": "^2.1.1" 1833 | } 1834 | } 1835 | } 1836 | }, 1837 | "nopt": { 1838 | "version": "1.0.10", 1839 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 1840 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", 1841 | "dev": true, 1842 | "requires": { 1843 | "abbrev": "1" 1844 | } 1845 | }, 1846 | "normalize-path": { 1847 | "version": "3.0.0", 1848 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1849 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1850 | "dev": true 1851 | }, 1852 | "normalize-url": { 1853 | "version": "4.5.0", 1854 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", 1855 | "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", 1856 | "dev": true 1857 | }, 1858 | "oauth-sign": { 1859 | "version": "0.9.0", 1860 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 1861 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 1862 | }, 1863 | "object-copy": { 1864 | "version": "0.1.0", 1865 | "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", 1866 | "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", 1867 | "requires": { 1868 | "copy-descriptor": "^0.1.0", 1869 | "define-property": "^0.2.5", 1870 | "kind-of": "^3.0.3" 1871 | }, 1872 | "dependencies": { 1873 | "define-property": { 1874 | "version": "0.2.5", 1875 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 1876 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 1877 | "requires": { 1878 | "is-descriptor": "^0.1.0" 1879 | } 1880 | }, 1881 | "kind-of": { 1882 | "version": "3.2.2", 1883 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1884 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1885 | "requires": { 1886 | "is-buffer": "^1.1.5" 1887 | } 1888 | } 1889 | } 1890 | }, 1891 | "object-inspect": { 1892 | "version": "1.8.0", 1893 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", 1894 | "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" 1895 | }, 1896 | "object-keys": { 1897 | "version": "1.1.1", 1898 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1899 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 1900 | }, 1901 | "object-visit": { 1902 | "version": "1.0.1", 1903 | "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", 1904 | "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", 1905 | "requires": { 1906 | "isobject": "^3.0.0" 1907 | } 1908 | }, 1909 | "object.assign": { 1910 | "version": "4.1.0", 1911 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 1912 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 1913 | "requires": { 1914 | "define-properties": "^1.1.2", 1915 | "function-bind": "^1.1.1", 1916 | "has-symbols": "^1.0.0", 1917 | "object-keys": "^1.0.11" 1918 | } 1919 | }, 1920 | "object.defaults": { 1921 | "version": "1.1.0", 1922 | "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", 1923 | "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", 1924 | "requires": { 1925 | "array-each": "^1.0.1", 1926 | "array-slice": "^1.0.0", 1927 | "for-own": "^1.0.0", 1928 | "isobject": "^3.0.0" 1929 | } 1930 | }, 1931 | "object.map": { 1932 | "version": "1.0.1", 1933 | "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", 1934 | "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", 1935 | "requires": { 1936 | "for-own": "^1.0.0", 1937 | "make-iterator": "^1.0.0" 1938 | } 1939 | }, 1940 | "object.pick": { 1941 | "version": "1.3.0", 1942 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 1943 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 1944 | "requires": { 1945 | "isobject": "^3.0.1" 1946 | } 1947 | }, 1948 | "once": { 1949 | "version": "1.4.0", 1950 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1951 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1952 | "requires": { 1953 | "wrappy": "1" 1954 | } 1955 | }, 1956 | "p-cancelable": { 1957 | "version": "1.1.0", 1958 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", 1959 | "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", 1960 | "dev": true 1961 | }, 1962 | "package-json": { 1963 | "version": "6.5.0", 1964 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", 1965 | "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", 1966 | "dev": true, 1967 | "requires": { 1968 | "got": "^9.6.0", 1969 | "registry-auth-token": "^4.0.0", 1970 | "registry-url": "^5.0.0", 1971 | "semver": "^6.2.0" 1972 | }, 1973 | "dependencies": { 1974 | "semver": { 1975 | "version": "6.3.0", 1976 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1977 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1978 | "dev": true 1979 | } 1980 | } 1981 | }, 1982 | "packet-reader": { 1983 | "version": "1.0.0", 1984 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 1985 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 1986 | }, 1987 | "parse-filepath": { 1988 | "version": "1.0.2", 1989 | "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", 1990 | "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", 1991 | "requires": { 1992 | "is-absolute": "^1.0.0", 1993 | "map-cache": "^0.2.0", 1994 | "path-root": "^0.1.1" 1995 | } 1996 | }, 1997 | "parse-passwd": { 1998 | "version": "1.0.0", 1999 | "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", 2000 | "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" 2001 | }, 2002 | "pascalcase": { 2003 | "version": "0.1.1", 2004 | "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", 2005 | "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" 2006 | }, 2007 | "path-parse": { 2008 | "version": "1.0.6", 2009 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 2010 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 2011 | }, 2012 | "path-root": { 2013 | "version": "0.1.1", 2014 | "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", 2015 | "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", 2016 | "requires": { 2017 | "path-root-regex": "^0.1.0" 2018 | } 2019 | }, 2020 | "path-root-regex": { 2021 | "version": "0.1.2", 2022 | "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", 2023 | "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" 2024 | }, 2025 | "performance-now": { 2026 | "version": "2.1.0", 2027 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 2028 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 2029 | }, 2030 | "pg": { 2031 | "version": "8.6.0", 2032 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.6.0.tgz", 2033 | "integrity": "sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ==", 2034 | "requires": { 2035 | "buffer-writer": "2.0.0", 2036 | "packet-reader": "1.0.0", 2037 | "pg-connection-string": "^2.5.0", 2038 | "pg-pool": "^3.3.0", 2039 | "pg-protocol": "^1.5.0", 2040 | "pg-types": "^2.1.0", 2041 | "pgpass": "1.x" 2042 | }, 2043 | "dependencies": { 2044 | "pg-connection-string": { 2045 | "version": "2.5.0", 2046 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 2047 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 2048 | } 2049 | } 2050 | }, 2051 | "pg-connection-string": { 2052 | "version": "2.1.0", 2053 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.1.0.tgz", 2054 | "integrity": "sha512-bhlV7Eq09JrRIvo1eKngpwuqKtJnNhZdpdOlvrPrA4dxqXPjxSrbNrfnIDmTpwMyRszrcV4kU5ZA4mMsQUrjdg==" 2055 | }, 2056 | "pg-int8": { 2057 | "version": "1.0.1", 2058 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 2059 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" 2060 | }, 2061 | "pg-pool": { 2062 | "version": "3.3.0", 2063 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.3.0.tgz", 2064 | "integrity": "sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==" 2065 | }, 2066 | "pg-protocol": { 2067 | "version": "1.5.0", 2068 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 2069 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 2070 | }, 2071 | "pg-types": { 2072 | "version": "2.2.0", 2073 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 2074 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 2075 | "requires": { 2076 | "pg-int8": "1.0.1", 2077 | "postgres-array": "~2.0.0", 2078 | "postgres-bytea": "~1.0.0", 2079 | "postgres-date": "~1.0.4", 2080 | "postgres-interval": "^1.1.0" 2081 | } 2082 | }, 2083 | "pgpass": { 2084 | "version": "1.0.4", 2085 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", 2086 | "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", 2087 | "requires": { 2088 | "split2": "^3.1.1" 2089 | } 2090 | }, 2091 | "picomatch": { 2092 | "version": "2.2.2", 2093 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 2094 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 2095 | "dev": true 2096 | }, 2097 | "pino": { 2098 | "version": "6.5.1", 2099 | "resolved": "https://registry.npmjs.org/pino/-/pino-6.5.1.tgz", 2100 | "integrity": "sha512-76+RUhQkqjUD4AtQcSfEzh6vlsjXmoWZK5gg+2d70aCLXZTbo4/5js4I9rN1Xk6z1h2/7pnOFX10G4c2T4qNiA==", 2101 | "requires": { 2102 | "fast-redact": "^2.0.0", 2103 | "fast-safe-stringify": "^2.0.7", 2104 | "flatstr": "^1.0.12", 2105 | "pino-std-serializers": "^2.4.2", 2106 | "quick-format-unescaped": "^4.0.1", 2107 | "sonic-boom": "^1.0.2" 2108 | } 2109 | }, 2110 | "pino-std-serializers": { 2111 | "version": "2.5.0", 2112 | "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.5.0.tgz", 2113 | "integrity": "sha512-wXqbqSrIhE58TdrxxlfLwU9eDhrzppQDvGhBEr1gYbzzM4KKo3Y63gSjiDXRKLVS2UOXdPNR2v+KnQgNrs+xUg==" 2114 | }, 2115 | "posix-character-classes": { 2116 | "version": "0.1.1", 2117 | "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 2118 | "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" 2119 | }, 2120 | "postgres-array": { 2121 | "version": "2.0.0", 2122 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 2123 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" 2124 | }, 2125 | "postgres-bytea": { 2126 | "version": "1.0.0", 2127 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 2128 | "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" 2129 | }, 2130 | "postgres-date": { 2131 | "version": "1.0.7", 2132 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 2133 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" 2134 | }, 2135 | "postgres-interval": { 2136 | "version": "1.2.0", 2137 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 2138 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 2139 | "requires": { 2140 | "xtend": "^4.0.0" 2141 | } 2142 | }, 2143 | "prepend-http": { 2144 | "version": "2.0.0", 2145 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", 2146 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", 2147 | "dev": true 2148 | }, 2149 | "process-nextick-args": { 2150 | "version": "2.0.1", 2151 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 2152 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 2153 | }, 2154 | "psl": { 2155 | "version": "1.8.0", 2156 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", 2157 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" 2158 | }, 2159 | "pstree.remy": { 2160 | "version": "1.1.8", 2161 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 2162 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 2163 | "dev": true 2164 | }, 2165 | "pump": { 2166 | "version": "2.0.1", 2167 | "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", 2168 | "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", 2169 | "requires": { 2170 | "end-of-stream": "^1.1.0", 2171 | "once": "^1.3.1" 2172 | } 2173 | }, 2174 | "punycode": { 2175 | "version": "2.1.1", 2176 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 2177 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 2178 | }, 2179 | "pupa": { 2180 | "version": "2.0.1", 2181 | "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", 2182 | "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", 2183 | "dev": true, 2184 | "requires": { 2185 | "escape-goat": "^2.0.0" 2186 | } 2187 | }, 2188 | "qs": { 2189 | "version": "6.5.2", 2190 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 2191 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 2192 | }, 2193 | "quick-format-unescaped": { 2194 | "version": "4.0.1", 2195 | "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz", 2196 | "integrity": "sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A==" 2197 | }, 2198 | "rc": { 2199 | "version": "1.2.8", 2200 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 2201 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 2202 | "dev": true, 2203 | "requires": { 2204 | "deep-extend": "^0.6.0", 2205 | "ini": "~1.3.0", 2206 | "minimist": "^1.2.0", 2207 | "strip-json-comments": "~2.0.1" 2208 | } 2209 | }, 2210 | "readable-stream": { 2211 | "version": "2.3.7", 2212 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 2213 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 2214 | "requires": { 2215 | "core-util-is": "~1.0.0", 2216 | "inherits": "~2.0.3", 2217 | "isarray": "~1.0.0", 2218 | "process-nextick-args": "~2.0.0", 2219 | "safe-buffer": "~5.1.1", 2220 | "string_decoder": "~1.1.1", 2221 | "util-deprecate": "~1.0.1" 2222 | } 2223 | }, 2224 | "readdirp": { 2225 | "version": "3.4.0", 2226 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", 2227 | "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", 2228 | "dev": true, 2229 | "requires": { 2230 | "picomatch": "^2.2.1" 2231 | } 2232 | }, 2233 | "rechoir": { 2234 | "version": "0.6.2", 2235 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 2236 | "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", 2237 | "requires": { 2238 | "resolve": "^1.1.6" 2239 | } 2240 | }, 2241 | "regex-not": { 2242 | "version": "1.0.2", 2243 | "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", 2244 | "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", 2245 | "requires": { 2246 | "extend-shallow": "^3.0.2", 2247 | "safe-regex": "^1.1.0" 2248 | } 2249 | }, 2250 | "registry-auth-token": { 2251 | "version": "4.2.0", 2252 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz", 2253 | "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==", 2254 | "dev": true, 2255 | "requires": { 2256 | "rc": "^1.2.8" 2257 | } 2258 | }, 2259 | "registry-url": { 2260 | "version": "5.1.0", 2261 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", 2262 | "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", 2263 | "dev": true, 2264 | "requires": { 2265 | "rc": "^1.2.8" 2266 | } 2267 | }, 2268 | "repeat-element": { 2269 | "version": "1.1.4", 2270 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", 2271 | "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" 2272 | }, 2273 | "repeat-string": { 2274 | "version": "1.6.1", 2275 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 2276 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" 2277 | }, 2278 | "request": { 2279 | "version": "2.88.2", 2280 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", 2281 | "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", 2282 | "requires": { 2283 | "aws-sign2": "~0.7.0", 2284 | "aws4": "^1.8.0", 2285 | "caseless": "~0.12.0", 2286 | "combined-stream": "~1.0.6", 2287 | "extend": "~3.0.2", 2288 | "forever-agent": "~0.6.1", 2289 | "form-data": "~2.3.2", 2290 | "har-validator": "~5.1.3", 2291 | "http-signature": "~1.2.0", 2292 | "is-typedarray": "~1.0.0", 2293 | "isstream": "~0.1.2", 2294 | "json-stringify-safe": "~5.0.1", 2295 | "mime-types": "~2.1.19", 2296 | "oauth-sign": "~0.9.0", 2297 | "performance-now": "^2.1.0", 2298 | "qs": "~6.5.2", 2299 | "safe-buffer": "^5.1.2", 2300 | "tough-cookie": "~2.5.0", 2301 | "tunnel-agent": "^0.6.0", 2302 | "uuid": "^3.3.2" 2303 | }, 2304 | "dependencies": { 2305 | "uuid": { 2306 | "version": "3.4.0", 2307 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", 2308 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" 2309 | } 2310 | } 2311 | }, 2312 | "request-promise": { 2313 | "version": "4.2.6", 2314 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", 2315 | "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", 2316 | "requires": { 2317 | "bluebird": "^3.5.0", 2318 | "request-promise-core": "1.1.4", 2319 | "stealthy-require": "^1.1.1", 2320 | "tough-cookie": "^2.3.3" 2321 | } 2322 | }, 2323 | "request-promise-core": { 2324 | "version": "1.1.4", 2325 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", 2326 | "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", 2327 | "requires": { 2328 | "lodash": "^4.17.19" 2329 | }, 2330 | "dependencies": { 2331 | "lodash": { 2332 | "version": "4.17.20", 2333 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 2334 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 2335 | } 2336 | } 2337 | }, 2338 | "resolve": { 2339 | "version": "1.20.0", 2340 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 2341 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 2342 | "requires": { 2343 | "is-core-module": "^2.2.0", 2344 | "path-parse": "^1.0.6" 2345 | } 2346 | }, 2347 | "resolve-dir": { 2348 | "version": "1.0.1", 2349 | "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", 2350 | "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", 2351 | "requires": { 2352 | "expand-tilde": "^2.0.0", 2353 | "global-modules": "^1.0.0" 2354 | } 2355 | }, 2356 | "resolve-url": { 2357 | "version": "0.2.1", 2358 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 2359 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" 2360 | }, 2361 | "responselike": { 2362 | "version": "1.0.2", 2363 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", 2364 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", 2365 | "dev": true, 2366 | "requires": { 2367 | "lowercase-keys": "^1.0.0" 2368 | } 2369 | }, 2370 | "ret": { 2371 | "version": "0.1.15", 2372 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", 2373 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" 2374 | }, 2375 | "safe-buffer": { 2376 | "version": "5.1.2", 2377 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 2378 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 2379 | }, 2380 | "safe-regex": { 2381 | "version": "1.1.0", 2382 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", 2383 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", 2384 | "requires": { 2385 | "ret": "~0.1.10" 2386 | } 2387 | }, 2388 | "safer-buffer": { 2389 | "version": "2.1.2", 2390 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2391 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 2392 | }, 2393 | "semver": { 2394 | "version": "5.7.1", 2395 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 2396 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 2397 | "dev": true 2398 | }, 2399 | "semver-diff": { 2400 | "version": "3.1.1", 2401 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", 2402 | "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", 2403 | "dev": true, 2404 | "requires": { 2405 | "semver": "^6.3.0" 2406 | }, 2407 | "dependencies": { 2408 | "semver": { 2409 | "version": "6.3.0", 2410 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 2411 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 2412 | "dev": true 2413 | } 2414 | } 2415 | }, 2416 | "set-value": { 2417 | "version": "2.0.1", 2418 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", 2419 | "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", 2420 | "requires": { 2421 | "extend-shallow": "^2.0.1", 2422 | "is-extendable": "^0.1.1", 2423 | "is-plain-object": "^2.0.3", 2424 | "split-string": "^3.0.1" 2425 | }, 2426 | "dependencies": { 2427 | "extend-shallow": { 2428 | "version": "2.0.1", 2429 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 2430 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 2431 | "requires": { 2432 | "is-extendable": "^0.1.0" 2433 | } 2434 | } 2435 | } 2436 | }, 2437 | "signal-exit": { 2438 | "version": "3.0.3", 2439 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 2440 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", 2441 | "dev": true 2442 | }, 2443 | "snapdragon": { 2444 | "version": "0.8.2", 2445 | "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", 2446 | "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", 2447 | "requires": { 2448 | "base": "^0.11.1", 2449 | "debug": "^2.2.0", 2450 | "define-property": "^0.2.5", 2451 | "extend-shallow": "^2.0.1", 2452 | "map-cache": "^0.2.2", 2453 | "source-map": "^0.5.6", 2454 | "source-map-resolve": "^0.5.0", 2455 | "use": "^3.1.0" 2456 | }, 2457 | "dependencies": { 2458 | "debug": { 2459 | "version": "2.6.9", 2460 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 2461 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 2462 | "requires": { 2463 | "ms": "2.0.0" 2464 | } 2465 | }, 2466 | "define-property": { 2467 | "version": "0.2.5", 2468 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 2469 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 2470 | "requires": { 2471 | "is-descriptor": "^0.1.0" 2472 | } 2473 | }, 2474 | "extend-shallow": { 2475 | "version": "2.0.1", 2476 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 2477 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 2478 | "requires": { 2479 | "is-extendable": "^0.1.0" 2480 | } 2481 | }, 2482 | "ms": { 2483 | "version": "2.0.0", 2484 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2485 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 2486 | } 2487 | } 2488 | }, 2489 | "snapdragon-node": { 2490 | "version": "2.1.1", 2491 | "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", 2492 | "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", 2493 | "requires": { 2494 | "define-property": "^1.0.0", 2495 | "isobject": "^3.0.0", 2496 | "snapdragon-util": "^3.0.1" 2497 | }, 2498 | "dependencies": { 2499 | "define-property": { 2500 | "version": "1.0.0", 2501 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 2502 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 2503 | "requires": { 2504 | "is-descriptor": "^1.0.0" 2505 | } 2506 | }, 2507 | "is-accessor-descriptor": { 2508 | "version": "1.0.0", 2509 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 2510 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 2511 | "requires": { 2512 | "kind-of": "^6.0.0" 2513 | } 2514 | }, 2515 | "is-data-descriptor": { 2516 | "version": "1.0.0", 2517 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 2518 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 2519 | "requires": { 2520 | "kind-of": "^6.0.0" 2521 | } 2522 | }, 2523 | "is-descriptor": { 2524 | "version": "1.0.2", 2525 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 2526 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 2527 | "requires": { 2528 | "is-accessor-descriptor": "^1.0.0", 2529 | "is-data-descriptor": "^1.0.0", 2530 | "kind-of": "^6.0.2" 2531 | } 2532 | } 2533 | } 2534 | }, 2535 | "snapdragon-util": { 2536 | "version": "3.0.1", 2537 | "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", 2538 | "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", 2539 | "requires": { 2540 | "kind-of": "^3.2.0" 2541 | }, 2542 | "dependencies": { 2543 | "kind-of": { 2544 | "version": "3.2.2", 2545 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2546 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2547 | "requires": { 2548 | "is-buffer": "^1.1.5" 2549 | } 2550 | } 2551 | } 2552 | }, 2553 | "sonic-boom": { 2554 | "version": "1.1.0", 2555 | "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.1.0.tgz", 2556 | "integrity": "sha512-JyOf+Xt7GBN4tAic/DD1Bitw6OMgSHAnswhPeOiLpfRoSjPNjEIi73UF3OxHzhSNn9WavxGuCZzprFCGFSNwog==", 2557 | "requires": { 2558 | "atomic-sleep": "^1.0.0", 2559 | "flatstr": "^1.0.12" 2560 | } 2561 | }, 2562 | "source-map": { 2563 | "version": "0.5.7", 2564 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 2565 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 2566 | }, 2567 | "source-map-resolve": { 2568 | "version": "0.5.3", 2569 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", 2570 | "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", 2571 | "requires": { 2572 | "atob": "^2.1.2", 2573 | "decode-uri-component": "^0.2.0", 2574 | "resolve-url": "^0.2.1", 2575 | "source-map-url": "^0.4.0", 2576 | "urix": "^0.1.0" 2577 | } 2578 | }, 2579 | "source-map-url": { 2580 | "version": "0.4.1", 2581 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", 2582 | "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" 2583 | }, 2584 | "split-string": { 2585 | "version": "3.1.0", 2586 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", 2587 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", 2588 | "requires": { 2589 | "extend-shallow": "^3.0.0" 2590 | } 2591 | }, 2592 | "split2": { 2593 | "version": "3.2.2", 2594 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 2595 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 2596 | "requires": { 2597 | "readable-stream": "^3.0.0" 2598 | }, 2599 | "dependencies": { 2600 | "readable-stream": { 2601 | "version": "3.6.0", 2602 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 2603 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 2604 | "requires": { 2605 | "inherits": "^2.0.3", 2606 | "string_decoder": "^1.1.1", 2607 | "util-deprecate": "^1.0.1" 2608 | } 2609 | } 2610 | } 2611 | }, 2612 | "sshpk": { 2613 | "version": "1.16.1", 2614 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 2615 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 2616 | "requires": { 2617 | "asn1": "~0.2.3", 2618 | "assert-plus": "^1.0.0", 2619 | "bcrypt-pbkdf": "^1.0.0", 2620 | "dashdash": "^1.12.0", 2621 | "ecc-jsbn": "~0.1.1", 2622 | "getpass": "^0.1.1", 2623 | "jsbn": "~0.1.0", 2624 | "safer-buffer": "^2.0.2", 2625 | "tweetnacl": "~0.14.0" 2626 | } 2627 | }, 2628 | "static-extend": { 2629 | "version": "0.1.2", 2630 | "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", 2631 | "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", 2632 | "requires": { 2633 | "define-property": "^0.2.5", 2634 | "object-copy": "^0.1.0" 2635 | }, 2636 | "dependencies": { 2637 | "define-property": { 2638 | "version": "0.2.5", 2639 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 2640 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 2641 | "requires": { 2642 | "is-descriptor": "^0.1.0" 2643 | } 2644 | } 2645 | } 2646 | }, 2647 | "stealthy-require": { 2648 | "version": "1.1.1", 2649 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 2650 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 2651 | }, 2652 | "string-width": { 2653 | "version": "4.2.0", 2654 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 2655 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 2656 | "dev": true, 2657 | "requires": { 2658 | "emoji-regex": "^8.0.0", 2659 | "is-fullwidth-code-point": "^3.0.0", 2660 | "strip-ansi": "^6.0.0" 2661 | }, 2662 | "dependencies": { 2663 | "ansi-regex": { 2664 | "version": "5.0.0", 2665 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 2666 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 2667 | "dev": true 2668 | }, 2669 | "emoji-regex": { 2670 | "version": "8.0.0", 2671 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 2672 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 2673 | "dev": true 2674 | }, 2675 | "is-fullwidth-code-point": { 2676 | "version": "3.0.0", 2677 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 2678 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 2679 | "dev": true 2680 | }, 2681 | "strip-ansi": { 2682 | "version": "6.0.0", 2683 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 2684 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 2685 | "dev": true, 2686 | "requires": { 2687 | "ansi-regex": "^5.0.0" 2688 | } 2689 | } 2690 | } 2691 | }, 2692 | "string.prototype.trimend": { 2693 | "version": "1.0.1", 2694 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", 2695 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", 2696 | "requires": { 2697 | "define-properties": "^1.1.3", 2698 | "es-abstract": "^1.17.5" 2699 | } 2700 | }, 2701 | "string.prototype.trimstart": { 2702 | "version": "1.0.1", 2703 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 2704 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", 2705 | "requires": { 2706 | "define-properties": "^1.1.3", 2707 | "es-abstract": "^1.17.5" 2708 | } 2709 | }, 2710 | "string_decoder": { 2711 | "version": "1.1.1", 2712 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 2713 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 2714 | "requires": { 2715 | "safe-buffer": "~5.1.0" 2716 | } 2717 | }, 2718 | "strip-ansi": { 2719 | "version": "5.2.0", 2720 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 2721 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 2722 | "dev": true, 2723 | "requires": { 2724 | "ansi-regex": "^4.1.0" 2725 | } 2726 | }, 2727 | "strip-json-comments": { 2728 | "version": "2.0.1", 2729 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 2730 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 2731 | "dev": true 2732 | }, 2733 | "supports-color": { 2734 | "version": "5.5.0", 2735 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2736 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2737 | "dev": true, 2738 | "requires": { 2739 | "has-flag": "^3.0.0" 2740 | } 2741 | }, 2742 | "tarn": { 2743 | "version": "2.0.0", 2744 | "resolved": "https://registry.npmjs.org/tarn/-/tarn-2.0.0.tgz", 2745 | "integrity": "sha512-7rNMCZd3s9bhQh47ksAQd92ADFcJUjjbyOvyFjNLwTPpGieFHMC84S+LOzw0fx1uh6hnDz/19r8CPMnIjJlMMA==" 2746 | }, 2747 | "term-size": { 2748 | "version": "2.2.0", 2749 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", 2750 | "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", 2751 | "dev": true 2752 | }, 2753 | "tildify": { 2754 | "version": "2.0.0", 2755 | "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", 2756 | "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" 2757 | }, 2758 | "to-object-path": { 2759 | "version": "0.3.0", 2760 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 2761 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 2762 | "requires": { 2763 | "kind-of": "^3.0.2" 2764 | }, 2765 | "dependencies": { 2766 | "kind-of": { 2767 | "version": "3.2.2", 2768 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2769 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2770 | "requires": { 2771 | "is-buffer": "^1.1.5" 2772 | } 2773 | } 2774 | } 2775 | }, 2776 | "to-readable-stream": { 2777 | "version": "1.0.0", 2778 | "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", 2779 | "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", 2780 | "dev": true 2781 | }, 2782 | "to-regex": { 2783 | "version": "3.0.2", 2784 | "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", 2785 | "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", 2786 | "requires": { 2787 | "define-property": "^2.0.2", 2788 | "extend-shallow": "^3.0.2", 2789 | "regex-not": "^1.0.2", 2790 | "safe-regex": "^1.1.0" 2791 | } 2792 | }, 2793 | "to-regex-range": { 2794 | "version": "2.1.1", 2795 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", 2796 | "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", 2797 | "requires": { 2798 | "is-number": "^3.0.0", 2799 | "repeat-string": "^1.6.1" 2800 | } 2801 | }, 2802 | "touch": { 2803 | "version": "3.1.0", 2804 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 2805 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 2806 | "dev": true, 2807 | "requires": { 2808 | "nopt": "~1.0.10" 2809 | } 2810 | }, 2811 | "tough-cookie": { 2812 | "version": "2.5.0", 2813 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", 2814 | "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", 2815 | "requires": { 2816 | "psl": "^1.1.28", 2817 | "punycode": "^2.1.1" 2818 | } 2819 | }, 2820 | "tunnel-agent": { 2821 | "version": "0.6.0", 2822 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 2823 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 2824 | "requires": { 2825 | "safe-buffer": "^5.0.1" 2826 | } 2827 | }, 2828 | "tweetnacl": { 2829 | "version": "0.14.5", 2830 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 2831 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 2832 | }, 2833 | "type-fest": { 2834 | "version": "0.8.1", 2835 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 2836 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 2837 | "dev": true 2838 | }, 2839 | "typedarray-to-buffer": { 2840 | "version": "3.1.5", 2841 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", 2842 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", 2843 | "dev": true, 2844 | "requires": { 2845 | "is-typedarray": "^1.0.0" 2846 | } 2847 | }, 2848 | "unc-path-regex": { 2849 | "version": "0.1.2", 2850 | "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", 2851 | "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" 2852 | }, 2853 | "undefsafe": { 2854 | "version": "2.0.3", 2855 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", 2856 | "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", 2857 | "dev": true, 2858 | "requires": { 2859 | "debug": "^2.2.0" 2860 | }, 2861 | "dependencies": { 2862 | "debug": { 2863 | "version": "2.6.9", 2864 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 2865 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 2866 | "dev": true, 2867 | "requires": { 2868 | "ms": "2.0.0" 2869 | } 2870 | }, 2871 | "ms": { 2872 | "version": "2.0.0", 2873 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2874 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 2875 | "dev": true 2876 | } 2877 | } 2878 | }, 2879 | "union-value": { 2880 | "version": "1.0.1", 2881 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", 2882 | "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", 2883 | "requires": { 2884 | "arr-union": "^3.1.0", 2885 | "get-value": "^2.0.6", 2886 | "is-extendable": "^0.1.1", 2887 | "set-value": "^2.0.1" 2888 | } 2889 | }, 2890 | "unique-string": { 2891 | "version": "2.0.0", 2892 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", 2893 | "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", 2894 | "dev": true, 2895 | "requires": { 2896 | "crypto-random-string": "^2.0.0" 2897 | } 2898 | }, 2899 | "unset-value": { 2900 | "version": "1.0.0", 2901 | "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", 2902 | "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", 2903 | "requires": { 2904 | "has-value": "^0.3.1", 2905 | "isobject": "^3.0.0" 2906 | }, 2907 | "dependencies": { 2908 | "has-value": { 2909 | "version": "0.3.1", 2910 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", 2911 | "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", 2912 | "requires": { 2913 | "get-value": "^2.0.3", 2914 | "has-values": "^0.1.4", 2915 | "isobject": "^2.0.0" 2916 | }, 2917 | "dependencies": { 2918 | "isobject": { 2919 | "version": "2.1.0", 2920 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 2921 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 2922 | "requires": { 2923 | "isarray": "1.0.0" 2924 | } 2925 | } 2926 | } 2927 | }, 2928 | "has-values": { 2929 | "version": "0.1.4", 2930 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", 2931 | "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" 2932 | } 2933 | } 2934 | }, 2935 | "update-notifier": { 2936 | "version": "4.1.1", 2937 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.1.tgz", 2938 | "integrity": "sha512-9y+Kds0+LoLG6yN802wVXoIfxYEwh3FlZwzMwpCZp62S2i1/Jzeqb9Eeeju3NSHccGGasfGlK5/vEHbAifYRDg==", 2939 | "dev": true, 2940 | "requires": { 2941 | "boxen": "^4.2.0", 2942 | "chalk": "^3.0.0", 2943 | "configstore": "^5.0.1", 2944 | "has-yarn": "^2.1.0", 2945 | "import-lazy": "^2.1.0", 2946 | "is-ci": "^2.0.0", 2947 | "is-installed-globally": "^0.3.1", 2948 | "is-npm": "^4.0.0", 2949 | "is-yarn-global": "^0.3.0", 2950 | "latest-version": "^5.0.0", 2951 | "pupa": "^2.0.1", 2952 | "semver-diff": "^3.1.1", 2953 | "xdg-basedir": "^4.0.0" 2954 | } 2955 | }, 2956 | "uri-js": { 2957 | "version": "4.2.2", 2958 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 2959 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 2960 | "requires": { 2961 | "punycode": "^2.1.0" 2962 | } 2963 | }, 2964 | "urix": { 2965 | "version": "0.1.0", 2966 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 2967 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" 2968 | }, 2969 | "url-parse-lax": { 2970 | "version": "3.0.0", 2971 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", 2972 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", 2973 | "dev": true, 2974 | "requires": { 2975 | "prepend-http": "^2.0.0" 2976 | } 2977 | }, 2978 | "use": { 2979 | "version": "3.1.1", 2980 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", 2981 | "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" 2982 | }, 2983 | "util-deprecate": { 2984 | "version": "1.0.2", 2985 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2986 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 2987 | }, 2988 | "uuid": { 2989 | "version": "8.3.0", 2990 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", 2991 | "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" 2992 | }, 2993 | "v8flags": { 2994 | "version": "3.2.0", 2995 | "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", 2996 | "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", 2997 | "requires": { 2998 | "homedir-polyfill": "^1.0.1" 2999 | } 3000 | }, 3001 | "verror": { 3002 | "version": "1.10.0", 3003 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 3004 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 3005 | "requires": { 3006 | "assert-plus": "^1.0.0", 3007 | "core-util-is": "1.0.2", 3008 | "extsprintf": "^1.2.0" 3009 | } 3010 | }, 3011 | "which": { 3012 | "version": "1.3.1", 3013 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 3014 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 3015 | "requires": { 3016 | "isexe": "^2.0.0" 3017 | } 3018 | }, 3019 | "widest-line": { 3020 | "version": "3.1.0", 3021 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", 3022 | "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", 3023 | "dev": true, 3024 | "requires": { 3025 | "string-width": "^4.0.0" 3026 | } 3027 | }, 3028 | "wrappy": { 3029 | "version": "1.0.2", 3030 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 3031 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 3032 | }, 3033 | "write-file-atomic": { 3034 | "version": "3.0.3", 3035 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", 3036 | "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", 3037 | "dev": true, 3038 | "requires": { 3039 | "imurmurhash": "^0.1.4", 3040 | "is-typedarray": "^1.0.0", 3041 | "signal-exit": "^3.0.2", 3042 | "typedarray-to-buffer": "^3.1.5" 3043 | } 3044 | }, 3045 | "xdg-basedir": { 3046 | "version": "4.0.0", 3047 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", 3048 | "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", 3049 | "dev": true 3050 | }, 3051 | "xtend": { 3052 | "version": "4.0.2", 3053 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 3054 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 3055 | } 3056 | } 3057 | } 3058 | -------------------------------------------------------------------------------- /bot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telegram-forwarder-bot-agent", 3 | "version": "1.0.0", 4 | "description": "Telegram bot that acts as a frontend for all the controls", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "node bot.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/adityathebe/telegramForwarder.git" 12 | }, 13 | "keywords": [], 14 | "author": "Aditya Thebe (https://www.adityathebe.com)", 15 | "license": "ISC", 16 | "dependencies": { 17 | "knex": "^0.20.15", 18 | "node-telegram-bot-api": "^0.40.0", 19 | "pg": "^8.6.0", 20 | "pino": "^6.5.1", 21 | "request": "^2.88.2", 22 | "uuid": "^8.3.0" 23 | }, 24 | "devDependencies": { 25 | "nodemon": "^2.0.4" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bot/readme.md: -------------------------------------------------------------------------------- 1 | # Database 2 | 3 | ### 1. User 4 | 5 | - chat_id* (string) 6 | - username (string) 7 | - ref_code (string) 8 | - ref_by (string) 9 | - premium (Boolean) 10 | 11 | ### 2. Redirections 12 | 13 | - id* (int) 14 | - owner (string) 15 | - source (string) 16 | - source_title (string) 17 | - destination (string) 18 | - destination_title (string) 19 | - active (boolean); 20 | 21 | ### 3. Filters 22 | 23 | - id* (int) 24 | - red_id 25 | - name 26 | - state 27 | 28 | # Features 29 | 30 | ## Free 31 | 32 | 1. /add -- Adding redirections allows you to setup a automatic routing of messages from any telegram channels to your own telegram channels 33 | 10 active redirections 34 | 2. /activate -- Activate a redirection from your list. *Bot does automatic forwarding of messages only for active redirections* 35 | 3. /deactivate -- deactivates a redirection from your list. Bot does not do automatic forwarding of messages for inactive re-directions 36 | 4. /list -- get list of redirections with their corresponding redirection IDs 37 | 5. /remove -- remove the redirection with id REDIRECTION_ID from your redirections list 38 | 6. /filters -- get information about filters, applied to redirection with id REDIRECTION_ID 39 | 7. /filter -- use filters allow you to make the bot skip messages that you do not want to be forwarded. 40 | Message can also be forwarded, but filter removes photos, documents, animations, stickers, links, hashtags, etc. 41 | Please see MultiFeed Bot for all filters it has that I want. 42 | - FILTER_NAME = name of the filter 43 | - REDIRECTION_ID = ID of the redirection for which you update the filter’s state 44 | - STATE = state of filter; use on for enabling filter and off for disabling it. 45 | 8. /me – gets information about your account (including information about activated paid bot features & invited users). 46 | List all PAID features with subscription end date. 47 | PAID features may have a different subscription end date, depending on date customer purchased it. 48 | Admin has the ability to enable/disable PAID features & change subscription end date for each feature. 49 | 9. /ref – Share referral link with others and get bonus. 50 | +30 day subscription to all PAID features when referral pays for subscription. 51 | Assign unique referral link/ID for each subscriber. 52 | Admin will know which existing customer had referred the new subscriber. 53 | Admin will manually update subscription of subscriber’s account. 54 | 55 | ## Premium 56 | 57 | 1. Use copy-paste mode of forwarding 58 | *Purpose*: Remove "Forwarded from" header (aka "link to the sourcing channel") from redirected messages 59 | 2. Connect Telegram account to Bot 60 | *Purpose*: Setup redirections from channels you don't have an invitation link for, but are a member of, which is the per-requisite for setting up redirections from/to bots, groups, people and transformation feature. 61 | 3. Enable Transformation 62 | *Purpose*: Replace particular words in messages with your own words. Remove particular words or phrases in messages 63 | 4. Setup redirections from/to bots, groups, or people each direction 64 | 5. The FREE version only offers up to **10 active redirections** on your list. 65 | I would like the ability for PAID subscribers to buy package of **50 additional redirections**. 66 | Admin has the ability to specify any # of redirections. 67 | Limit up to 100,000 redirections. 68 | No limit – unlimited would be great to have as well. 69 | 70 | 71 | # WORKFLOW 72 | 1. Setup redirections from Bot, Channel (not an Admin), user --> Bot, Channel or user. 73 | Will need to Connect Telegram account to Bot for this to work from what I’ve gathered in my Research. 74 | Connect to telegram account to Bot also required to enable transformation & copy-paste forwarding feature. 75 | 2. Enable transformation to replace a particular word from message (e.g. Tier: Gold -> Plan: Platinum) 76 | 3. Enable copy-paste of Forwarding to remove "Forwarded from" header (aka "link to the sourcing channel") from redirected messages – hiding source 77 | 4. Apply Filter to remove images, links, hashtags or certain keywords 78 | 5. Apply Filter to forward a message containing a specific keyword/phrase to specific Bot, Channel or user– redirection. 79 | * Example#1: if message contains the keyword/phrase: “Plan: Platinum” -> Channel #1, Bot#1 or user#1. 80 | * Example#2: if message contains the keyword/phrase: “Plan: Gold” -> Channel#2, Bot#2 or user#2. 81 | * Example#3: if message contains the keyword/phrase: “Plan: Silver” -> Channel#3, Bot#3 or user#3. 82 | 83 | 84 | # Filters (/filter) 85 | 86 | Command format: 87 | 88 | ```/filter FILTER_NAME REDIRECTION_ID STATE``` 89 | 90 | **Available filters**: 91 | 92 | - photos 93 | - documents 94 | - audios 95 | - stickers 96 | - videos 97 | - links 98 | - hashtags 99 | - contains 100 | - notContains 101 | 102 | 103 | # Set commands 104 | 105 | Message this to @botfather 106 | ``` 107 | add - Add Redirection 108 | activate - Activate redirection 109 | deactivate - Deactivate redirection 110 | list - List redirection 111 | remove - Remove redirection 112 | filter - Add Filter 113 | filters - Get filter 114 | help - Get help 115 | transform - Add Transformation 116 | transforms - List Transformation for a given redirection 117 | transformrank - Swap rank of transformations for a given redirection 118 | transformremove - Remove transformation 119 | ``` -------------------------------------------------------------------------------- /bot/services/agent.js: -------------------------------------------------------------------------------- 1 | /* An agent that communicates with the python rest api */ 2 | const request = require('request'); 3 | const { AGENT_HOSTNAME, AGENT_PORT } = require('../config'); 4 | 5 | const AGENT_URL = `http://${AGENT_HOSTNAME}:${AGENT_PORT}/`; 6 | 7 | const _sendRequest = (endpoint) => { 8 | return new Promise((resolve, reject) => { 9 | request(AGENT_URL + endpoint, { json: true }, (err, resp, body) => { 10 | if (err) return reject(err); 11 | return resolve(body); 12 | }); 13 | }); 14 | }; 15 | 16 | class ForwardAgent { 17 | static async joinPublicUserEntity(entityName) { 18 | const endpoint = `joinPublicUserEntity?entity=${entityName}`; 19 | try { 20 | const resp = await _sendRequest(endpoint); 21 | return resp; 22 | } catch (err) { 23 | return err; 24 | } 25 | } 26 | 27 | static async joinPublicEntity(entityName) { 28 | const endpoint = `joinPublicEntity?entity=${entityName}`; 29 | try { 30 | const resp = await _sendRequest(endpoint); 31 | return resp; 32 | } catch (err) { 33 | return err; 34 | } 35 | } 36 | 37 | static async joinPrivateEntity(hash) { 38 | const endpoint = `joinPrivateEntity?hash=${hash}`; 39 | try { 40 | const resp = await _sendRequest(endpoint); 41 | return resp; 42 | } catch (err) { 43 | return err; 44 | } 45 | } 46 | 47 | /** 48 | * Calls Agent to get the detail of the entity 49 | * @param {String} entity 50 | * @returns {Promise} Returns a promise of object 51 | */ 52 | static getEntity(entity, option = { is_id: false }) { 53 | return new Promise(async (resolve, reject) => { 54 | try { 55 | let endpoint = `getentity?entity=${entity}`; 56 | if (option.is_id) { 57 | endpoint += `&is_id=1`; 58 | } 59 | const resp = await _sendRequest(endpoint); 60 | 61 | if (resp._ === 'User') { 62 | return resolve({ 63 | joined: false, 64 | entity: { 65 | type: 'user', 66 | chatId: resp.id, 67 | title: resp.username || resp.first_name || resp.last_name, 68 | accessHash: resp.access_hash, 69 | bot: resp.bot, 70 | }, 71 | }); 72 | } else if (resp._ === 'Channel') { 73 | return resolve({ 74 | joined: !resp.left, 75 | entity: { 76 | type: 'channel', 77 | chatId: resp.id, 78 | title: resp.title || resp.username, 79 | accessHash: resp.access_hash, 80 | megagroup: resp.megagroup, 81 | adminRights: resp.admin_rights, 82 | }, 83 | }); 84 | } else if (resp._ === 'Chat') { 85 | if (resp.kicked) { 86 | throw new Error(`Bot was kicked from ${resp.title}`); 87 | } 88 | 89 | return resolve({ 90 | joined: !resp.left, 91 | entity: { 92 | type: 'group', 93 | chatId: resp.id, 94 | title: resp.title, 95 | accessHash: resp.id, 96 | }, 97 | }); 98 | } else if ( 99 | resp.error === 100 | 'Cannot get entity from a channel (or group) that you are not part of. Join the group and retry' 101 | ) { 102 | return resolve({ 103 | joined: false, 104 | entity: null, 105 | }); 106 | } else { 107 | throw new Error(resp.error); 108 | } 109 | } catch (err) { 110 | console.error({ err }); 111 | return reject(err); 112 | } 113 | }); 114 | } 115 | } 116 | 117 | module.exports = ForwardAgent; 118 | 119 | if (require.main === module) { 120 | ForwardAgent.getEntity('1256091383', { is_id: true }) 121 | .then((x) => console.log(x)) 122 | .catch((x) => console.log(x)); 123 | } 124 | -------------------------------------------------------------------------------- /bot/services/database.js: -------------------------------------------------------------------------------- 1 | const { DB_HOST } = require('../config'); 2 | 3 | const knex = require('knex')({ 4 | client: 'pg', 5 | connection: { 6 | host: DB_HOST, 7 | user: 'postgres', 8 | password: 'mysecretpassword', 9 | database: 'telegram', 10 | }, 11 | }); 12 | 13 | (async () => { 14 | // Create Tables 15 | const hasUserTable = await knex.schema.hasTable('users'); 16 | if (!hasUserTable) { 17 | await knex.schema.createTable('users', tableBuilder => { 18 | tableBuilder.string('chat_id').primary(); 19 | tableBuilder.string('username').nullable().unique(); 20 | tableBuilder.string('ref_code').notNullable().unique(); 21 | tableBuilder.string('ref_by'); 22 | tableBuilder.boolean('premium').defaultTo(true); 23 | tableBuilder.integer('quota').defaultTo(0); 24 | 25 | // Foreign Key 26 | tableBuilder.foreign('ref_by').references('ref_code').inTable('users'); 27 | }); 28 | console.log('User table created'); 29 | } 30 | 31 | const hasRedTable = await knex.schema.hasTable('redirections'); 32 | if (!hasRedTable) { 33 | await knex.schema.createTable('redirections', tableBuilder => { 34 | tableBuilder.increments('id').primary(); 35 | tableBuilder.string('owner').notNullable(); 36 | tableBuilder.string('source').notNullable(); 37 | tableBuilder.string('destination').notNullable(); 38 | tableBuilder.string('source_title').notNullable(); 39 | tableBuilder.string('destination_title').notNullable(); 40 | tableBuilder.boolean('active').defaultTo(false); 41 | 42 | // Foreign Key 43 | tableBuilder.foreign('owner', 'redirections_fk0').references('chat_id').inTable('users').onDelete('cascade'); 44 | }); 45 | console.log('redirections table created'); 46 | } 47 | 48 | const hasFiltersTable = await knex.schema.hasTable('filters'); 49 | if (!hasFiltersTable) { 50 | await knex.schema.createTable('filters', tableBuilder => { 51 | tableBuilder.increments('id').primary(); 52 | tableBuilder.boolean('audio').defaultTo(false); 53 | tableBuilder.boolean('video').defaultTo(false); 54 | tableBuilder.boolean('photo').defaultTo(false); 55 | tableBuilder.boolean('sticker').defaultTo(false); 56 | tableBuilder.boolean('document').defaultTo(false); 57 | tableBuilder.boolean('hashtag').defaultTo(false); 58 | tableBuilder.boolean('link').defaultTo(false); 59 | tableBuilder.string('contain'); 60 | tableBuilder.string('notcontain'); 61 | 62 | // Foreign Key 63 | tableBuilder.foreign('id').references('id').inTable('redirections').onDelete('cascade'); 64 | }); 65 | console.log('filters table created'); 66 | } 67 | 68 | const hasTransformationsTable = await knex.schema.hasTable('transformations'); 69 | if (!hasTransformationsTable) { 70 | await knex.schema.createTable('transformations', tableBuilder => { 71 | tableBuilder.increments('id').primary(); 72 | tableBuilder.integer('redirection_id').notNullable(); 73 | tableBuilder.string('old_phrase').notNullable(); 74 | tableBuilder.string('new_phrase').notNullable(); 75 | tableBuilder.integer('rank').notNullable(); 76 | 77 | // Foreign Key 78 | tableBuilder.foreign('redirection_id').references('id').inTable('redirections').onDelete('cascade'); 79 | }); 80 | console.log('transformations table created'); 81 | } 82 | })(); 83 | 84 | module.exports = knex; 85 | -------------------------------------------------------------------------------- /bot/services/telegram.js: -------------------------------------------------------------------------------- 1 | const TelegramBot = require('node-telegram-bot-api'); 2 | 3 | const config = require('../config'); 4 | 5 | const bot = new TelegramBot(config.TG.TG_API_KEY, { polling: false }); 6 | module.exports = bot; 7 | -------------------------------------------------------------------------------- /bot/wait-for.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2017 Eficode Oy 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | set -- "$@" -- "$TIMEOUT" "$QUIET" "$HOST" "$PORT" "$result" 26 | TIMEOUT=15 27 | QUIET=0 28 | 29 | echoerr() { 30 | if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi 31 | } 32 | 33 | usage() { 34 | exitcode="$1" 35 | cat << USAGE >&2 36 | Usage: 37 | $cmdname host:port [-t timeout] [-- command args] 38 | -q | --quiet Do not output any status messages 39 | -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout 40 | -- COMMAND ARGS Execute command with args after the test finishes 41 | USAGE 42 | exit "$exitcode" 43 | } 44 | 45 | wait_for() { 46 | if ! command -v nc >/dev/null; then 47 | echoerr 'nc command is missing!' 48 | exit 1 49 | fi 50 | 51 | while :; do 52 | nc -z "$HOST" "$PORT" > /dev/null 2>&1 53 | 54 | result=$? 55 | if [ $result -eq 0 ] ; then 56 | if [ $# -gt 6 ] ; then 57 | for result in $(seq $(($# - 6))); do 58 | result=$1 59 | shift 60 | set -- "$@" "$result" 61 | done 62 | 63 | TIMEOUT=$2 QUIET=$3 HOST=$4 PORT=$5 result=$6 64 | shift 6 65 | exec "$@" 66 | fi 67 | exit 0 68 | fi 69 | 70 | if [ "$TIMEOUT" -le 0 ]; then 71 | break 72 | fi 73 | TIMEOUT=$((TIMEOUT - 1)) 74 | 75 | sleep 1 76 | done 77 | echo "Operation timed out" >&2 78 | exit 1 79 | } 80 | 81 | while :; do 82 | case "$1" in 83 | *:* ) 84 | HOST=$(printf "%s\n" "$1"| cut -d : -f 1) 85 | PORT=$(printf "%s\n" "$1"| cut -d : -f 2) 86 | shift 1 87 | ;; 88 | -q | --quiet) 89 | QUIET=1 90 | shift 1 91 | ;; 92 | -q-*) 93 | QUIET=0 94 | echoerr "Unknown option: $1" 95 | usage 1 96 | ;; 97 | -q*) 98 | QUIET=1 99 | result=$1 100 | shift 1 101 | set -- -"${result#-q}" "$@" 102 | ;; 103 | -t | --timeout) 104 | TIMEOUT="$2" 105 | shift 2 106 | ;; 107 | -t*) 108 | TIMEOUT="${1#-t}" 109 | shift 1 110 | ;; 111 | --timeout=*) 112 | TIMEOUT="${1#*=}" 113 | shift 1 114 | ;; 115 | --) 116 | shift 117 | break 118 | ;; 119 | --help) 120 | usage 0 121 | ;; 122 | -*) 123 | QUIET=0 124 | echoerr "Unknown option: $1" 125 | usage 1 126 | ;; 127 | *) 128 | QUIET=0 129 | echoerr "Unknown argument: $1" 130 | usage 1 131 | ;; 132 | esac 133 | done 134 | 135 | if ! [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then 136 | echoerr "Error: invalid timeout '$TIMEOUT'" 137 | usage 3 138 | fi 139 | 140 | if [ "$HOST" = "" -o "$PORT" = "" ]; then 141 | echoerr "Error: you need to provide a host and port to test." 142 | usage 2 143 | fi 144 | 145 | wait_for "$@" -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | node-bot: 5 | build: ./bot 6 | restart: always 7 | image: telegram-forwarder-node-bot 8 | environment: 9 | AGENT_PORT: 3000 10 | AGENT_HOSTNAME: python-agent 11 | TG_API_KEY: '${TG_API_KEY}' 12 | TG_BOT_USERNAME: '${TG_BOT_USERNAME}' 13 | DB_HOST: postgres-db 14 | NTBA_FIX_319: 1 15 | depends_on: 16 | - postgres-db 17 | command: ["./wait-for.sh", "postgres-db:5432", "--", "node", "bot.js"] 18 | 19 | python-agent: 20 | build: './agent' 21 | restart: always 22 | image: 'telegram-forwarder-python-agent' 23 | depends_on: 24 | - postgres-db 25 | - node-bot 26 | environment: 27 | API_PORT: 3000 28 | TG_API_ID: '${TG_API_ID}' 29 | TG_HASH_ID: '${TG_HASH_ID}' 30 | DB_HOST: postgres-db 31 | ports: 32 | - '3000:3000' 33 | volumes: 34 | - './agent/session:/telegram-python-agent/session' 35 | 36 | postgres-db: 37 | image: postgres:alpine 38 | environment: 39 | POSTGRES_PASSWORD: mysecretpassword 40 | POSTGRES_DB: telegram 41 | volumes: 42 | - ./init.sql:/docker-entrypoint-initdb.d/init.sql 43 | ports: 44 | - '5432:5432' 45 | -------------------------------------------------------------------------------- /init.sql: -------------------------------------------------------------------------------- 1 | -- Use this file to run sql queries on database intialization -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Telegram Forwarder Bot 2 | 3 | - Automatically forward messages from Channels and Groups (private or public) 4 | - Group channels into Thematic feeds 5 | - Clone all messages from any channel to your own channel 6 | 7 | # Pre Installation 8 | 9 | You'll require two different api keys. One for the telegram bot api and one for the telegram account used as an agent. 10 | 11 | ## A. Bot API 12 | 13 | Telegram offers a neat way to create api keys for telegram bots. You need to message [@botfather](https://t.me/botfather) - a telegram bot to get create new bots! The bot will guide you through the process of creating and managing new bots and the api keys. 14 | 15 | ![Create Telegram bot with @botfather](https://i.imgur.com/DNeoeTO.png) 16 | 17 | ## B. Telegram API 18 | 19 | To get the API id and Hash id for the telegram account visit [https://my.telegram.org/auth?to=apps](https://my.telegram.org/auth?to=apps) 20 | 21 | ![](https://i.imgur.com/KJ1kDDO.png) 22 | 23 | # Installation 24 | 25 | Clone the repository 26 | 27 | ```bash 28 | git clone https://github.com/adityathebe/telegramForwarder.git 29 | ``` 30 | 31 | ## 1. Docker (Recommended) 32 | 33 | The `docker-compose` file requires few environment variables. Create a `.env` file in the root directory. Docker compose will automatically pull the required environment variables from this file. Here's an example of my `.env` file 34 | 35 | ```docker 36 | TG_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 37 | TG_API_ID=XXXX 38 | TG_HASH_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 39 | TG_BOT_USERNAME=@XXXXXXXXXXXXXXXXXbot 40 | ``` 41 | 42 | With that set up you're ready to go ! 43 | 44 | ```bash 45 | docker-compose up 46 | ``` 47 | 48 | > Things might go wrong the first time you run this command. If that happens, stop the process and re-run the command 49 | 50 | ## 2. Manual 51 | 52 | ### 1. Install Python Packages 53 | 54 | ```bash 55 | cd agent 56 | pip install -r requirements.txt 57 | ``` 58 | 59 | ### 2. Install Nodejs Packages 60 | 61 | ```bash 62 | cd bot 63 | npm install 64 | ``` 65 | 66 | ### 3. Install and setup postgress 67 | 68 | Install the postgres server and create a new database named `telegram`. 69 | 70 | ### 4. Run everything 71 | 72 | # Post Installation 73 | 74 | Once you get the database, python agent and node server running, you need to login with the telegram account that you want to use as the forwarder agent. 75 | 76 | Visit [http://localhost:3000/login](http://localhost:3000/login) to login 77 | 78 | # Things to keep in mind 79 | 80 | 1. If you're running the code via docker and docker-compose then you'll need to rebuild the docker images after pulling new updates. 81 | 82 | ``` 83 | docker-compose up --build 84 | ``` 85 | 86 | 2. Docker will persist the postgres database even after you stop the docker containers. If for some reason you want to start fresh and clean the database you need to purge the docker volume. 87 | 88 | ``` 89 | docker-compose down -v 90 | ``` 91 | 92 | # Access database from the docker container 93 | 94 | If you've already installed `psql` or any other Postgres GUI tools then you can simply connect to the database as the port `5432` is exposed and mapped to the host system's port `5432`. 95 | 96 | However, if you don't have any of those tools and don't want to bother installing them, you can simply get an interactive shell on the docker container and access database from there. If you run the command below, you will get a shell on the postgres docker container 97 | 98 | ```bash 99 | docker container exec -it telegramforwarder_postgres-db_1 psql -U postgres 100 | ``` 101 | 102 | > Note 1: The PostgreSQL image sets up trust authentication locally so you may notice a password is not required when connecting from localhost (inside the same container). However, a password will be required if connecting from a different host/container. 103 | 104 | ```sql 105 | -- \c telegram 106 | select * FROM users; 107 | ``` 108 | 109 | ### FAQ: 110 | 111 | -Q: How to start using the bot? 112 | A: Send /start command to the bot and follow the instructions. 113 | 114 | Q: Does the bot need admin permissions in a channel/group it forwards from? 115 | A: No. 116 | 117 | Q: Does the bot need admin permissions in a channel/group it forwards to? 118 | A: Yes. 119 | 120 | Q: Can I filter out ads or media content (videos, stickers, etc.)? 121 | A: Yes. 122 | 123 | Q: Can I set up automatic forwarding from another bot? 124 | A: Yes. 125 | --------------------------------------------------------------------------------