Merge branch 'master' of github.com:bukhalo/nestjs-telegraf into feature/typedoc

 Conflicts:
	package-lock.json
	package.json
This commit is contained in:
Alexander Bukhalo 2021-01-02 21:49:15 +03:00
commit 7d49cf2663
94 changed files with 26019 additions and 4893 deletions

View File

@ -1,64 +0,0 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "Sedjj",
"name": "Eldar Salimzebarov",
"avatar_url": "https://avatars3.githubusercontent.com/u/5383030?v=4",
"profile": "https://github.com/Sedjj",
"contributions": [
"bug"
]
},
{
"login": "lamuertepeluda",
"name": "Vito Macchia",
"avatar_url": "https://avatars3.githubusercontent.com/u/2249342?v=4",
"profile": "http://www.ismb.it/vito.macchia",
"contributions": [
"code",
"bug"
]
},
{
"login": "edgesite",
"name": "KITAHARA SETSUNA",
"avatar_url": "https://avatars3.githubusercontent.com/u/10336620?v=4",
"profile": "https://github.com/edgesite",
"contributions": [
"code",
"bug"
]
},
{
"login": "bukhalo",
"name": "Aleksandr Bukhalo",
"avatar_url": "https://avatars2.githubusercontent.com/u/14031838?v=4",
"profile": "https://bukhalo.com/",
"contributions": [
"code",
"doc",
"review"
]
},
{
"login": "VyacheslavSaloidWork",
"name": "Vyacheslav Saloid",
"avatar_url": "https://avatars3.githubusercontent.com/u/43011265?v=4",
"profile": "https://github.com/VyacheslavSaloidWork",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,
"projectName": "nestjs-telegraf",
"projectOwner": "bukhalo",
"repoType": "github",
"repoHost": "https://github.com",
"skipCi": true
}

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
custom: ["https://www.tinkoff.ru/sl/95M2htqoxux"] custom: ['https://www.tinkoff.ru/sl/95M2htqoxux']

View File

@ -1,11 +0,0 @@
version: 2
updates:
# Configuration for npm
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
reviewers:
- "bukhalo"
assignees:
- "bukhalo"

View File

@ -12,12 +12,12 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [12.x, 13.x] node-version: [14.x, 15.x]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: npm ci - run: npm ci

4
.gitignore vendored
View File

@ -1,3 +1,7 @@
# lock
package-lock.json
yarn.lock
# dependencies # dependencies
/node_modules /node_modules

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2019 - present Bukhalo Aleksandr Aleksandrovich Copyright (c) 2019 - present Alexander Bukhalo (a@bukhalo.com)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -71,40 +71,3 @@ export class AppService {
} }
} }
``` ```
## Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
## People
- Authors - [Aleksandr Bukhalo](https://bukhalo.com/) & [Igor Kamyshev](https://kamyshev.me/)
- Maintainers - [Aleksandr Bukhalo](https://bukhalo.com/)
- Website - [https://nestjs.com](https://nestjs.com/)
## License
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/Sedjj"><img src="https://avatars3.githubusercontent.com/u/5383030?v=4" width="100px;" alt=""/><br /><sub><b>Eldar Salimzebarov</b></sub></a><br /><a href="https://github.com/bukhalo/nestjs-telegraf/issues?q=author%3ASedjj" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://www.ismb.it/vito.macchia"><img src="https://avatars3.githubusercontent.com/u/2249342?v=4" width="100px;" alt=""/><br /><sub><b>Vito Macchia</b></sub></a><br /><a href="https://github.com/bukhalo/nestjs-telegraf/commits?author=lamuertepeluda" title="Code">💻</a> <a href="https://github.com/bukhalo/nestjs-telegraf/issues?q=author%3Alamuertepeluda" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/edgesite"><img src="https://avatars3.githubusercontent.com/u/10336620?v=4" width="100px;" alt=""/><br /><sub><b>KITAHARA SETSUNA</b></sub></a><br /><a href="https://github.com/bukhalo/nestjs-telegraf/commits?author=edgesite" title="Code">💻</a> <a href="https://github.com/bukhalo/nestjs-telegraf/issues?q=author%3Aedgesite" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://bukhalo.com/"><img src="https://avatars2.githubusercontent.com/u/14031838?v=4" width="100px;" alt=""/><br /><sub><b>Aleksandr Bukhalo</b></sub></a><br /><a href="https://github.com/bukhalo/nestjs-telegraf/commits?author=bukhalo" title="Code">💻</a> <a href="https://github.com/bukhalo/nestjs-telegraf/commits?author=bukhalo" title="Documentation">📖</a> <a href="https://github.com/bukhalo/nestjs-telegraf/pulls?q=is%3Apr+reviewed-by%3Abukhalo" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/VyacheslavSaloidWork"><img src="https://avatars3.githubusercontent.com/u/43011265?v=4" width="100px;" alt=""/><br /><sub><b>Vyacheslav Saloid</b></sub></a><br /><a href="https://github.com/bukhalo/nestjs-telegraf/issues?q=author%3AVyacheslavSaloidWork" title="Bug reports">🐛</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

View File

@ -1,6 +1,6 @@
"use strict"; "use strict";
function __export(m) { function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
} }
exports.__esModule = true; exports.__esModule = true;
__export(require("./dist")); __export(require("./dist"));

View File

@ -1,27 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import { HearsTriggers } from 'telegraf/typings/composer';
import { Context } from '../interfaces';
export type TelegrafActionTriggers = HearsTriggers<Context>;
export interface ActionOptions {
triggers: TelegrafActionTriggers;
}
/**
* Registers middleware for handling callback_data actions with regular expressions.
*
* @see https://telegraf.js.org/#/?id=action
*/
export const Action = (triggers: TelegrafActionTriggers): MethodDecorator => {
return SetMetadata(DECORATORS.ACTION, { triggers });
};
/**
* Registers middleware for handling callback_data actions with regular expressions.
*
* @see https://telegraf.js.org/#/?id=action
* @deprecated since v2, use Action decorator instead.
*/
export const TelegrafAction = Action;

View File

@ -1,25 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafCashtagCashtag = string | string[];
export interface CashtagOptions {
cashtag: TelegrafCashtagCashtag;
}
/**
* Cashtag handling.
*
* @see https://telegraf.js.org/#/?id=cashtag
*/
export const Cashtag = (cashtag: TelegrafCashtagCashtag): MethodDecorator => {
return SetMetadata(DECORATORS.CASHTAG, { cashtag });
};
/**
* Cashtag handling.
*
* @see https://telegraf.js.org/#/?id=cashtag
* @deprecated since v2, use Cashtag decorator instead.
*/
export const TelegrafCashtag = Cashtag;

View File

@ -1,25 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafCommandCommands = string | string[];
export interface CommandOptions {
commands: TelegrafCommandCommands;
}
/**
* Command handling.
*
* @see https://telegraf.js.org/#/?id=command
*/
export const Command = (commands: TelegrafCommandCommands): MethodDecorator => {
return SetMetadata(DECORATORS.COMMAND, { commands });
};
/**
* Command handling.
*
* @see https://telegraf.js.org/#/?id=command
* @deprecated since v2, use Command decorator instead.
*/
export const TelegrafCommand = Command;

View File

@ -0,0 +1,3 @@
export * from './update.decorator';
export * from './scene.decorator';
export * from './inject-bot.decorator';

View File

@ -0,0 +1,5 @@
import { Inject } from '@nestjs/common';
import { getBotToken } from '../../utils';
export const InjectBot = (name?: string): ParameterDecorator =>
Inject(getBotToken(name));

View File

@ -0,0 +1,8 @@
import { SetMetadata } from '@nestjs/common';
import { SCENE_METADATA } from '../../telegraf.constants';
/**
* TODO
*/
export const Scene = (id: string): ClassDecorator =>
SetMetadata(SCENE_METADATA, id);

View File

@ -1,8 +1,8 @@
import { SetMetadata } from '@nestjs/common'; import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants'; import { UPDATE_METADATA } from '../../telegraf.constants';
/** /**
* `@Update` decorator, it's like NestJS `@Controller` decorator, * `@Update` decorator, it's like NestJS `@Controller` decorator,
* but for Telegram Bot API updates. * but for Telegram Bot API updates.
*/ */
export const Update = (): ClassDecorator => SetMetadata(DECORATORS.UPDATE, {}); export const Update = (): ClassDecorator => SetMetadata(UPDATE_METADATA, true);

View File

@ -1,30 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafEntityEntity =
| string
| string[]
| RegExp
| RegExp[]
| Function;
export interface EntityOptions {
entity: TelegrafEntityEntity;
}
/**
* Entity handling.
*
* @see https://telegraf.js.org/#/?id=entity
*/
export const Entity = (entity: TelegrafEntityEntity): MethodDecorator => {
return SetMetadata(DECORATORS.ENTITY, { entity });
};
/**
* Entity handling.
*
* @see https://telegraf.js.org/#/?id=entity
* @deprecated since v2, use Entity decorator instead.
*/
export const TelegrafEntity = Entity;

View File

@ -1,19 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Registers middleware for handling callback_data actions with game query.
*
* @see https://telegraf.js.org/#/?id=inlinequery
*/
export const GameQuery = (): MethodDecorator => {
return SetMetadata(DECORATORS.GAME_QUERY, {});
};
/**
* Registers middleware for handling callback_data actions with game query.
*
* @see https://telegraf.js.org/#/?id=inlinequery
* @deprecated since v2, use Action decorator instead.
*/
export const TelegrafGameQuery = GameQuery;

View File

@ -1,25 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafHashtagHashtag = string | string[];
export interface HashtagOptions {
hashtag: TelegrafHashtagHashtag;
}
/**
* Hashtag handling.
*
* @see https://telegraf.js.org/#/?id=hashtag
*/
export const Hashtag = (hashtag: TelegrafHashtagHashtag): MethodDecorator => {
return SetMetadata(DECORATORS.HASHTAG, { hashtag });
};
/**
* Hashtag handling.
*
* @see https://telegraf.js.org/#/?id=hashtag
* @deprecated since v2, use Hashtag decorator instead.
*/
export const TelegrafHashtag = Hashtag;

View File

@ -1,27 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import { HearsTriggers } from 'telegraf/typings/composer';
import { Context } from '../interfaces';
export type TelegrafHearsTriggers = HearsTriggers<Context>;
export interface HearsOptions {
triggers: TelegrafHearsTriggers;
}
/**
* Registers middleware for handling text messages.
*
* @see https://telegraf.js.org/#/?id=hears
*/
export const Hears = (triggers: TelegrafHearsTriggers): MethodDecorator => {
return SetMetadata(DECORATORS.HEARS, { triggers: triggers });
};
/**
* Registers middleware for handling text messages.
*
* @see https://telegraf.js.org/#/?id=hears
* @deprecated since v2, use Hears decorator instead.
*/
export const TelegrafHears = Hears;

View File

@ -1,19 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Handler for /help command.
*
* @see https://telegraf.js.org/#/?id=help
*/
export const Help = (): MethodDecorator => {
return SetMetadata(DECORATORS.HELP, {});
};
/**
* Handler for /help command.
*
* @see https://telegraf.js.org/#/?id=help
* @deprecated since v2, use Help decorator instead.
*/
export const TelegrafHelp = Help;

View File

@ -1,18 +1,3 @@
export * from './action.decorator'; export * from './core';
export * from './cashtag.decorator'; export * from './listeners';
export * from './command.decorator'; export * from './scene';
export * from './entity.decorator';
export * from './game-query.decorator';
export * from './hashtag.decorator';
export * from './hears.decorator';
export * from './help.decorator';
export * from './inject-bot.decorator';
export * from './inline-query.decorator';
export * from './mention.decorator';
export * from './on.decorator';
export * from './phone.decorator';
export * from './settings.decorator';
export * from './start.decorator';
export * from './update.decorator';
export * from './update-hooks.decorators';
export * from './use.decorator';

View File

@ -1,4 +0,0 @@
import { Inject } from '@nestjs/common';
import { TELEGRAF_PROVIDER } from '../telegraf.constants';
export const InjectBot = (): ParameterDecorator => Inject(TELEGRAF_PROVIDER);

View File

@ -1,36 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import * as tt from 'telegraf/typings/telegram-types';
export type TelegrafInlineQueryTriggers = string | string[] | RegExp | RegExp[];
export interface InlineQueryOptions {
triggers?: TelegrafInlineQueryTriggers;
updateType:
| tt.UpdateType
| tt.UpdateType[]
| tt.MessageSubTypes
| tt.MessageSubTypes[];
}
/**
* Registers middleware for handling inline_query actions with regular expressions.
*
* @see https://telegraf.js.org/#/?id=inlinequery
*/
export const InlineQuery = (
triggers?: TelegrafInlineQueryTriggers,
): MethodDecorator => {
return SetMetadata(DECORATORS.INLINE_QUERY, {
triggers,
updateType: 'inline_query',
});
};
/**
* Registers middleware for handling inline_query actions with regular expressions.
*
* @see https://telegraf.js.org/#/?id=inlinequery
* @deprecated since v2, use InlineQuery decorator instead.
*/
export const TelegrafInlineQuery = InlineQuery;

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling callback_data actions with regular expressions.
*
* @see https://telegraf.js.org/#/?id=action
*/
export const Action = createUpdateListenerDecorator('action');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Cashtag handling.
*
* @see https://telegraf.js.org/#/?id=cashtag
*/
export const Cashtag = createUpdateListenerDecorator('cashtag');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Command handling.
*
* @see https://telegraf.js.org/#/?id=command
*/
export const Command = createUpdateListenerDecorator('command');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling messages with email entity.
*
* @see https://telegraf.js.org/#/?id=telegraf-email
*/
export const Email = createUpdateListenerDecorator('email');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling callback_data actions with game query.
*
* @see https://telegraf.js.org/#/?id=inlinequery
*/
export const GameQuery = createUpdateListenerDecorator('gameQuery');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Hashtag handling.
*
* @see https://telegraf.js.org/#/?id=hashtag
*/
export const Hashtag = createUpdateListenerDecorator('hashtag');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling text messages.
*
* @see https://telegraf.js.org/#/?id=hears
*/
export const Hears = createUpdateListenerDecorator('hears');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Handler for /help command.
*
* @see https://telegraf.js.org/#/?id=help
*/
export const Help = createUpdateListenerDecorator('help');

View File

@ -0,0 +1,18 @@
export * from './on.decorator';
export * from './use.decorator';
export * from './action.decorator';
export * from './cashtag.decorator';
export * from './command.decorator';
export * from './game-query.decorator';
export * from './hashtag.decorator';
export * from './hears.decorator';
export * from './help.decorator';
export * from './inline-query.decorator';
export * from './mention.decorator';
export * from './phone.decorator';
export * from './settings.decorator';
export * from './start.decorator';
export * from './email.decorator';
export * from './url.decorator';
export * from './text-link.decorator';
export * from './text-mention.decorator';

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling inline_query actions with regular expressions.
*
* @see https://telegraf.js.org/#/?id=inlinequery
*/
export const InlineQuery = createUpdateListenerDecorator('inlineQuery');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Mention handling.
*
* @see https://telegraf.js.org/#/?id=mention
*/
export const Mention = createUpdateListenerDecorator('mention');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for provided update type.
*
* @see https://telegraf.js.org/#/?id=on
*/
export const On = createUpdateListenerDecorator('on');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Phone number handling.
*
* @see https://telegraf.js.org/#/?id=phone
*/
export const Phone = createUpdateListenerDecorator('phone');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Handler for /settings command.
*
* @see https://telegraf.js.org/#/?id=settings
*/
export const Settings = createUpdateListenerDecorator('settings');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Handler for /start command.
*
* @see https://telegraf.js.org/#/?id=start
*/
export const Start = createUpdateListenerDecorator('start');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling messages with text_link entity.
*
* @see https://telegraf.js.org/#/?id=telegraf-textlink
*/
export const TextLink = createUpdateListenerDecorator('textLink');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling messages with text_mention entity.
*
* @see https://telegraf.js.org/#/?id=telegraf-textlink
*/
export const TextMention = createUpdateListenerDecorator('textMention');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers middleware for handling messages with url entity.
*
* @see https://telegraf.js.org/#/?id=telegraf-url
*/
export const Url = createUpdateListenerDecorator('url');

View File

@ -0,0 +1,8 @@
import { createUpdateListenerDecorator } from '../../helpers';
/**
* Registers a middleware.
*
* @see https://telegraf.js.org/#/?id=use
*/
export const Use = createUpdateListenerDecorator('use');

View File

@ -1,25 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafMentionUsername = string | string[];
export interface MentionOptions {
username: TelegrafMentionUsername;
}
/**
* Mention handling.
*
* @see https://telegraf.js.org/#/?id=mention
*/
export const Mention = (username: TelegrafMentionUsername): MethodDecorator => {
return SetMetadata(DECORATORS.MENTION, { username });
};
/**
* Mention handling.
*
* @see https://telegraf.js.org/#/?id=mention
* @deprecated since v2, use Mention decorator instead.
*/
export const TelegrafMention = Mention;

View File

@ -1,30 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import { UpdateType, MessageSubTypes } from 'telegraf/typings/telegram-types';
export type TelegrafOnUpdateTypes =
| UpdateType
| UpdateType[]
| MessageSubTypes
| MessageSubTypes[];
export interface OnOptions {
updateTypes: TelegrafOnUpdateTypes;
}
/**
* Registers middleware for provided update type.
*
* @see https://telegraf.js.org/#/?id=on
*/
export const On = (updateTypes: TelegrafOnUpdateTypes): MethodDecorator => {
return SetMetadata(DECORATORS.ON, { updateTypes: updateTypes });
};
/**
* Registers middleware for provided update type.
*
* @see https://telegraf.js.org/#/?id=on
* @deprecated since v2, use On decorator instead.
*/
export const TelegrafOn = On;

View File

@ -1,25 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafPhonePhone = string | string[];
export interface PhoneOptions {
phone: TelegrafPhonePhone;
}
/**
* Phone number handling.
*
* @see https://telegraf.js.org/#/?id=phone
*/
export const Phone = (phone: TelegrafPhonePhone): MethodDecorator => {
return SetMetadata(DECORATORS.PHONE, { phone });
};
/**
* Phone number handling.
*
* @see https://telegraf.js.org/#/?id=phone
* @deprecated since v2, use Phone decorator instead.
*/
export const TelegrafPhone = Phone;

View File

@ -0,0 +1,2 @@
export * from './scene-enter.decorator';
export * from './scene-leave.decorator';

View File

@ -0,0 +1,3 @@
import { createSceneListenerDecorator } from '../../helpers';
export const SceneEnter = createSceneListenerDecorator('enter');

View File

@ -0,0 +1,3 @@
import { createSceneListenerDecorator } from '../../helpers';
export const SceneLeave = createSceneListenerDecorator('leave');

View File

@ -1,19 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Handler for /settings command.
*
* @see https://telegraf.js.org/#/?id=settings
*/
export const Settings = (): MethodDecorator => {
return SetMetadata(DECORATORS.SETTINGS, {});
};
/**
* Handler for /settings command.
*
* @see https://telegraf.js.org/#/?id=settings
* @deprecated since v2, use Settings decorator instead.
*/
export const TelegrafSettings = Settings;

View File

@ -1,19 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Handler for /start command.
*
* @see https://telegraf.js.org/#/?id=start
*/
export const Start = (): MethodDecorator => {
return SetMetadata(DECORATORS.START, {});
};
/**
* Handler for /start command.
*
* @see https://telegraf.js.org/#/?id=start
* @deprecated since v2, use Start decorator instead.
*/
export const TelegrafStart = Start;

View File

@ -1,104 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import * as tt from 'telegraf/typings/telegram-types';
export interface UpdateHookOptions {
updateType:
| tt.UpdateType
| tt.UpdateType[]
| tt.MessageSubTypes
| tt.MessageSubTypes[];
}
/**
* New incoming message of any kind text, photo, sticker, etc.
* @constructor
*/
export const Message = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'message',
});
};
/**
* New version of a message that is known to the bot and was edited
* @constructor
*/
export const EditedMessage = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'edited_message',
});
};
/**
* New incoming channel post of any kind text, photo, sticker, etc.
* @constructor
*/
export const ChannelPost = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'channel_post',
});
};
/**
* New version of a channel post that is known to the bot and was edited
* @constructor
*/
export const EditedChannelPost = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'edited_channel_post',
});
};
/**
* New incoming inline query
* See this decorator in inline-query.decorator.ts
* @constructor
*/
// export const InlineQuery = (): MethodDecorator => {
// return SetMetadata(DECORATORS.UPDATE_HOOK, {
// updateType: 'inline_query',
// });
// };
/**
* The result of an inline query that was chosen by a user and sent to their chat partner.
* @constructor
*/
export const ChosenInlineResult = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'chosen_inline_result',
});
};
/**
* New incoming callback query
* @constructor
*/
export const CallbackQuery = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'callback_query',
});
};
/**
* New incoming shipping query. Only for invoices with flexible price
* @constructor
*/
export const ShippingQuery = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'shipping_query',
});
};
/**
* New incoming pre-checkout query. Contains full information about checkout
* @constructor
*/
export const PreCheckoutQuery = (): MethodDecorator => {
return SetMetadata(DECORATORS.UPDATE_HOOK, {
updateType: 'pre_checkout_query',
});
};
// Two more decorators are missing here. For 'poll' and 'poll_answer' update types.

View File

@ -1,19 +0,0 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Registers a middleware.
*
* @see https://telegraf.js.org/#/?id=use
*/
export const Use = (): MethodDecorator => {
return SetMetadata(DECORATORS.USE, {});
};
/**
* Registers a middleware.
*
* @see https://telegraf.js.org/#/?id=use
* @deprecated since v2, use Use decorator instead.
*/
export const TelegrafUse = Use;

View File

@ -0,0 +1,18 @@
import { SetMetadata } from '@nestjs/common';
import { BaseScene as Scene } from 'telegraf';
import { ComposerMethodArgs, SceneMethods } from '../types';
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
import { ListenerMetadata } from '../interfaces';
export function createSceneListenerDecorator<Method extends SceneMethods>(
method: Method,
) {
return (
...args: ComposerMethodArgs<Scene<never>, Method>
): MethodDecorator => {
return SetMetadata(UPDATE_LISTENER_METADATA, {
method,
args,
} as ListenerMetadata);
};
}

View File

@ -0,0 +1,18 @@
import { SetMetadata } from '@nestjs/common';
import { Composer } from 'telegraf';
import { ComposerMethodArgs, UpdateMethods } from '../types';
import { UPDATE_LISTENER_METADATA } from '../telegraf.constants';
import { ListenerMetadata } from '../interfaces';
export function createUpdateListenerDecorator<Method extends UpdateMethods>(
method: unknown,
) {
return (
...args: ComposerMethodArgs<Composer<never>, Method>
): MethodDecorator => {
return SetMetadata(UPDATE_LISTENER_METADATA, {
method,
args,
} as ListenerMetadata);
};
}

2
lib/helpers/index.ts Normal file
View File

@ -0,0 +1,2 @@
export * from './create-update-listener-decorator.helper';
export * from './create-scene-listener-decorator.helper';

View File

@ -8,5 +8,8 @@ export * as Extra from 'telegraf/extra';
export * from './decorators'; export * from './decorators';
export * from './interfaces'; export * from './interfaces';
export * from './helpers';
export * from './utils';
export * from './telegraf.module'; export * from './telegraf.module';
export * from './telegraf.provider'; export * from './types';
export { Telegraf } from 'telegraf';

View File

@ -1,11 +0,0 @@
import { TelegrafContext } from 'telegraf/typings/context';
export interface Context extends TelegrafContext {
[key: string]: any;
}
/**
* Removed type from Telegraf v3.38.0, added for backward compatibility.
* TODO: remove on next major release
*/
export interface ContextMessageUpdate extends Context {}

View File

@ -1,2 +1,3 @@
export * from './context.interface';
export * from './telegraf-options.interface'; export * from './telegraf-options.interface';
export * from './listener-metadata.interface';
export * from './update-metadata.interface';

View File

@ -0,0 +1,4 @@
export interface ListenerMetadata {
method: string;
args: unknown[];
}

View File

@ -1,17 +1,21 @@
import { ModuleMetadata, Type } from '@nestjs/common/interfaces'; import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
import { Middleware, Context } from 'telegraf';
import { import {
TelegrafOptions, TelegrafOptions,
LaunchPollingOptions, LaunchPollingOptions,
LaunchWebhookOptions, LaunchWebhookOptions,
} from 'telegraf/typings/telegraf'; } from 'telegraf/typings/telegraf';
export interface TelegrafModuleOptions { export interface TelegrafModuleOptions<C extends Context = Context> {
token: string; token: string;
options?: TelegrafOptions; options?: TelegrafOptions;
launchOptions?: { launchOptions?: {
polling?: LaunchPollingOptions; polling?: LaunchPollingOptions;
webhook?: LaunchWebhookOptions; webhook?: LaunchWebhookOptions;
}; };
botName?: string;
include?: Function[];
middlewares?: ReadonlyArray<Middleware<C>>;
} }
export interface TelegrafOptionsFactory { export interface TelegrafOptionsFactory {
@ -20,6 +24,7 @@ export interface TelegrafOptionsFactory {
export interface TelegrafModuleAsyncOptions export interface TelegrafModuleAsyncOptions
extends Pick<ModuleMetadata, 'imports'> { extends Pick<ModuleMetadata, 'imports'> {
botName?: string;
useExisting?: Type<TelegrafOptionsFactory>; useExisting?: Type<TelegrafOptionsFactory>;
useClass?: Type<TelegrafOptionsFactory>; useClass?: Type<TelegrafOptionsFactory>;
useFactory?: ( useFactory?: (

View File

@ -0,0 +1,6 @@
export interface UpdateMetadata {
name: string;
type: string;
methodName: string;
callback?: Function | Record<string, any>;
}

View File

@ -0,0 +1,59 @@
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { Module } from '@nestjs/core/injector/module';
import { flattenDeep, groupBy, identity, isEmpty, mapValues } from 'lodash';
import { UpdateMetadata } from '../interfaces';
export class BaseExplorerService {
getModules(
modulesContainer: Map<string, Module>,
include: Function[],
): Module[] {
if (!include || isEmpty(include)) {
return [...modulesContainer.values()];
}
const whitelisted = this.includeWhitelisted(modulesContainer, include);
return whitelisted;
}
includeWhitelisted(
modulesContainer: Map<string, Module>,
include: Function[],
): Module[] {
const modules = [...modulesContainer.values()];
return modules.filter(({ metatype }) =>
include.some((item) => item === metatype),
);
}
flatMap<T = UpdateMetadata>(
modules: Module[],
callback: (instance: InstanceWrapper, moduleRef: Module) => T | T[],
): T[] {
const invokeMap = () => {
return modules.map((moduleRef) => {
const providers = [...moduleRef.providers.values()];
return providers.map((wrapper) => callback(wrapper, moduleRef));
});
};
return flattenDeep(invokeMap()).filter(identity);
}
groupMetadata(resolvers: UpdateMetadata[]) {
const groupByType = groupBy(
resolvers,
(metadata: UpdateMetadata) => metadata.type,
);
const groupedMetadata = mapValues(
groupByType,
(resolversArr: UpdateMetadata[]) =>
resolversArr.reduce(
(prev, curr) => ({
...prev,
[curr.name]: curr.callback,
}),
{},
),
);
return groupedMetadata;
}
}

4
lib/services/index.ts Normal file
View File

@ -0,0 +1,4 @@
export * from './updates-explorer.service';
export * from './metadata-accessor.service';
export * from './scenes-explorer.service';
export * from './updates-explorer.service';

View File

@ -0,0 +1,42 @@
import { Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import {
SCENE_METADATA,
UPDATE_LISTENER_METADATA,
UPDATE_METADATA,
} from '../telegraf.constants';
import { ListenerMetadata } from '../interfaces';
@Injectable()
export class MetadataAccessorService {
constructor(private readonly reflector: Reflector) {}
isUpdate(target: Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(UPDATE_METADATA, target);
}
isUpdateListener(target: Function) {
if (!target) {
return false;
}
return !!this.reflector.get(UPDATE_LISTENER_METADATA, target);
}
isScene(target: Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(SCENE_METADATA, target);
}
getListenerMetadata(target: Function): ListenerMetadata | undefined {
return this.reflector.get(UPDATE_LISTENER_METADATA, target);
}
getSceneMetadata(target: Function): string | undefined {
return this.reflector.get(SCENE_METADATA, target);
}
}

View File

@ -0,0 +1,98 @@
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { BaseScene as Scene, Stage, Telegraf } from 'telegraf';
import { MetadataAccessorService } from './metadata-accessor.service';
import { BaseExplorerService } from './base-explorer.service';
import {
TELEGRAF_BOT_NAME,
TELEGRAF_MODULE_OPTIONS,
} from '../telegraf.constants';
import { TelegrafModuleOptions } from '../interfaces';
import { Module } from '@nestjs/core/injector/module';
@Injectable()
export class ScenesExplorerService
extends BaseExplorerService
implements OnModuleInit {
private readonly stage = new Stage([]);
constructor(
@Inject(TELEGRAF_BOT_NAME)
private readonly botName: string,
@Inject(TELEGRAF_MODULE_OPTIONS)
private readonly telegrafModuleOptions: TelegrafModuleOptions,
private readonly moduleRef: ModuleRef,
private readonly discoveryService: DiscoveryService,
private readonly metadataAccessor: MetadataAccessorService,
private readonly metadataScanner: MetadataScanner,
private readonly modulesContainer: ModulesContainer,
) {
super();
}
private bot: Telegraf<any>;
onModuleInit(): void {
this.bot = this.moduleRef.get<Telegraf<any>>(this.botName, {
strict: false,
});
this.bot.use(this.stage.middleware());
this.explore();
}
private explore(): void {
const modules = this.getModules(
this.modulesContainer,
this.telegrafModuleOptions.include || [],
);
const scenes = this.flatMap(modules, (instance, moduleRef) =>
this.applyScenes(instance, moduleRef),
);
}
private applyScenes(wrapper: InstanceWrapper, moduleRef: Module) {
const { instance } = wrapper;
if (!instance) {
return undefined;
}
const prototype = Object.getPrototypeOf(instance);
const providers: InstanceWrapper[] = this.discoveryService.getProviders();
const sceneProviders: InstanceWrapper[] = providers.filter(
(wrapper: InstanceWrapper) =>
this.metadataAccessor.isScene(wrapper.metatype),
);
sceneProviders.forEach((wrapper) => {
const { instance } = wrapper;
if (!instance) {
return undefined;
}
const sceneId = this.metadataAccessor.getSceneMetadata(
instance.constructor,
);
const scene = new Scene(sceneId);
this.stage.register(scene);
this.metadataScanner.scanFromPrototype(
instance,
prototype,
(methodKey: string) => {
const methodRef = instance[methodKey];
if (this.metadataAccessor.isUpdateListener(methodRef)) {
const metadata = this.metadataAccessor.getListenerMetadata(
methodRef,
);
const middlewareFn = methodRef.bind(instance);
const { method, args } = metadata;
(scene[method] as any)(...args, middlewareFn);
}
},
);
});
}
}

View File

@ -0,0 +1,83 @@
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core';
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import { MetadataAccessorService } from './metadata-accessor.service';
import {
TELEGRAF_BOT_NAME,
TELEGRAF_MODULE_OPTIONS,
} from '../telegraf.constants';
import { Telegraf } from 'telegraf';
import { TelegrafModuleOptions } from '../interfaces';
import { BaseExplorerService } from './base-explorer.service';
import { Module } from '@nestjs/core/injector/module';
@Injectable()
export class UpdatesExplorerService
extends BaseExplorerService
implements OnModuleInit {
constructor(
@Inject(TELEGRAF_BOT_NAME)
private readonly botName: string,
@Inject(TELEGRAF_MODULE_OPTIONS)
private readonly telegrafModuleOptions: TelegrafModuleOptions,
private readonly moduleRef: ModuleRef,
private readonly discoveryService: DiscoveryService,
private readonly metadataAccessor: MetadataAccessorService,
private readonly metadataScanner: MetadataScanner,
private readonly modulesContainer: ModulesContainer,
) {
super();
}
private bot: Telegraf<any>;
onModuleInit(): void {
this.bot = this.moduleRef.get<Telegraf<any>>(this.botName, {
strict: false,
});
this.explore();
}
explore() {
const modules = this.getModules(
this.modulesContainer,
this.telegrafModuleOptions.include || [],
);
const updates = this.flatMap(modules, (instance, moduleRef) =>
this.applyUpdates(instance, moduleRef),
);
}
private applyUpdates(wrapper: InstanceWrapper, moduleRef: Module) {
const { instance } = wrapper;
if (!instance) {
return undefined;
}
const prototype = Object.getPrototypeOf(instance);
const providers: InstanceWrapper[] = this.discoveryService.getProviders();
const updateProviders: InstanceWrapper[] = providers.filter(
(wrapper: InstanceWrapper) =>
this.metadataAccessor.isUpdate(wrapper.metatype),
);
updateProviders.forEach((wrapper: InstanceWrapper) => {
const { instance } = wrapper;
if (!instance) {
return undefined;
}
this.metadataScanner.scanFromPrototype(instance, prototype, (name) => {
const methodRef = instance[name];
if (this.metadataAccessor.isUpdateListener(methodRef)) {
const metadata = this.metadataAccessor.getListenerMetadata(methodRef);
const middlewareFn = methodRef.bind(instance);
const { method, args } = metadata;
// NOTE: Use "any" to disable "Expected at least 1 arguments, but got 1 or more." error.
// Use telegraf instance for non-scene listeners
(this.bot[method] as any)(...args, middlewareFn);
}
});
});
}
}

View File

@ -1,56 +1,126 @@
import { DiscoveryModule } from '@nestjs/core'; import { DiscoveryModule, ModuleRef } from '@nestjs/core';
import { Module, DynamicModule, Provider, Type } from '@nestjs/common'; import {
Module,
DynamicModule,
Provider,
Type,
Global,
Inject,
OnApplicationShutdown,
Logger,
} from '@nestjs/common';
import { import {
TelegrafModuleOptions, TelegrafModuleOptions,
TelegrafModuleAsyncOptions, TelegrafModuleAsyncOptions,
TelegrafOptionsFactory, TelegrafOptionsFactory,
} from './interfaces'; } from './interfaces';
import { import {
TELEGRAF_BOT_NAME,
TELEGRAF_MODULE_OPTIONS, TELEGRAF_MODULE_OPTIONS,
TELEGRAF_PROVIDER,
} from './telegraf.constants'; } from './telegraf.constants';
import { TelegrafMetadataAccessor } from './telegraf-metadata.accessor'; import {
import { TelegrafExplorer } from './telegraf.explorer'; MetadataAccessorService,
import { TelegrafProvider } from './telegraf.provider'; ScenesExplorerService,
UpdatesExplorerService,
} from './services';
import { getBotToken } from './utils';
import { Telegraf } from 'telegraf';
import { defer } from 'rxjs';
@Global()
@Module({ @Module({
imports: [DiscoveryModule], imports: [DiscoveryModule],
providers: [TelegrafMetadataAccessor, TelegrafExplorer], providers: [
UpdatesExplorerService,
ScenesExplorerService,
MetadataAccessorService,
],
}) })
export class TelegrafCoreModule { export class TelegrafCoreModule implements OnApplicationShutdown {
private static logger = new Logger(TelegrafCoreModule.name);
constructor(
@Inject(TELEGRAF_BOT_NAME) private readonly botName: string,
private readonly moduleRef: ModuleRef,
) {}
public static forRoot(options: TelegrafModuleOptions): DynamicModule { public static forRoot(options: TelegrafModuleOptions): DynamicModule {
const telegrafProvider = { const telegrafBotName = getBotToken(options.botName);
provide: TELEGRAF_PROVIDER,
useClass: TelegrafProvider, const telegrafBotProvider = {
inject: [TELEGRAF_MODULE_OPTIONS], provide: telegrafBotName,
useFactory: async (): Promise<any> =>
await defer(async () => {
const bot = new Telegraf<any>(options.token);
this.applyBotMiddlewares(bot, options.middlewares);
await bot.launch(options.launchOptions);
return bot;
}).toPromise(),
}; };
return { return {
module: TelegrafCoreModule, module: TelegrafCoreModule,
providers: [ providers: [
{ provide: TELEGRAF_MODULE_OPTIONS, useValue: options }, {
telegrafProvider, provide: TELEGRAF_MODULE_OPTIONS,
useValue: options,
},
{
provide: TELEGRAF_BOT_NAME,
useValue: telegrafBotName,
},
telegrafBotProvider,
], ],
exports: [telegrafProvider], exports: [telegrafBotProvider],
}; };
} }
public static forRootAsync( public static forRootAsync(
options: TelegrafModuleAsyncOptions, options: TelegrafModuleAsyncOptions,
): DynamicModule { ): DynamicModule {
const telegrafProvider = { const telegrafBotName = getBotToken(options.botName);
provide: TELEGRAF_PROVIDER,
useClass: TelegrafProvider, const telegrafBotProvider = {
provide: telegrafBotName,
useFactory: async (
telegrafModuleOptions: TelegrafModuleOptions,
): Promise<any> => {
const { botName, ...telegrafOptions } = telegrafModuleOptions;
return await defer(async () => {
const bot = new Telegraf<any>(telegrafOptions.token);
this.applyBotMiddlewares(bot, telegrafOptions.middlewares);
await bot.launch(telegrafOptions.launchOptions);
return bot;
}).toPromise();
},
inject: [TELEGRAF_MODULE_OPTIONS], inject: [TELEGRAF_MODULE_OPTIONS],
}; };
const asyncProviders = this.createAsyncProviders(options); const asyncProviders = this.createAsyncProviders(options);
return { return {
module: TelegrafCoreModule, module: TelegrafCoreModule,
imports: options.imports, imports: options.imports,
providers: [...asyncProviders, telegrafProvider], providers: [
exports: [telegrafProvider], ...asyncProviders,
{
provide: TELEGRAF_BOT_NAME,
useValue: telegrafBotName,
},
telegrafBotProvider,
],
exports: [telegrafBotProvider],
}; };
} }
private static applyBotMiddlewares(bot, middlewares) {
if (middlewares) {
middlewares.forEach((middleware) => {
bot.use(middleware);
});
}
}
private static createAsyncProviders( private static createAsyncProviders(
options: TelegrafModuleAsyncOptions, options: TelegrafModuleAsyncOptions,
): Provider[] { ): Provider[] {
@ -88,4 +158,9 @@ export class TelegrafCoreModule {
inject, inject,
}; };
} }
async onApplicationShutdown(): Promise<void> {
const bot = this.moduleRef.get<any>(this.botName);
bot && (await bot.stop());
}
} }

View File

@ -1,204 +0,0 @@
import { Injectable, Type } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import {
ActionOptions,
CashtagOptions,
CommandOptions,
EntityOptions,
HashtagOptions,
HearsOptions,
InlineQueryOptions,
MentionOptions,
OnOptions,
PhoneOptions,
UpdateHookOptions,
} from './decorators';
import { DECORATORS } from './telegraf.constants';
@Injectable()
export class TelegrafMetadataAccessor {
constructor(private readonly reflector: Reflector) {}
isUpdate(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.UPDATE, target);
}
isUpdateHook(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.UPDATE_HOOK, target);
}
getUpdateHookMetadata(
target: Type<any> | Function,
): UpdateHookOptions | undefined {
return this.reflector.get(DECORATORS.UPDATE_HOOK, target);
}
isTelegrafUse(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.USE, target);
}
isTelegrafOn(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.ON, target);
}
getTelegrafOnMetadata(target: Type<any> | Function): OnOptions | undefined {
return this.reflector.get(DECORATORS.ON, target);
}
isTelegrafHears(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.HEARS, target);
}
getTelegrafHearsMetadata(
target: Type<any> | Function,
): HearsOptions | undefined {
return this.reflector.get(DECORATORS.HEARS, target);
}
isTelegrafCommand(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.COMMAND, target);
}
getTelegrafCommandMetadata(
target: Type<any> | Function,
): CommandOptions | undefined {
return this.reflector.get(DECORATORS.COMMAND, target);
}
isTelegrafStart(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.START, target);
}
isTelegrafHelp(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.HELP, target);
}
isTelegrafSettings(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.SETTINGS, target);
}
isTelegrafEntity(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.ENTITY, target);
}
getTelegrafEntityMetadata(
target: Type<any> | Function,
): EntityOptions | undefined {
return this.reflector.get(DECORATORS.ENTITY, target);
}
isTelegrafMention(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.MENTION, target);
}
getTelegrafMentionMetadata(
target: Type<any> | Function,
): MentionOptions | undefined {
return this.reflector.get(DECORATORS.MENTION, target);
}
isTelegrafPhone(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.PHONE, target);
}
getTelegrafPhoneMetadata(
target: Type<any> | Function,
): PhoneOptions | undefined {
return this.reflector.get(DECORATORS.PHONE, target);
}
isTelegrafHashtag(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.HASHTAG, target);
}
getTelegrafHashtagMetadata(
target: Type<any> | Function,
): HashtagOptions | undefined {
return this.reflector.get(DECORATORS.HASHTAG, target);
}
isTelegrafCashtag(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.CASHTAG, target);
}
getTelegrafCashtagMetadata(
target: Type<any> | Function,
): CashtagOptions | undefined {
return this.reflector.get(DECORATORS.CASHTAG, target);
}
isTelegrafAction(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.ACTION, target);
}
getTelegrafActionMetadata(
target: Type<any> | Function,
): ActionOptions | undefined {
return this.reflector.get(DECORATORS.ACTION, target);
}
isTelegrafInlineQuery(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.INLINE_QUERY, target);
}
getTelegrafInlineQueryMetadata(
target: Type<any> | Function,
): InlineQueryOptions | undefined {
return this.reflector.get(DECORATORS.INLINE_QUERY, target);
}
isTelegrafGameQuery(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.GAME_QUERY, target);
}
}

View File

@ -1,23 +1,8 @@
export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS'; export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
export const TELEGRAF_PROVIDER = 'TelegrafProvider'; export const TELEGRAF_BOT_NAME = 'TELEGRAF_BOT_NAME';
export const DEFAULT_BOT_NAME = 'DEFAULT_BOT_NAME';
export const DECORATORS_PREFIX = 'TELEGRAF'; export const UPDATE_METADATA = 'UPDATE_METADATA';
export const DECORATORS = { export const UPDATE_LISTENER_METADATA = 'UPDATE_LISTENER_METADATA';
USE: `${DECORATORS_PREFIX}/USE`,
ON: `${DECORATORS_PREFIX}/ON`, export const SCENE_METADATA = 'SCENE_METADATA';
HEARS: `${DECORATORS_PREFIX}/HEARS`,
COMMAND: `${DECORATORS_PREFIX}/COMMAND`,
START: `${DECORATORS_PREFIX}/START`,
HELP: `${DECORATORS_PREFIX}/HELP`,
SETTINGS: `${DECORATORS_PREFIX}/SETTINGS`,
ENTITY: `${DECORATORS_PREFIX}/ENTITY`,
MENTION: `${DECORATORS_PREFIX}/MENTION`,
PHONE: `${DECORATORS_PREFIX}/PHONE`,
HASHTAG: `${DECORATORS_PREFIX}/HASHTAG`,
CASHTAG: `${DECORATORS_PREFIX}/CASHTAG`,
ACTION: `${DECORATORS_PREFIX}/ACTION`,
INLINE_QUERY: `${DECORATORS_PREFIX}/INLINE_QUERY`,
GAME_QUERY: `${DECORATORS_PREFIX}/GAME_QUERY`,
UPDATE: `${DECORATORS_PREFIX}/UPDATE`,
UPDATE_HOOK: `${DECORATORS_PREFIX}/UPDATE_HOOK`,
};

View File

@ -1,245 +0,0 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { DiscoveryService, ModuleRef } from '@nestjs/core';
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import { TelegrafMetadataAccessor } from './telegraf-metadata.accessor';
import { TelegrafProvider } from './telegraf.provider';
import { TELEGRAF_PROVIDER } from './telegraf.constants';
import {
ActionOptions,
CashtagOptions,
CommandOptions,
EntityOptions,
HashtagOptions,
HearsOptions,
InlineQueryOptions,
MentionOptions,
OnOptions,
PhoneOptions,
UpdateHookOptions,
} from './decorators';
@Injectable()
export class TelegrafExplorer implements OnModuleInit {
constructor(
private readonly moduleRef: ModuleRef,
private readonly discoveryService: DiscoveryService,
private readonly metadataAccessor: TelegrafMetadataAccessor,
private readonly metadataScanner: MetadataScanner,
) {}
private telegraf: TelegrafProvider;
onModuleInit() {
this.telegraf = this.moduleRef.get<TelegrafProvider>(TELEGRAF_PROVIDER, {
strict: false,
});
this.explore();
}
explore() {
/**
* Update providers section is only for decorators under Update decorator
*/
const updateProviders: InstanceWrapper[] = this.discoveryService
.getProviders()
.filter((wrapper: InstanceWrapper) =>
this.metadataAccessor.isUpdate(wrapper.metatype),
);
updateProviders.forEach((wrapper: InstanceWrapper) => {
const { instance } = wrapper;
this.metadataScanner.scanFromPrototype(
instance,
Object.getPrototypeOf(instance),
(key: string) => {
if (this.metadataAccessor.isUpdateHook(instance[key])) {
const metadata = this.metadataAccessor.getUpdateHookMetadata(
instance[key],
);
this.handleUpdateHook(instance, key, metadata);
}
},
);
});
const providers: InstanceWrapper[] = this.discoveryService.getProviders();
providers.forEach((wrapper: InstanceWrapper) => {
const { instance } = wrapper;
if (!instance) {
return;
}
this.metadataScanner.scanFromPrototype(
instance,
Object.getPrototypeOf(instance),
(key: string) => {
if (this.metadataAccessor.isTelegrafUse(instance[key])) {
this.handleTelegrafUse(instance, key);
} else if (this.metadataAccessor.isTelegrafOn(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafOnMetadata(
instance[key],
);
this.handleTelegrafOn(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafHears(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafHearsMetadata(
instance[key],
);
this.handleTelegrafHears(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafCommand(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafCommandMetadata(
instance[key],
);
this.handleTelegrafCommand(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafStart(instance[key])) {
this.handleTelegrafStart(instance, key);
} else if (this.metadataAccessor.isTelegrafHelp(instance[key])) {
this.handleTelegrafHelp(instance, key);
} else if (this.metadataAccessor.isTelegrafSettings(instance[key])) {
this.handleTelegrafSettings(instance, key);
} else if (this.metadataAccessor.isTelegrafEntity(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafEntityMetadata(
instance[key],
);
this.handleTelegrafEntity(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafMention(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafMentionMetadata(
instance[key],
);
this.handleTelegrafMention(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafPhone(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafPhoneMetadata(
instance[key],
);
this.handleTelegrafPhone(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafHashtag(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafHashtagMetadata(
instance[key],
);
this.handleTelegrafHashtag(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafCashtag(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafCashtagMetadata(
instance[key],
);
this.handleTelegrafCashtag(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafAction(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafActionMetadata(
instance[key],
);
this.handleTelegrafAction(instance, key, metadata);
} else if (
this.metadataAccessor.isTelegrafInlineQuery(instance[key])
) {
const metadata = this.metadataAccessor.getTelegrafInlineQueryMetadata(
instance[key],
);
this.handleTelegrafInlineQuery(instance, key, metadata);
} else if (this.metadataAccessor.isTelegrafGameQuery(instance[key])) {
this.handleTelegrafGameQuery(instance, key);
}
},
);
});
}
handleUpdateHook(instance: object, key: string, metadata: UpdateHookOptions) {
this.telegraf.on(metadata.updateType, instance[key].bind(instance));
}
handleTelegrafUse(instance: object, key: string) {
this.telegraf.use(instance[key].bind(instance));
}
handleTelegrafOn(instance: object, key: string, metadata: OnOptions) {
this.telegraf.on(metadata.updateTypes, instance[key].bind(instance));
}
handleTelegrafHears(instance: object, key: string, metadata: HearsOptions) {
this.telegraf.hears(metadata.triggers, instance[key].bind(instance));
}
handleTelegrafCommand(
instance: object,
key: string,
metadata: CommandOptions,
) {
this.telegraf.command(metadata.commands, instance[key].bind(instance));
}
handleTelegrafStart(instance: object, key: string) {
this.telegraf.start(instance[key].bind(instance));
}
handleTelegrafHelp(instance: object, key: string) {
this.telegraf.help(instance[key].bind(instance));
}
handleTelegrafSettings(instance: object, key: string) {
// @ts-ignore
this.telegraf.settings(instance[key].bind(instance));
}
handleTelegrafEntity(instance: object, key: string, metadata: EntityOptions) {
// @ts-ignore
this.telegraf.entity(metadata.entity, instance[key].bind(instance));
}
handleTelegrafMention(
instance: object,
key: string,
metadata: MentionOptions,
) {
// @ts-ignore
this.telegraf.mention(metadata.username, instance[key].bind(instance));
}
handleTelegrafPhone(instance: object, key: string, metadata: PhoneOptions) {
// @ts-ignore
this.telegraf.phone(metadata.phone, instance[key].bind(instance));
}
handleTelegrafHashtag(
instance: object,
key: string,
metadata: HashtagOptions,
) {
// @ts-ignore
this.telegraf.hashtag(metadata.hashtag, instance[key].bind(instance));
}
handleTelegrafCashtag(
instance: object,
key: string,
metadata: CashtagOptions,
) {
// @ts-ignore
this.telegraf.cashtag(metadata.cashtag, instance[key].bind(instance));
}
handleTelegrafAction(instance: object, key: string, metadata: ActionOptions) {
this.telegraf.action(metadata.triggers, instance[key].bind(instance));
}
handleTelegrafInlineQuery(
instance: object,
key: string,
metadata: InlineQueryOptions,
) {
if (metadata.triggers) {
// @ts-ignore
this.telegraf.inlineQuery(
metadata.triggers,
instance[key].bind(instance),
);
} else {
this.telegraf.on(metadata.updateType, instance[key].bind(instance));
}
}
handleTelegrafGameQuery(instance: object, key: string) {
this.telegraf.gameQuery(instance[key].bind(instance));
}
}

View File

@ -1,37 +0,0 @@
import {
Injectable,
Inject,
OnApplicationBootstrap,
Logger,
OnApplicationShutdown,
} from '@nestjs/common';
import { Telegraf } from 'telegraf';
import { Context, TelegrafModuleOptions } from './interfaces';
import { TELEGRAF_MODULE_OPTIONS } from './telegraf.constants';
@Injectable()
export class TelegrafProvider extends Telegraf<Context>
implements OnApplicationBootstrap, OnApplicationShutdown {
private logger = new Logger('Telegraf');
private readonly launchOptions;
constructor(@Inject(TELEGRAF_MODULE_OPTIONS) options: TelegrafModuleOptions) {
super(options.token, options.options);
this.launchOptions = options.launchOptions;
}
async onApplicationBootstrap() {
this.catch((err, ctx: Context) => {
this.logger.error(
`Encountered an error for ${ctx.updateType} update type`,
err,
);
});
await this.launch(this.launchOptions);
}
async onApplicationShutdown() {
await this.stop();
}
}

21
lib/types/index.ts Normal file
View File

@ -0,0 +1,21 @@
import { BaseScene, Composer, Middleware } from 'telegraf';
export type Filter<T extends any[], F> = T extends []
? []
: T extends [infer Head, ...infer Tail]
? Head extends F
? Filter<Tail, F>
: [Head, ...Filter<Tail, F>]
: [];
export type OnlyFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: any) => any ? K : never;
}[keyof T];
export type ComposerMethodArgs<
T extends Composer<never>,
U extends OnlyFunctionPropertyNames<T> = OnlyFunctionPropertyNames<T>
> = Filter<Parameters<T[U]>, Middleware<never>>;
export type UpdateMethods = OnlyFunctionPropertyNames<Composer<never>>;
export type SceneMethods = OnlyFunctionPropertyNames<BaseScene<never>>;

View File

@ -0,0 +1,7 @@
import { DEFAULT_BOT_NAME } from '../telegraf.constants';
export function getBotToken(name?: string) {
return name && name !== DEFAULT_BOT_NAME
? `${name}_BOT_NAME`
: DEFAULT_BOT_NAME;
}

1
lib/utils/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './get-bot-token.util';

4768
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "nestjs-telegraf", "name": "nestjs-telegraf",
"version": "1.3.0", "version": "2.0.0",
"description": "Telegraf module for NestJS", "description": "Telegraf module for NestJS",
"keywords": [ "keywords": [
"nest", "nest",
@ -19,10 +19,9 @@
"url": "https://github.com/bukhalo/nestjs-telegraf/issues" "url": "https://github.com/bukhalo/nestjs-telegraf/issues"
}, },
"license": "MIT", "license": "MIT",
"author": "Aleksandr Bukhalo <a@bukhalo.com>", "author": "Alexander Bukhalo <a@bukhalo.com>",
"contributors": [ "contributors": [
"Aleksandr Bukhalo <a@bukhalo.com> (https://bukhalo.com/)", "Alexander Bukhalo <a@bukhalo.com> (https://bukhalo.com/)"
"Igor Kamyshev <igor@kamyshev.me> (https://kamyshev.me/)"
], ],
"repository": "git@github.com:bukhalo/nestjs-telegraf.git", "repository": "git@github.com:bukhalo/nestjs-telegraf.git",
"scripts": { "scripts": {
@ -34,23 +33,25 @@
"typedoc:build": "typedoc --tsconfig ./tsconfig.typedoc.json" "typedoc:build": "typedoc --tsconfig ./tsconfig.typedoc.json"
}, },
"dependencies": { "dependencies": {
"telegraf": "3.38.0" "telegraf": "^3.38.0"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/common": "7.4.4", "@nestjs/common": "7.6.5",
"@nestjs/core": "7.4.4", "@nestjs/core": "7.6.5",
"@typescript-eslint/eslint-plugin": "4.0.0", "@types/lodash": "^4.14.167",
"@typescript-eslint/parser": "3.10.1", "@typescript-eslint/eslint-plugin": "4.11.1",
"eslint": "7.8.1", "@typescript-eslint/parser": "4.11.1",
"eslint-config-prettier": "6.11.0", "eslint": "7.17.0",
"eslint-plugin-import": "2.22.0", "eslint-config-prettier": "7.1.0",
"husky": "4.3.0", "eslint-plugin-import": "2.22.1",
"lint-staged": "10.3.0", "husky": "4.3.6",
"prettier": "2.1.1", "lint-staged": "10.5.3",
"lodash": "^4.17.20",
"prettier": "2.2.1",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rxjs": "6.6.3", "rxjs": "6.6.3",
"typedoc": "^0.19.1", "typedoc": "^0.19.1",
"typescript": "4.0.2" "typescript": "4.1.3"
}, },
"peerDependencies": { "peerDependencies": {
"@nestjs/common": "^6.7.0 || ^7.0.0", "@nestjs/common": "^6.7.0 || ^7.0.0",

10
renovate.json Normal file
View File

@ -0,0 +1,10 @@
{
"semanticCommits": true,
"packageRules": [
{
"depTypeList": ["devDependencies"],
"automerge": true
}
],
"extends": ["config:base"]
}

1
sample/app.constants.ts Normal file
View File

@ -0,0 +1 @@
export const HELLO_SCENE_ID = 'HELLO_SCENE_ID';

17
sample/app.module.ts Normal file
View File

@ -0,0 +1,17 @@
import { Module } from '@nestjs/common';
import { TelegrafModule } from '../lib';
import { EchoService } from './echo.service';
import { AppUpdate } from './app.update';
import { HelloScene } from './scenes/hello.scene';
import { sessionMiddleware } from './middleware/session.middleware';
@Module({
imports: [
TelegrafModule.forRoot({
token: '1467731595:AAHCvH65H9VQYKF9jE-E8c2rXsQBVAYseg8', // Don't steal >:(
middlewares: [sessionMiddleware],
}),
],
providers: [EchoService, AppUpdate, HelloScene],
})
export class AppModule {}

43
sample/app.update.ts Normal file
View File

@ -0,0 +1,43 @@
import { Telegraf } from 'telegraf';
import { Command, Help, InjectBot, On, Start, Update } from '../lib';
import { EchoService } from './echo.service';
import { HELLO_SCENE_ID } from './app.constants';
import { Context } from './interfaces/context.interface';
@Update()
export class AppUpdate {
constructor(
@InjectBot()
private readonly bot: Telegraf<any>, // TODO: fix any
private readonly echoService: EchoService,
) {}
@Start()
async onStart(ctx: Context): Promise<void> {
const me = await this.bot.telegram.getMe();
await ctx.reply(`Hey, I'm ${me.first_name}`);
}
@Help()
async onHelp(ctx: Context): Promise<void> {
await ctx.reply('Send me any text');
}
@Command('scene')
async onSceneCommand(ctx: Context): Promise<void> {
await ctx.scene.enter(HELLO_SCENE_ID);
}
@On('message')
async onMessage(ctx: Context): Promise<void> {
console.log('New message received');
if ('text' in ctx.message) {
const messageText = ctx.message.text;
const echoText = this.echoService.echo(messageText);
await ctx.reply(echoText);
} else {
await ctx.reply('Only text messages');
}
}
}

8
sample/echo.service.ts Normal file
View File

@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class EchoService {
echo(text: string): string {
return `Echo: ${text}`;
}
}

View File

@ -0,0 +1,4 @@
import { SceneContextMessageUpdate } from 'telegraf/typings/stage';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Context extends SceneContextMessageUpdate {}

7
sample/main.ts Normal file
View File

@ -0,0 +1,7 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
await NestFactory.createApplicationContext(AppModule);
}
bootstrap();

View File

@ -0,0 +1,3 @@
import { session } from 'telegraf';
export const sessionMiddleware = session();

View File

@ -0,0 +1,29 @@
import { HELLO_SCENE_ID } from '../app.constants';
import { Context } from '../interfaces/context.interface';
import { Scene, SceneEnter, SceneLeave, Command } from '../../lib';
@Scene(HELLO_SCENE_ID)
export class HelloScene {
@SceneEnter()
async onSceneEnter(ctx: Context): Promise<void> {
console.log('Enter to scene');
await ctx.reply('Welcome on scene ✋');
}
@SceneLeave()
async onSceneLeave(ctx: Context): Promise<void> {
console.log('Leave from scene');
await ctx.reply('Bye Bye 👋');
}
@Command('hello')
async onHelloCommand(ctx: Context): Promise<void> {
console.log('Use say hello');
await ctx.reply('Hi');
}
@Command('leave')
async onLeaveCommand(ctx: Context): Promise<void> {
await ctx.scene.leave();
}
}

View File

@ -8,10 +8,10 @@ slug: /bot-injection
At times you may need to access the native `Telegraf` instance. For example, you may want to connect stage middleware. You can inject the Telegraf by using the `@InjectBot()` decorator as follows: At times you may need to access the native `Telegraf` instance. For example, you may want to connect stage middleware. You can inject the Telegraf by using the `@InjectBot()` decorator as follows:
```typescript ```typescript
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectBot, TelegrafProvider } from 'nestjs-telegraf'; import { InjectBot, TelegrafProvider, Context } from 'nestjs-telegraf';
@Injectable() @Injectable()
export class BotSettingsService { export class BotSettingsService {
constructor(@InjectBot() private bot: TelegrafProvider) {} constructor(@InjectBot() private bot: TelegrafProvider<Context>) {}
} }
``` ```

View File

@ -0,0 +1,31 @@
---
id: error-handling
title: Error handling
sidebar_label: Error handling
slug: /error-handling
---
By default, `nestjs-telegraf` catches all errors using the `Logger` built into NestJS.
Use can disable global errors catch with `disableGlobalCatch`:
```typescript
TelegrafModule.forRoot({
disableGlobalCatch: true,
}),
```
After that you can override errors handling with bot instance `catch` function.
```typescript
import { Injectable } from '@nestjs/common';
import { InjectBot, TelegrafProvider, Context } from 'nestjs-telegraf';
@Injectable()
export class BotSettingsService {
constructor(@InjectBot() private bot: TelegrafProvider<Context>) {
this.bot.catch((err, ctx) => {
console.log(`Ooops, encountered an error for ${ctx.updateType}`, err);
});
}
}
```

View File

@ -0,0 +1,27 @@
---
id: standalone-applications
title: Standalone applications
sidebar_label: Standalone applications
slug: standalone-applications
---
If you initialized your application with the [Nest CLI](https://docs.nestjs.com/cli/overview), [Express](https://expressjs.com/) framework will be installed by default along with Nest. Nest and NestJS Telegraf does not require Express for work. So if you don't plan to getting bot updates through webhooks, and you don't need a web server, you can remove Express.
To do this, change the `bootstrap` function in the `main.ts` file of your project on something like that:
```typescript
async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
}
bootstrap();
```
This initializes Nest as a **standalone application** (without any network listeners).
All that remains is to remove unused dependencies:
```bash
npm un @nestjs/platform-express @types/express
```
:::info
More information about standalone applications located at [Nest documentation](https://docs.nestjs.com/standalone-applications)
:::

View File

@ -1,27 +1,36 @@
--- ---
id: webhooks id: getting-updates
title: Webhooks title: Getting updates
sidebar_label: Webhooks sidebar_label: Getting updates
slug: webhooks slug: getting-updates
--- ---
If you want to configure a telegram bot webhook, you need to get a middleware from `TelegrafProvider` for connect it in your `main.ts` file. ## Long polling
By default, the bot receives updates using long-polling and requires no additional action.
## Webhooks
If you want to configure a telegram bot webhook, you need to get a middleware via `getBotToken` helper in your `main.ts` file.
To access it, you must use the `app.get()` method, followed by the provider reference: To access it, you must use the `app.get()` method, followed by the provider reference:
```typescript ```typescript
const telegrafProvider = app.get('TelegrafProvider'); import { getBotToken } from 'nestjs-telegraf';
// ...
const bot = app.get(getBotToken());
``` ```
Now you can connect middleware: Now you can connect middleware:
```typescript ```typescript
app.use(telegrafProvider.webhookCallback('/secret-path')); app.use(bot.webhookCallback('/secret-path'));
``` ```
The last step is to specify launchOptions in `forRoot` method: The last step is to specify launchOptions in `forRoot` method:
```typescript ```typescript
TelegrafModule.forRootAsync({ TelegrafModule.forRootAsync({
imports: [ConfigModule.forFeature(telegrafModuleConfig)], imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({ useFactory: (configService: ConfigService) => ({
token: configService.get<string>('TELEGRAM_BOT_TOKEN'), token: configService.get<string>('TELEGRAM_BOT_TOKEN'),
launchOptions: { launchOptions: {
webhook: { webhook: {

View File

@ -0,0 +1,13 @@
---
id: middlewares
title: Middlewares
sidebar_label: Middlewares
slug: /middlewares
---
`nestjs-telegraf` has support of the Telegraf middleware packages. To use an existing middleware package, simply import it and add it to the middlewares array:
```typescript
TelegrafModule.forRoot({
middlewares: [session()],
}),
```

View File

@ -0,0 +1,74 @@
---
id: multiple-bots
title: Multiple bots
sidebar_label: Multiple bots
slug: /multiple-bots
---
In some cases, you may need to run multiple bots at the same time. This can also be achieved with this module. To work with multiple bots, first create the bots. In this case, bot naming becomes mandatory.
```typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TelegrafModule } from 'nestjs-telegraf';
@Module({
imports: [
ConfigModule.forRoot(),
TelegrafModule.forRootAsync({
imports: [ConfigModule],
botName: 'cat',
useFactory: (configService: ConfigService) => ({
token: configService.get<string>('CAT_BOT_TOKEN'),
}),
inject: [ConfigService],
}),
TelegrafModule.forRootAsync({
imports: [ConfigModule.forFeature(telegrafModuleConfig)],
botName: 'dog',
useFactory: async (configService: ConfigService) => ({
token: configService.get<string>('DOG_BOT_TOKEN'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}
```
:::caution
Please note that you shouldn't have multiple bots without a name, or with the same name, otherwise they will get overridden.
:::
You can also inject the `Bot` for a given bot:
```typescript
import { Injectable } from '@nestjs/common';
import { InjectBot, Telegraf, Context } from 'nestjs-telegraf';
@Injectable()
export class EchoService {
constructor(@InjectBot('cat') private catBot: Telegraf<Context>) {}
}
```
To inject a given `Bot` to a custom provider (for example, factory provider), use the `getBotToken()` function passing the name of the bot as an argument.
```typescript
{
provide: CatsService,
useFactory: (catBot: Telegraf<Context>) => {
return new CatsService(catBot);
},
inject: [getBotToken('cat')],
}
```
Another useful feature of the `nestjs-telegraf` module is the ability to choose which modules should handle updates for each launched bot. By default, module searches for handlers throughout the whole app. To limit this scan to only a subset of modules, use the include property.
```typescript
TelegrafModule.forRootAsync({
imports: [ConfigModule],
botName: 'cat',
useFactory: (configService: ConfigService) => ({
token: configService.get<string>('CAT_BOT_TOKEN'),
include: [CatsModule],
}),
inject: [ConfigService],
}),
```

23947
website/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,12 +11,12 @@
"serve": "docusaurus serve" "serve": "docusaurus serve"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-alpha.63", "@docusaurus/core": "2.0.0-alpha.70",
"@docusaurus/preset-classic": "2.0.0-alpha.63", "@docusaurus/preset-classic": "2.0.0-alpha.70",
"@mdx-js/react": "^1.5.8", "@mdx-js/react": "1.6.22",
"clsx": "^1.1.1", "clsx": "1.1.1",
"react": "^16.8.4", "react": "17.0.1",
"react-dom": "^16.8.4" "react-dom": "17.0.1"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
@ -31,11 +31,11 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/module-type-aliases": "^2.0.0-alpha.51", "@docusaurus/module-type-aliases": "2.0.0-alpha.f37987f32",
"@tsconfig/docusaurus": "^1.0.2", "@tsconfig/docusaurus": "1.0.2",
"@types/react": "^16.9.49", "@types/react": "17.0.0",
"@types/react-helmet": "^6.1.0", "@types/react-helmet": "6.1.0",
"@types/react-router-dom": "^5.1.5", "@types/react-router-dom": "5.1.7",
"typescript": "^4.0.2" "typescript": "4.1.3"
} }
} }

View File

@ -2,11 +2,15 @@ module.exports = {
docs: { docs: {
'Getting Started': [ 'Getting Started': [
'installation', 'installation',
'getting-updates',
'telegraf-methods', 'telegraf-methods',
'bot-injection', 'bot-injection',
'async-configuration', 'async-configuration',
'webhooks', 'multiple-bots',
'middlewares',
'error-handling',
], ],
Extras: ['extras/standalone-applications'],
'API Reference': ['api-reference/decorators'], 'API Reference': ['api-reference/decorators'],
}, },
}; };