Fixes
- init/help/version does not throw an error if there is no config file - node_module usage - now working
This commit is contained in:
parent
e73b8b9bf9
commit
49c36b471f
10 changed files with 144 additions and 45 deletions
50
README.md
50
README.md
|
@ -8,7 +8,7 @@
|
||||||
4. Need help? `$ telme --help`
|
4. Need help? `$ telme --help`
|
||||||
|
|
||||||
## How do i get a bot token?
|
## How do i get a bot token?
|
||||||
- Get a telegram bot token from the botFather
|
- Get a telegram bot token from the BotFather, It takes less than a minute
|
||||||
- Just talk to [BotFather](https://telegram.me/botfather) and follow a few simple steps. Once you've created a bot and received your authorization token, copy it for later
|
- Just talk to [BotFather](https://telegram.me/botfather) and follow a few simple steps. Once you've created a bot and received your authorization token, copy it for later
|
||||||
|
|
||||||
## Configure `telme`
|
## Configure `telme`
|
||||||
|
@ -16,6 +16,25 @@
|
||||||
Simply run `$ telme --init` and follow 2 easy steps. You will need the bot token at this stage.
|
Simply run `$ telme --init` and follow 2 easy steps. You will need the bot token at this stage.
|
||||||
This will help you generate a `.telmeconfig` file in your home directory. You can always run `--init` again to override values or just edit the file yourself.
|
This will help you generate a `.telmeconfig` file in your home directory. You can always run `--init` again to override values or just edit the file yourself.
|
||||||
|
|
||||||
|
#### Config file structure
|
||||||
|
The config file `.telmeconfig` should be located in your home folder and contain a valid JSON.
|
||||||
|
|
||||||
|
Example config (`~/.telmeconfig`):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"profiles": {
|
||||||
|
"profile_name": {
|
||||||
|
"chat_id": 000000,
|
||||||
|
"bot_token": "<bot_token>",
|
||||||
|
"task_message_template": "*Task:*\n\n```sh\n%cmd%\n```\nHas finished.\n*Errors*:\n %errors%"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> `task_message_template` allows the following optional placeholders `%cmd%`, `%errors%`. These will be replaced with the actual command and errors.
|
||||||
|
|
||||||
## Profiles
|
## Profiles
|
||||||
|
|
||||||
You can set multiple profiles, that will target different bots and/or different chats.
|
You can set multiple profiles, that will target different bots and/or different chats.
|
||||||
|
@ -53,3 +72,32 @@ $ telme -p movie-club curl https://example.com/large/file/download.mp4
|
||||||
```
|
```
|
||||||
this will send the message to the `movie-club` profile chat. (By the `movie-club` bot)
|
this will send the message to the `movie-club` profile chat. (By the `movie-club` bot)
|
||||||
|
|
||||||
|
## Using as a `node_module`
|
||||||
|
> Typescript users will have definitions
|
||||||
|
```javascript
|
||||||
|
import Telme from 'node-telme' // OR const Telme = require('node-telme').default
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
chat_id: 'somechatid',
|
||||||
|
bot_token: 'bot-token'
|
||||||
|
}
|
||||||
|
|
||||||
|
Telme.sendMessage(config, 'Hi there!').then(_=>{
|
||||||
|
...
|
||||||
|
}).catch(console.error);
|
||||||
|
|
||||||
|
// %cmd% and %errors% will be replaced buy actual values.
|
||||||
|
config.task_message_template = 'Task: %cmd% is done!. Errors: %errors%';
|
||||||
|
const options = {
|
||||||
|
command: 'ls',
|
||||||
|
args: ['-lah'] // If no args pass in an empty array
|
||||||
|
};
|
||||||
|
|
||||||
|
Telme.runTask(config, options).then(_=>{
|
||||||
|
...
|
||||||
|
}).catch(console.error);
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ const HOME = require('os').homedir();
|
||||||
const CONFIG_FILE_NAME = '.telmeconfig';
|
const CONFIG_FILE_NAME = '.telmeconfig';
|
||||||
const FILEPATH = `${HOME}/${CONFIG_FILE_NAME}`;
|
const FILEPATH = `${HOME}/${CONFIG_FILE_NAME}`;
|
||||||
|
|
||||||
|
let singleton = null;
|
||||||
|
|
||||||
export enum EConfigVersions {
|
export enum EConfigVersions {
|
||||||
V004 = '0.0.4',
|
V004 = '0.0.4',
|
||||||
V010 = '0.1.0'
|
V010 = '0.1.0'
|
||||||
|
@ -21,6 +23,9 @@ export default class Config {
|
||||||
static CURRENT_CONFIG_VERSION = CURRENT_CONFIG_VERSION;
|
static CURRENT_CONFIG_VERSION = CURRENT_CONFIG_VERSION;
|
||||||
static DEFAULT_TASK_MESSAGE_TEMPLATE = '*Task:*\n\n```sh\n%cmd%\n```\nHas finished.\n*Errors*:\n %errors%';
|
static DEFAULT_TASK_MESSAGE_TEMPLATE = '*Task:*\n\n```sh\n%cmd%\n```\nHas finished.\n*Errors*:\n %errors%';
|
||||||
private config: IConfig;
|
private config: IConfig;
|
||||||
|
static cliInit() {
|
||||||
|
singleton = new Config();
|
||||||
|
}
|
||||||
constructor() {
|
constructor() {
|
||||||
const file = this.readConfigFile();
|
const file = this.readConfigFile();
|
||||||
const parsed = this.parseConfig(file);
|
const parsed = this.parseConfig(file);
|
||||||
|
@ -29,11 +34,11 @@ export default class Config {
|
||||||
}
|
}
|
||||||
this.config = parsed.config;
|
this.config = parsed.config;
|
||||||
}
|
}
|
||||||
static getConfig(profile: string = 'default'): IProfileConfig {
|
static getConfig(profile: string = 'default'): ITaskConfig {
|
||||||
return singleton.getConfig(profile);
|
return singleton.getConfig(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
static generateProfileTemplate(): IProfileConfig {
|
static generateProfileTemplate(): ITaskConfig {
|
||||||
return {
|
return {
|
||||||
chat_id: null,
|
chat_id: null,
|
||||||
task_message_template: Config.DEFAULT_TASK_MESSAGE_TEMPLATE,
|
task_message_template: Config.DEFAULT_TASK_MESSAGE_TEMPLATE,
|
||||||
|
@ -49,7 +54,7 @@ export default class Config {
|
||||||
return singleton.writeConfigToFile(config);
|
return singleton.writeConfigToFile(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getConfig(profile: string): IProfileConfig {
|
private getConfig(profile: string): ITaskConfig {
|
||||||
if (!this.config.profiles[profile]) {
|
if (!this.config.profiles[profile]) {
|
||||||
throw new ConfigProfileError(`No profile named ${profile} found.`);
|
throw new ConfigProfileError(`No profile named ${profile} found.`);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +66,7 @@ export default class Config {
|
||||||
const file = fs.readFileSync(FILEPATH);
|
const file = fs.readFileSync(FILEPATH);
|
||||||
return file;
|
return file;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new ConfigFileMissingError('');
|
return Buffer.from(JSON.stringify(EMPTY_CONFIG));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +82,14 @@ export default class Config {
|
||||||
return { config, originalConfigVersion: config.version };
|
return { config, originalConfigVersion: config.version };
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new ConfigFileFormatError('');
|
throw new ConfigFileFormatError('Invalid JSON format in config file. If you modified the file yourself, please double check your modifications');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private writeConfigToFile(config: IConfig): boolean {
|
private writeConfigToFile(config: IConfig): boolean {
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(FILEPATH, JSON.stringify(config, null, 2));
|
fs.writeFileSync(FILEPATH, JSON.stringify(config, null, 2));
|
||||||
console.log(`created config file at ${FILEPATH}`);
|
console.log(`✅ created config file at ${FILEPATH}`);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -92,21 +97,21 @@ export default class Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EMPTY_CONFIG: IConfig = {
|
||||||
|
version: CURRENT_CONFIG_VERSION,
|
||||||
const singleton = new Config();
|
profiles: {}
|
||||||
|
}
|
||||||
|
export interface IMessageConfig {
|
||||||
|
|
||||||
export interface IProfileConfig {
|
|
||||||
chat_id: string;
|
chat_id: string;
|
||||||
bot_token: string;
|
bot_token: string;
|
||||||
|
}
|
||||||
|
export interface ITaskConfig extends IMessageConfig {
|
||||||
task_message_template: string;
|
task_message_template: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConfig {
|
export interface IConfig {
|
||||||
version: EConfigVersions,
|
version: EConfigVersions,
|
||||||
profiles: {
|
profiles: {
|
||||||
[key: string]: IProfileConfig;
|
[key: string]: ITaskConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,8 @@ enum ErrorCodes {
|
||||||
CONFIG_FILE_FORMAT_ERROR = 1001,
|
CONFIG_FILE_FORMAT_ERROR = 1001,
|
||||||
CONFIG_PROFILE_ERROR = 1002,
|
CONFIG_PROFILE_ERROR = 1002,
|
||||||
INVALID_ARGS_ERROR = 1003,
|
INVALID_ARGS_ERROR = 1003,
|
||||||
INVALID_COMMAND_ERROR = 1004
|
INVALID_COMMAND_ERROR = 1004,
|
||||||
|
INVALID_BOT_CHAT_CONFIG = 1005,
|
||||||
|
|
||||||
}
|
}
|
||||||
export { ErrorCodes as default };
|
export { ErrorCodes as default };
|
7
lib/errors/invalid_bot_chat_config.error.ts
Normal file
7
lib/errors/invalid_bot_chat_config.error.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import BaseError from './base_error';
|
||||||
|
|
||||||
|
export default class InvalidBotOrChatConfig extends BaseError {
|
||||||
|
constructor() {
|
||||||
|
super(`bot_token OR chat_id are invalid`, BaseError.ErrorCodes.INVALID_BOT_CHAT_CONFIG);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,12 +41,12 @@ export default class Init {
|
||||||
console.log('Cool, Got the chat. Saving config...');
|
console.log('Cool, Got the chat. Saving config...');
|
||||||
await Config.writeConfigToFile(currentConfig);
|
await Config.writeConfigToFile(currentConfig);
|
||||||
const profileFlag = profileName === 'default' ? '' : `-p ${profileName}`;
|
const profileFlag = profileName === 'default' ? '' : `-p ${profileName}`;
|
||||||
await Telme.SendMessage(currentConfig.profiles[profileName], {
|
await Telme.sendMessage(currentConfig.profiles[profileName],
|
||||||
message: `*Thanks!*\nYou are all set.\ntelme usage:\n\`\`\`\n
|
`*Thanks!*\nYou are all set.\ntelme usage:\n\`\`\`\n
|
||||||
$ ${Config.APP_NAME} ${profileFlag} --m "message to send"
|
$ ${Config.APP_NAME} ${profileFlag} --m "message to send"
|
||||||
$ ${Config.APP_NAME} ${profileFlag} <command> <args>
|
$ ${Config.APP_NAME} ${profileFlag} <command> <args>
|
||||||
\n\`\`\`\nFor more info, visit: [telme repo](https://gitlab.com/sagidayan/telme)\n\n_Enjoy!_`
|
\n\`\`\`\nFor more info, visit: [telme repo](https://gitlab.com/sagidayan/telme)\n\n_Enjoy!_`
|
||||||
})
|
);
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -57,9 +57,12 @@ $ ${Config.APP_NAME} ${profileFlag} <command> <args>
|
||||||
}
|
}
|
||||||
|
|
||||||
function listenToMessage(bot, code): Promise<string> {
|
function listenToMessage(bot, code): Promise<string> {
|
||||||
console.log(`Thanks! Please send '/code ${code}' to your bot from telegram.
|
console.log(`
|
||||||
You can send a direct message to the bot OR send this message to a group that this bot is a member of.
|
✅ Thanks! Please send '/code ${code}' to your bot from telegram.
|
||||||
Keep in mind that '${Config.APP_NAME}' will send messages to the chat of your choosing.`);
|
|
||||||
|
ℹ️ You can send a direct message to the bot OR send this message to a group that this bot is a member of.
|
||||||
|
Keep in mind that '${Config.APP_NAME}' will send messages to the chat of your choosing.
|
||||||
|
`);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
bot.on('message', msg => {
|
bot.on('message', msg => {
|
||||||
|
|
|
@ -1,9 +1,22 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
const TelegramBot = require('node-telegram-bot-api');
|
const TelegramBot = require('node-telegram-bot-api');
|
||||||
import { IProfileConfig } from '../config/config';
|
import { IMessageConfig } from '../config/config';
|
||||||
|
import InvalidBotOrChatConfig from '../errors/invalid_bot_chat_config.error';
|
||||||
|
import InvalidArgumentsError from '../errors/invalid_arguments.error';
|
||||||
export default class SendMessage {
|
export default class SendMessage {
|
||||||
static async send(config: IProfileConfig, msg: string) {
|
static async send(config: IMessageConfig, msg: string) {
|
||||||
|
validate(config, msg);
|
||||||
const bot = new TelegramBot(config.bot_token);
|
const bot = new TelegramBot(config.bot_token);
|
||||||
return await bot.sendMessage(config.chat_id, `${msg}`, { parse_mode: 'Markdown' });
|
try {
|
||||||
|
await bot.sendMessage(config.chat_id, `${msg}`, { parse_mode: 'Markdown' });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
throw new InvalidBotOrChatConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate(config: IMessageConfig, msg: string) {
|
||||||
|
if (!config.bot_token || !config.chat_id) throw new InvalidArgumentsError(`Config object must have bot_token<string>, chat_id<string>`);
|
||||||
|
if (typeof msg !== 'string') throw new InvalidArgumentsError(`message must be of type string`)
|
||||||
|
}
|
|
@ -3,12 +3,14 @@
|
||||||
const { spawn } = require('child_process');
|
const { spawn } = require('child_process');
|
||||||
// import TelegramBot from 'node-telegram-bot-api';
|
// import TelegramBot from 'node-telegram-bot-api';
|
||||||
import SendMessage from './send_message';
|
import SendMessage from './send_message';
|
||||||
import { IProfileConfig } from '../config/config';
|
import { ITaskConfig } from '../config/config';
|
||||||
import { ITaskOptions } from '../utils';
|
import { ITaskOptions } from '../utils';
|
||||||
import Config from '../config/config'
|
import Config from '../config/config'
|
||||||
import InvalidCommandError from '../errors/invalid_command';
|
import InvalidCommandError from '../errors/invalid_command';
|
||||||
|
import InvalidArgumentsError from '../errors/invalid_arguments.error';
|
||||||
export default class TaskMessage {
|
export default class TaskMessage {
|
||||||
static async run(config: IProfileConfig, options: ITaskOptions) {
|
static async run(config: ITaskConfig, options: ITaskOptions) {
|
||||||
|
validate(config, options);
|
||||||
const exec = spawn(options.command, options.args);
|
const exec = spawn(options.command, options.args);
|
||||||
let errors = await promisifyExec(exec, options.command);
|
let errors = await promisifyExec(exec, options.command);
|
||||||
let msg = config.task_message_template.replace('%cmd%', ` $ ${options.command} ${options.args.join(' ')}`)
|
let msg = config.task_message_template.replace('%cmd%', ` $ ${options.command} ${options.args.join(' ')}`)
|
||||||
|
@ -23,6 +25,11 @@ export default class TaskMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validate(config: ITaskConfig, options: ITaskOptions) {
|
||||||
|
if (!config.bot_token || !config.chat_id || !config.task_message_template) throw new InvalidArgumentsError(`Config object must have bot_token<string>, chat_id<string>, task_message_template<string>`);
|
||||||
|
if (!options.command || !options.args || !Array.isArray(options.args) || typeof options.command !== 'string') throw new InvalidArgumentsError(`Option object must have command<string>, and args<string[]>`)
|
||||||
|
}
|
||||||
|
|
||||||
function promisifyExec(exec, command): Promise<string> {
|
function promisifyExec(exec, command): Promise<string> {
|
||||||
let errors = null;
|
let errors = null;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
11
lib/telme.ts
11
lib/telme.ts
|
@ -1,20 +1,21 @@
|
||||||
process.env.NTBA_FIX_319 = 'junk';
|
process.env.NTBA_FIX_319 = 'junk';
|
||||||
import SendMessage from './flows/send_message';
|
import SendMessage from './flows/send_message';
|
||||||
import TaskMessage from './flows/task_message';
|
import TaskMessage from './flows/task_message';
|
||||||
import { IProfileConfig } from './config/config';
|
import { ITaskConfig as TaskConfig, IMessageConfig as MessageConfig } from './config/config';
|
||||||
import { ISimpleMessageOptions, ITaskOptions } from './utils';
|
import { ISimpleMessageOptions, ITaskOptions } from './utils';
|
||||||
|
|
||||||
export default class Telme {
|
export default class Telme {
|
||||||
static async SendMessage(config: IProfileConfig, options: ISimpleMessageOptions) {
|
static async sendMessage(config: MessageConfig, msg: string) {
|
||||||
await SendMessage.send(config, options.message);
|
await SendMessage.send(config, msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static async RunTask(config: IProfileConfig, options: ITaskOptions) {
|
static async runTask(config: TaskConfig, options: ITaskOptions) {
|
||||||
await TaskMessage.run(config, options);
|
await TaskMessage.run(config, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export namespace Interfaces {
|
export namespace Interfaces {
|
||||||
export interface IConfig extends IProfileConfig { };
|
export interface IMessageConfig extends MessageConfig { };
|
||||||
|
export interface ITaskConfig extends TaskConfig { };
|
||||||
export interface IMessageOptions extends ISimpleMessageOptions { };
|
export interface IMessageOptions extends ISimpleMessageOptions { };
|
||||||
export interface ITaskMessageOptions extends ITaskOptions { };
|
export interface ITaskMessageOptions extends ITaskOptions { };
|
||||||
}
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import Telme from './telme';
|
import Telme from './telme';
|
||||||
import { ArgParser, ERunMode, ISimpleMessageOptions, ITaskOptions, IInitProfileOptions } from './utils';
|
import { ArgParser, ERunMode, ISimpleMessageOptions, ITaskOptions, IInitProfileOptions } from './utils';
|
||||||
import Config, { IProfileConfig } from './config/config';
|
import Config, { ITaskConfig } from './config/config';
|
||||||
import Init from './flows/init'
|
import Init from './flows/init'
|
||||||
const { version } = require('../package.json');
|
const { version } = require('../package.json');
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const parsed = ArgParser.parse(process.argv);
|
const parsed = ArgParser.parse(process.argv);
|
||||||
let config: IProfileConfig;
|
Config.cliInit();
|
||||||
|
let config: ITaskConfig;
|
||||||
let options: any;
|
let options: any;
|
||||||
switch (parsed.mode) {
|
switch (parsed.mode) {
|
||||||
case ERunMode.VERSION:
|
case ERunMode.VERSION:
|
||||||
|
@ -22,13 +23,13 @@ async function main() {
|
||||||
case ERunMode.SIMPLE_MESSAGE:
|
case ERunMode.SIMPLE_MESSAGE:
|
||||||
config = await Config.getConfig(parsed.mode_data.profileName);
|
config = await Config.getConfig(parsed.mode_data.profileName);
|
||||||
options = parsed.mode_data as ISimpleMessageOptions;
|
options = parsed.mode_data as ISimpleMessageOptions;
|
||||||
await Telme.SendMessage(config, options);
|
await Telme.sendMessage(config, options.message);
|
||||||
console.log(`[${Config.APP_NAME}]: Told Ya!`);
|
console.log(`[${Config.APP_NAME}]: Told Ya!`);
|
||||||
break;
|
break;
|
||||||
case ERunMode.TASK_MESSAGE:
|
case ERunMode.TASK_MESSAGE:
|
||||||
config = await Config.getConfig(parsed.mode_data.profileName);
|
config = await Config.getConfig(parsed.mode_data.profileName);
|
||||||
options = parsed.mode_data as ITaskOptions;
|
options = parsed.mode_data as ITaskOptions;
|
||||||
await Telme.RunTask(config, options);
|
await Telme.runTask(config, options);
|
||||||
console.log(`[${Config.APP_NAME}]: Told Ya!`);
|
console.log(`[${Config.APP_NAME}]: Told Ya!`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -52,15 +53,15 @@ Options:
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
init:
|
init:
|
||||||
\t\t '${Config.APP_NAME} --init' - init a default profile
|
\t '${Config.APP_NAME} --init' - init a default profile
|
||||||
\t\t '${Config.APP_NAME} -i -p <profile-name>' - init a 'named' profile
|
\t '${Config.APP_NAME} -i -p <profile-name>' - init a 'named' profile
|
||||||
tasks:
|
tasks:
|
||||||
\t\t '${Config.APP_NAME} docker-compose pull' - Send a message to default profile once the command 'docker-compose pull' is done
|
\t '${Config.APP_NAME} docker-compose pull' - Send a message to default profile once the command 'docker-compose pull' is done
|
||||||
\t\t '${Config.APP_NAME} -p <profile-name> docker-compose pull' - Send a message to <profile-name> profile once the command 'docker-compose pull' is done
|
\t '${Config.APP_NAME} -p <profile-name> docker-compose pull' - Send a message to <profile-name> profile once the command 'docker-compose pull' is done
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
\t\t '${Config.APP_NAME} -m "text to send"' - Send a message to default profile
|
\t '${Config.APP_NAME} -m "text to send"' - Send a message to default profile
|
||||||
\t\t '${Config.APP_NAME} -p <profile-name> -m "text to send"' - Send message to <profile-name> profile
|
\t '${Config.APP_NAME} -p <profile-name> -m "text to send"' - Send message to <profile-name> profile
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
16
package.json
16
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "node-telme",
|
"name": "node-telme",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"bin": {
|
"bin": {
|
||||||
"telme": "dist/telme_cli.js"
|
"telme": "dist/telme_cli.js"
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,9 @@
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.com/sagidayan/telme"
|
"url": "https://gitlab.com/sagidayan/telme"
|
||||||
},
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://gitlab.com/sagidayan/telme/-/issues"
|
||||||
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-telegram-bot-api": "^0.40.0"
|
"node-telegram-bot-api": "^0.40.0"
|
||||||
|
@ -20,5 +23,14 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
}
|
},
|
||||||
|
"keywords": [
|
||||||
|
"telegram",
|
||||||
|
"bot",
|
||||||
|
"cli",
|
||||||
|
"telme",
|
||||||
|
"notifications",
|
||||||
|
"notification",
|
||||||
|
"automation"
|
||||||
|
]
|
||||||
}
|
}
|
Loading…
Reference in a new issue