diff --git a/.gitignore b/.gitignore index f9a2902..8a8a4fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# lock +package-lock.json +yarn.lock + # dependencies /node_modules diff --git a/.npmignore b/.npmignore index 130fdb1..267876c 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,5 @@ # source lib -index.ts package-lock.json tsconfig.json .prettierrc diff --git a/index.js b/index.js index a82ea05..9f5e27a 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ "use strict"; 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; -__export(require("./dist")); \ No newline at end of file +__export(require("./dist")); diff --git a/lib/decorators/action.decorator.ts b/lib/decorators/action.decorator.ts deleted file mode 100644 index a6c7a99..0000000 --- a/lib/decorators/action.decorator.ts +++ /dev/null @@ -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; - -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; diff --git a/lib/decorators/cashtag.decorator.ts b/lib/decorators/cashtag.decorator.ts deleted file mode 100644 index e85efb3..0000000 --- a/lib/decorators/cashtag.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/command.decorator.ts b/lib/decorators/command.decorator.ts deleted file mode 100644 index 6100612..0000000 --- a/lib/decorators/command.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/core/index.ts b/lib/decorators/core/index.ts new file mode 100644 index 0000000..baddc8e --- /dev/null +++ b/lib/decorators/core/index.ts @@ -0,0 +1,3 @@ +export * from './update.decorator'; +export * from './scene.decorator'; +export * from './inject-bot.decorator'; diff --git a/lib/decorators/core/inject-bot.decorator.ts b/lib/decorators/core/inject-bot.decorator.ts new file mode 100644 index 0000000..d010fbe --- /dev/null +++ b/lib/decorators/core/inject-bot.decorator.ts @@ -0,0 +1,4 @@ +import { Inject } from '@nestjs/common'; +import { Telegraf } from 'telegraf'; + +export const InjectBot = (): ParameterDecorator => Inject(Telegraf); diff --git a/lib/decorators/core/scene.decorator.ts b/lib/decorators/core/scene.decorator.ts new file mode 100644 index 0000000..391c842 --- /dev/null +++ b/lib/decorators/core/scene.decorator.ts @@ -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); diff --git a/lib/decorators/update.decorator.ts b/lib/decorators/core/update.decorator.ts similarity index 53% rename from lib/decorators/update.decorator.ts rename to lib/decorators/core/update.decorator.ts index 1946199..2002fec 100644 --- a/lib/decorators/update.decorator.ts +++ b/lib/decorators/core/update.decorator.ts @@ -1,8 +1,8 @@ import { SetMetadata } from '@nestjs/common'; -import { DECORATORS } from '../telegraf.constants'; +import { UPDATE_METADATA } from '../../telegraf.constants'; /** * `@Update` decorator, it's like NestJS `@Controller` decorator, * but for Telegram Bot API updates. */ -export const Update = (): ClassDecorator => SetMetadata(DECORATORS.UPDATE, {}); +export const Update = (): ClassDecorator => SetMetadata(UPDATE_METADATA, true); diff --git a/lib/decorators/entity.decorator.ts b/lib/decorators/entity.decorator.ts deleted file mode 100644 index 53be71f..0000000 --- a/lib/decorators/entity.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/game-query.decorator.ts b/lib/decorators/game-query.decorator.ts deleted file mode 100644 index c9d240b..0000000 --- a/lib/decorators/game-query.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/hashtag.decorator.ts b/lib/decorators/hashtag.decorator.ts deleted file mode 100644 index 88e03cb..0000000 --- a/lib/decorators/hashtag.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/hears.decorator.ts b/lib/decorators/hears.decorator.ts deleted file mode 100644 index ecb7c56..0000000 --- a/lib/decorators/hears.decorator.ts +++ /dev/null @@ -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; - -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; diff --git a/lib/decorators/help.decorator.ts b/lib/decorators/help.decorator.ts deleted file mode 100644 index ced12b1..0000000 --- a/lib/decorators/help.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/index.ts b/lib/decorators/index.ts index 03af4ba..31fa986 100644 --- a/lib/decorators/index.ts +++ b/lib/decorators/index.ts @@ -1,18 +1,3 @@ -export * from './action.decorator'; -export * from './cashtag.decorator'; -export * from './command.decorator'; -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'; +export * from './core'; +export * from './listeners'; +export * from './scene'; diff --git a/lib/decorators/inline-query.decorator.ts b/lib/decorators/inline-query.decorator.ts deleted file mode 100644 index 8f2b0fa..0000000 --- a/lib/decorators/inline-query.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/listeners/action.decorator.ts b/lib/decorators/listeners/action.decorator.ts new file mode 100644 index 0000000..4b14901 --- /dev/null +++ b/lib/decorators/listeners/action.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/cashtag.decorator.ts b/lib/decorators/listeners/cashtag.decorator.ts new file mode 100644 index 0000000..c3e37e9 --- /dev/null +++ b/lib/decorators/listeners/cashtag.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Cashtag handling. + * + * @see https://telegraf.js.org/#/?id=cashtag + */ +export const Cashtag = createUpdateListenerDecorator('cashtag'); diff --git a/lib/decorators/listeners/command.decorator.ts b/lib/decorators/listeners/command.decorator.ts new file mode 100644 index 0000000..0e7806e --- /dev/null +++ b/lib/decorators/listeners/command.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Command handling. + * + * @see https://telegraf.js.org/#/?id=command + */ +export const Command = createUpdateListenerDecorator('command'); diff --git a/lib/decorators/listeners/email.decorator.ts b/lib/decorators/listeners/email.decorator.ts new file mode 100644 index 0000000..e9bb1a6 --- /dev/null +++ b/lib/decorators/listeners/email.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/game-query.decorator.ts b/lib/decorators/listeners/game-query.decorator.ts new file mode 100644 index 0000000..347f998 --- /dev/null +++ b/lib/decorators/listeners/game-query.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/hashtag.decorator.ts b/lib/decorators/listeners/hashtag.decorator.ts new file mode 100644 index 0000000..86e9e13 --- /dev/null +++ b/lib/decorators/listeners/hashtag.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Hashtag handling. + * + * @see https://telegraf.js.org/#/?id=hashtag + */ +export const Hashtag = createUpdateListenerDecorator('hashtag'); diff --git a/lib/decorators/listeners/hears.decorator.ts b/lib/decorators/listeners/hears.decorator.ts new file mode 100644 index 0000000..79d71af --- /dev/null +++ b/lib/decorators/listeners/hears.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/help.decorator.ts b/lib/decorators/listeners/help.decorator.ts new file mode 100644 index 0000000..36ac9e4 --- /dev/null +++ b/lib/decorators/listeners/help.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Handler for /help command. + * + * @see https://telegraf.js.org/#/?id=help + */ +export const Help = createUpdateListenerDecorator('help'); diff --git a/lib/decorators/listeners/index.ts b/lib/decorators/listeners/index.ts new file mode 100644 index 0000000..a332f5a --- /dev/null +++ b/lib/decorators/listeners/index.ts @@ -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'; diff --git a/lib/decorators/listeners/inline-query.decorator.ts b/lib/decorators/listeners/inline-query.decorator.ts new file mode 100644 index 0000000..722a348 --- /dev/null +++ b/lib/decorators/listeners/inline-query.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/mention.decorator.ts b/lib/decorators/listeners/mention.decorator.ts new file mode 100644 index 0000000..e4341a0 --- /dev/null +++ b/lib/decorators/listeners/mention.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Mention handling. + * + * @see https://telegraf.js.org/#/?id=mention + */ +export const Mention = createUpdateListenerDecorator('mention'); diff --git a/lib/decorators/listeners/on.decorator.ts b/lib/decorators/listeners/on.decorator.ts new file mode 100644 index 0000000..9f3c0fd --- /dev/null +++ b/lib/decorators/listeners/on.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/phone.decorator.ts b/lib/decorators/listeners/phone.decorator.ts new file mode 100644 index 0000000..0f68380 --- /dev/null +++ b/lib/decorators/listeners/phone.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Phone number handling. + * + * @see https://telegraf.js.org/#/?id=phone + */ +export const Phone = createUpdateListenerDecorator('phone'); diff --git a/lib/decorators/listeners/settings.decorator.ts b/lib/decorators/listeners/settings.decorator.ts new file mode 100644 index 0000000..6cca7c7 --- /dev/null +++ b/lib/decorators/listeners/settings.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Handler for /settings command. + * + * @see https://telegraf.js.org/#/?id=settings + */ +export const Settings = createUpdateListenerDecorator('settings'); diff --git a/lib/decorators/listeners/start.decorator.ts b/lib/decorators/listeners/start.decorator.ts new file mode 100644 index 0000000..48bdc5b --- /dev/null +++ b/lib/decorators/listeners/start.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Handler for /start command. + * + * @see https://telegraf.js.org/#/?id=start + */ +export const Start = createUpdateListenerDecorator('start'); diff --git a/lib/decorators/listeners/text-link.decorator.ts b/lib/decorators/listeners/text-link.decorator.ts new file mode 100644 index 0000000..c62439a --- /dev/null +++ b/lib/decorators/listeners/text-link.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/text-mention.decorator.ts b/lib/decorators/listeners/text-mention.decorator.ts new file mode 100644 index 0000000..895a458 --- /dev/null +++ b/lib/decorators/listeners/text-mention.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/url.decorator.ts b/lib/decorators/listeners/url.decorator.ts new file mode 100644 index 0000000..843aa41 --- /dev/null +++ b/lib/decorators/listeners/url.decorator.ts @@ -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'); diff --git a/lib/decorators/listeners/use.decorator.ts b/lib/decorators/listeners/use.decorator.ts new file mode 100644 index 0000000..ba83af5 --- /dev/null +++ b/lib/decorators/listeners/use.decorator.ts @@ -0,0 +1,8 @@ +import { createUpdateListenerDecorator } from '../../helpers'; + +/** + * Registers a middleware. + * + * @see https://telegraf.js.org/#/?id=use + */ +export const Use = createUpdateListenerDecorator('use'); diff --git a/lib/decorators/mention.decorator.ts b/lib/decorators/mention.decorator.ts deleted file mode 100644 index 7611c8e..0000000 --- a/lib/decorators/mention.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/on.decorator.ts b/lib/decorators/on.decorator.ts deleted file mode 100644 index bc36c94..0000000 --- a/lib/decorators/on.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/phone.decorator.ts b/lib/decorators/phone.decorator.ts deleted file mode 100644 index 90e6342..0000000 --- a/lib/decorators/phone.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/scene/index.ts b/lib/decorators/scene/index.ts new file mode 100644 index 0000000..b1d61b2 --- /dev/null +++ b/lib/decorators/scene/index.ts @@ -0,0 +1,2 @@ +export * from './scene-enter.decorator'; +export * from './scene-leave.decorator'; diff --git a/lib/decorators/scene/scene-enter.decorator.ts b/lib/decorators/scene/scene-enter.decorator.ts new file mode 100644 index 0000000..914b2d7 --- /dev/null +++ b/lib/decorators/scene/scene-enter.decorator.ts @@ -0,0 +1,3 @@ +import { createSceneListenerDecorator } from '../../helpers'; + +export const SceneEnter = createSceneListenerDecorator('enter'); diff --git a/lib/decorators/scene/scene-leave.decorator.ts b/lib/decorators/scene/scene-leave.decorator.ts new file mode 100644 index 0000000..19b970e --- /dev/null +++ b/lib/decorators/scene/scene-leave.decorator.ts @@ -0,0 +1,3 @@ +import { createSceneListenerDecorator } from '../../helpers'; + +export const SceneLeave = createSceneListenerDecorator('leave'); diff --git a/lib/decorators/settings.decorator.ts b/lib/decorators/settings.decorator.ts deleted file mode 100644 index 674af29..0000000 --- a/lib/decorators/settings.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/start.decorator.ts b/lib/decorators/start.decorator.ts deleted file mode 100644 index d11658e..0000000 --- a/lib/decorators/start.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/decorators/update-hooks.decorators.ts b/lib/decorators/update-hooks.decorators.ts deleted file mode 100644 index 75621d8..0000000 --- a/lib/decorators/update-hooks.decorators.ts +++ /dev/null @@ -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. diff --git a/lib/decorators/use.decorator.ts b/lib/decorators/use.decorator.ts deleted file mode 100644 index 8c47461..0000000 --- a/lib/decorators/use.decorator.ts +++ /dev/null @@ -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; diff --git a/lib/explorers/telegraf-scene.explorer.ts b/lib/explorers/telegraf-scene.explorer.ts new file mode 100644 index 0000000..2ab2c49 --- /dev/null +++ b/lib/explorers/telegraf-scene.explorer.ts @@ -0,0 +1,73 @@ +import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; +import { DiscoveryService } 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 { TelegrafMetadataAccessor } from '../telegraf.metadata-accessor'; + +@Injectable() +export class TelegrafSceneExplorer implements OnModuleInit { + private readonly stage = new Stage([]); + + constructor( + @Inject(Telegraf) + private readonly telegraf: Telegraf, + private readonly discoveryService: DiscoveryService, + private readonly metadataAccessor: TelegrafMetadataAccessor, + private readonly metadataScanner: MetadataScanner, + ) { + this.telegraf.use(this.stage.middleware()); + } + + onModuleInit(): void { + this.explore(); + } + + private explore(): void { + const sceneClasses = this.filterSceneClasses(); + + sceneClasses.forEach((wrapper) => { + const { instance } = wrapper; + + const sceneId = this.metadataAccessor.getSceneMetadata( + instance.constructor, + ); + const scene = new Scene(sceneId); + this.stage.register(scene); + + const prototype = Object.getPrototypeOf(instance); + this.metadataScanner.scanFromPrototype( + instance, + prototype, + (methodKey: string) => + this.registerIfListener(scene, instance, methodKey), + ); + }); + } + + private filterSceneClasses(): InstanceWrapper[] { + return this.discoveryService + .getProviders() + .filter((wrapper) => wrapper.instance) + .filter((wrapper) => + this.metadataAccessor.isScene(wrapper.instance.constructor), + ); + } + + private registerIfListener( + scene: Scene, + instance: Record, + methodKey: string, + ): void { + const methodRef = instance[methodKey]; + const middlewareFn = methodRef.bind(instance); + + const listenerMetadata = this.metadataAccessor.getListenerMetadata( + methodRef, + ); + if (!listenerMetadata) return; + + const { method, args } = listenerMetadata; + (scene[method] as any)(...args, middlewareFn); + } +} diff --git a/lib/explorers/telegraf-update.explorer.ts b/lib/explorers/telegraf-update.explorer.ts new file mode 100644 index 0000000..a848806 --- /dev/null +++ b/lib/explorers/telegraf-update.explorer.ts @@ -0,0 +1,63 @@ +import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; +import { DiscoveryService } from '@nestjs/core'; +import { MetadataScanner } from '@nestjs/core/metadata-scanner'; +import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; +import { Telegraf } from 'telegraf'; +import { TelegrafMetadataAccessor } from '../telegraf.metadata-accessor'; + +@Injectable() +export class TelegrafUpdateExplorer implements OnModuleInit { + constructor( + @Inject(Telegraf) + private readonly telegraf: Telegraf, + private readonly discoveryService: DiscoveryService, + private readonly metadataAccessor: TelegrafMetadataAccessor, + private readonly metadataScanner: MetadataScanner, + ) {} + + onModuleInit(): void { + this.explore(); + } + + private explore(): void { + const updateClasses = this.filterUpdateClasses(); + + updateClasses.forEach((wrapper) => { + const { instance } = wrapper; + + const prototype = Object.getPrototypeOf(instance); + this.metadataScanner.scanFromPrototype( + instance, + prototype, + (methodKey: string) => this.registerIfListener(instance, methodKey), + ); + }); + } + + private filterUpdateClasses(): InstanceWrapper[] { + return this.discoveryService + .getProviders() + .filter((wrapper) => wrapper.instance) + .filter((wrapper) => + this.metadataAccessor.isUpdate(wrapper.instance.constructor), + ); + } + + private registerIfListener( + instance: Record, + methodKey: string, + ): void { + const methodRef = instance[methodKey]; + const middlewareFn = methodRef.bind(instance); + + const listenerMetadata = this.metadataAccessor.getListenerMetadata( + methodRef, + ); + if (!listenerMetadata) return; + + const { method, args } = listenerMetadata; + // NOTE: Use "any" to disable "Expected at least 1 arguments, but got 1 or more." error. + // Use telegraf instance for non-scene listeners + (this.telegraf[method] as any)(...args, middlewareFn); + } +} diff --git a/lib/helpers/create-scene-listener-decorator.helper.ts b/lib/helpers/create-scene-listener-decorator.helper.ts new file mode 100644 index 0000000..c997ffc --- /dev/null +++ b/lib/helpers/create-scene-listener-decorator.helper.ts @@ -0,0 +1,18 @@ +import { SetMetadata } from '@nestjs/common'; +import { BaseScene as Scene } from 'telegraf'; +import { ComposerMethodArgs, SceneMethods } from '../telegraf.types'; +import { UPDATE_LISTENER_METADATA } from '../telegraf.constants'; +import { ListenerMetadata } from '../interfaces'; + +export function createSceneListenerDecorator( + method: Method, +) { + return ( + ...args: ComposerMethodArgs, Method> + ): MethodDecorator => { + return SetMetadata(UPDATE_LISTENER_METADATA, { + method, + args, + } as ListenerMetadata); + }; +} diff --git a/lib/helpers/create-update-listener-decorator.helper.ts b/lib/helpers/create-update-listener-decorator.helper.ts new file mode 100644 index 0000000..a27f85b --- /dev/null +++ b/lib/helpers/create-update-listener-decorator.helper.ts @@ -0,0 +1,18 @@ +import { SetMetadata } from '@nestjs/common'; +import { Composer } from 'telegraf'; +import { ComposerMethodArgs, UpdateMethods } from '../telegraf.types'; +import { UPDATE_LISTENER_METADATA } from '../telegraf.constants'; +import { ListenerMetadata } from '../interfaces'; + +export function createUpdateListenerDecorator( + method: unknown, +) { + return ( + ...args: ComposerMethodArgs, Method> + ): MethodDecorator => { + return SetMetadata(UPDATE_LISTENER_METADATA, { + method, + args, + } as ListenerMetadata); + }; +} diff --git a/lib/helpers/index.ts b/lib/helpers/index.ts new file mode 100644 index 0000000..20b6077 --- /dev/null +++ b/lib/helpers/index.ts @@ -0,0 +1,2 @@ +export * from './create-update-listener-decorator.helper'; +export * from './create-scene-listener-decorator.helper'; diff --git a/lib/index.ts b/lib/index.ts index fb91cba..e45daa6 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -8,13 +8,8 @@ export * as Extra from 'telegraf/extra'; export * from './decorators'; export * from './interfaces'; +export * from './helpers'; export * from './utils'; export * from './telegraf.module'; +export * from './telegraf.types'; export { Telegraf } from 'telegraf'; - -/** - * Backward compatibility with versions < 1.4.0, - * after removing TelegrafProvider service - * TODO: remove that on next major release - */ -export { Telegraf as TelegrafProvider } from 'telegraf'; diff --git a/lib/interfaces/index.ts b/lib/interfaces/index.ts index a403036..5d0c244 100644 --- a/lib/interfaces/index.ts +++ b/lib/interfaces/index.ts @@ -1,3 +1,4 @@ export * from './context.interface'; export * from './telegraf-options.interface'; +export * from './listener-metadata.interface'; export * from './update-metadata.interface'; diff --git a/lib/interfaces/listener-metadata.interface.ts b/lib/interfaces/listener-metadata.interface.ts new file mode 100644 index 0000000..9dc4925 --- /dev/null +++ b/lib/interfaces/listener-metadata.interface.ts @@ -0,0 +1,4 @@ +export interface ListenerMetadata { + method: string; + args: unknown[]; +} diff --git a/lib/interfaces/telegraf-options.interface.ts b/lib/interfaces/telegraf-options.interface.ts index 6de8013..6ac30d1 100644 --- a/lib/interfaces/telegraf-options.interface.ts +++ b/lib/interfaces/telegraf-options.interface.ts @@ -1,13 +1,15 @@ import { ModuleMetadata, Type } from '@nestjs/common/interfaces'; +import { Middleware, Context } from 'telegraf'; import { TelegrafOptions, LaunchPollingOptions, LaunchWebhookOptions, + TelegrafOptions, } from 'telegraf/typings/telegraf'; import { Middleware } from 'telegraf/typings/composer'; import { Context } from './context.interface'; -export interface TelegrafModuleOptions { +export interface TelegrafModuleOptions { token: string; options?: TelegrafOptions; launchOptions?: { @@ -18,6 +20,7 @@ export interface TelegrafModuleOptions { include?: Function[]; middlewares?: ReadonlyArray>; disableGlobalCatch?: boolean; + middlewares?: Middleware[]; } export interface TelegrafOptionsFactory { diff --git a/lib/telegraf.constants.ts b/lib/telegraf.constants.ts index 54270ef..3ac37e3 100644 --- a/lib/telegraf.constants.ts +++ b/lib/telegraf.constants.ts @@ -2,23 +2,7 @@ export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS'; export const TELEGRAF_BOT_NAME = 'TELEGRAF_BOT_NAME'; export const DEFAULT_BOT_NAME = 'DEFAULT_BOT_NAME'; -export const DECORATORS_PREFIX = 'TELEGRAF'; -export const DECORATORS = { - USE: `${DECORATORS_PREFIX}/USE`, - ON: `${DECORATORS_PREFIX}/ON`, - 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`, -}; +export const UPDATE_METADATA = 'UPDATE_METADATA'; +export const UPDATE_LISTENER_METADATA = 'UPDATE_LISTENER_METADATA'; + +export const SCENE_METADATA = 'SCENE_METADATA'; diff --git a/lib/telegraf.metadata-accessor.ts b/lib/telegraf.metadata-accessor.ts new file mode 100644 index 0000000..5c4394d --- /dev/null +++ b/lib/telegraf.metadata-accessor.ts @@ -0,0 +1,29 @@ +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 TelegrafMetadataAccessor { + constructor(private readonly reflector: Reflector) {} + + isUpdate(target: Function): boolean { + return !!this.reflector.get(UPDATE_METADATA, target); + } + + isScene(target: Function): boolean { + 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); + } +} diff --git a/lib/telegraf.module.ts b/lib/telegraf.module.ts index fb3cdeb..4e9f958 100644 --- a/lib/telegraf.module.ts +++ b/lib/telegraf.module.ts @@ -1,27 +1,106 @@ -import { Module, DynamicModule } from '@nestjs/common'; -import { TelegrafCoreModule } from './telegraf-core.module'; +import { DiscoveryModule, ModuleRef } from '@nestjs/core'; +import { + DynamicModule, + Inject, + Module, + OnApplicationBootstrap, + OnApplicationShutdown, + Provider, +} from '@nestjs/common'; +import { Telegraf } from 'telegraf'; import { - TelegrafModuleOptions, TelegrafModuleAsyncOptions, + TelegrafModuleOptions, + TelegrafOptionsFactory, } from './interfaces'; +import { TELEGRAF_MODULE_OPTIONS } from './telegraf.constants'; +import { TelegrafMetadataAccessor } from './telegraf.metadata-accessor'; +import { TelegrafUpdateExplorer } from './explorers/telegraf-update.explorer'; +import { TelegrafSceneExplorer } from './explorers/telegraf-scene.explorer'; +import { createProviders, TelegrafProvider } from './telegraf.providers'; + +@Module({ + imports: [DiscoveryModule], + providers: [ + TelegrafMetadataAccessor, + TelegrafSceneExplorer, + TelegrafUpdateExplorer, + ], +}) +export class TelegrafModule + implements OnApplicationBootstrap, OnApplicationShutdown { + constructor( + @Inject(TELEGRAF_MODULE_OPTIONS) + private readonly options: TelegrafModuleOptions, + private readonly moduleRef: ModuleRef, + ) {} + + async onApplicationBootstrap(): Promise { + const { launchOptions } = this.options; + const telegraf = this.moduleRef.get(Telegraf); + await telegraf.launch(launchOptions); + } + + async onApplicationShutdown(): Promise { + const telegraf = this.moduleRef.get(Telegraf); + await telegraf.stop(); + } -@Module({}) -export class TelegrafModule { public static forRoot(options: TelegrafModuleOptions): DynamicModule { + const providers = [...createProviders(options), TelegrafProvider]; + return { module: TelegrafModule, - imports: [TelegrafCoreModule.forRoot(options)], - exports: [TelegrafCoreModule], + providers, + exports: providers, }; } public static forRootAsync( options: TelegrafModuleAsyncOptions, ): DynamicModule { + const providers = [...this.createAsyncProviders(options), TelegrafProvider]; + return { module: TelegrafModule, - imports: [TelegrafCoreModule.forRootAsync(options)], - exports: [TelegrafCoreModule], + imports: options.imports || [], + providers, + exports: providers, + }; + } + + private static createAsyncProviders( + options: TelegrafModuleAsyncOptions, + ): Provider[] { + if (options.useExisting || options.useFactory) { + return [this.createAsyncOptionsProvider(options)]; + } + + return [ + this.createAsyncOptionsProvider(options), + { + provide: options.useClass, + useClass: options.useClass, + }, + ]; + } + + private static createAsyncOptionsProvider( + options: TelegrafModuleAsyncOptions, + ): Provider { + if (options.useFactory) { + return { + provide: TELEGRAF_MODULE_OPTIONS, + useFactory: options.useFactory, + inject: options.inject || [], + }; + } + + return { + provide: TELEGRAF_MODULE_OPTIONS, + useFactory: async (optionsFactory: TelegrafOptionsFactory) => + await optionsFactory.createTelegrafOptions(), + inject: [options.useExisting || options.useClass], }; } } diff --git a/lib/telegraf.providers.ts b/lib/telegraf.providers.ts new file mode 100644 index 0000000..b13de54 --- /dev/null +++ b/lib/telegraf.providers.ts @@ -0,0 +1,25 @@ +import { Provider } from '@nestjs/common'; +import { Telegraf } from 'telegraf'; +import { TELEGRAF_MODULE_OPTIONS } from './telegraf.constants'; +import { TelegrafModuleOptions } from './interfaces'; + +export const TelegrafProvider = { + provide: Telegraf, + useFactory: (options: TelegrafModuleOptions) => { + const telegraf = new Telegraf(options.token, options.options); + if (options.middlewares?.length > 0) { + telegraf.use(...options.middlewares); + } + return telegraf; + }, + inject: [TELEGRAF_MODULE_OPTIONS], +}; + +export function createProviders(options: TelegrafModuleOptions): Provider[] { + return [ + { + provide: TELEGRAF_MODULE_OPTIONS, + useValue: options, + }, + ]; +} diff --git a/lib/telegraf.types.ts b/lib/telegraf.types.ts new file mode 100644 index 0000000..4a6dc63 --- /dev/null +++ b/lib/telegraf.types.ts @@ -0,0 +1,21 @@ +import { BaseScene, Composer, Middleware } from 'telegraf'; + +export type Filter = T extends [] + ? [] + : T extends [infer Head, ...infer Tail] + ? Head extends F + ? Filter + : [Head, ...Filter] + : []; + +export type OnlyFunctionPropertyNames = { + [K in keyof T]: T[K] extends (...args: any) => any ? K : never; +}[keyof T]; + +export type ComposerMethodArgs< + T extends Composer, + U extends OnlyFunctionPropertyNames = OnlyFunctionPropertyNames +> = Filter, Middleware>; + +export type UpdateMethods = OnlyFunctionPropertyNames>; +export type SceneMethods = OnlyFunctionPropertyNames>; diff --git a/package-lock.json b/package-lock.json index c7dca95..7490ee2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,27 +1,25 @@ { "name": "nestjs-telegraf", - "version": "1.3.1", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.3.1", + "version": "2.0.0", "license": "MIT", "dependencies": { - "telegraf": "3.38.0" + "telegraf": "^3.38.0" }, "devDependencies": { "@nestjs/common": "7.6.5", "@nestjs/core": "7.6.5", - "@types/lodash": "^4.14.167", "@typescript-eslint/eslint-plugin": "4.11.1", "@typescript-eslint/parser": "4.11.1", - "eslint": "7.16.0", + "eslint": "7.17.0", "eslint-config-prettier": "7.1.0", "eslint-plugin-import": "2.22.1", "husky": "4.3.6", "lint-staged": "10.5.3", - "lodash": "^4.17.20", "prettier": "2.2.1", "reflect-metadata": "0.1.13", "rxjs": "6.6.3", @@ -294,12 +292,6 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "node_modules/@types/lodash": { - "version": "4.14.167", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.167.tgz", - "integrity": "sha512-w7tQPjARrvdeBkX/Rwg95S592JwxqOjmms3zWQ0XZgSyxSLdzWaYH3vErBhdVS/lRBX7F8aBYcYJYTr5TMGOzw==", - "dev": true - }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -944,9 +936,9 @@ } }, "node_modules/eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", - "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", + "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", @@ -3888,12 +3880,6 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "@types/lodash": { - "version": "4.14.167", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.167.tgz", - "integrity": "sha512-w7tQPjARrvdeBkX/Rwg95S592JwxqOjmms3zWQ0XZgSyxSLdzWaYH3vErBhdVS/lRBX7F8aBYcYJYTr5TMGOzw==", - "dev": true - }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -4377,9 +4363,9 @@ "dev": true }, "eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", - "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", + "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", diff --git a/package.json b/package.json index b783949..4bb4b75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestjs-telegraf", - "version": "1.3.1", + "version": "2.0.0", "description": "Telegraf module for NestJS", "keywords": [ "nest", @@ -32,7 +32,7 @@ "test": "" }, "dependencies": { - "telegraf": "3.38.0" + "telegraf": "^3.38.0" }, "devDependencies": { "@nestjs/common": "7.6.5", @@ -40,7 +40,7 @@ "@types/lodash": "^4.14.167", "@typescript-eslint/eslint-plugin": "4.11.1", "@typescript-eslint/parser": "4.11.1", - "eslint": "7.16.0", + "eslint": "7.17.0", "eslint-config-prettier": "7.1.0", "eslint-plugin-import": "2.22.1", "husky": "4.3.6", diff --git a/sample/app.constants.ts b/sample/app.constants.ts new file mode 100644 index 0000000..b9cfdda --- /dev/null +++ b/sample/app.constants.ts @@ -0,0 +1 @@ +export const HELLO_SCENE_ID = 'HELLO_SCENE_ID'; diff --git a/sample/app.module.ts b/sample/app.module.ts new file mode 100644 index 0000000..2d177de --- /dev/null +++ b/sample/app.module.ts @@ -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 {} diff --git a/sample/app.update.ts b/sample/app.update.ts new file mode 100644 index 0000000..f3c5022 --- /dev/null +++ b/sample/app.update.ts @@ -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, // TODO: fix any + private readonly echoService: EchoService, + ) {} + + @Start() + async onStart(ctx: Context): Promise { + const me = await this.bot.telegram.getMe(); + await ctx.reply(`Hey, I'm ${me.first_name}`); + } + + @Help() + async onHelp(ctx: Context): Promise { + await ctx.reply('Send me any text'); + } + + @Command('scene') + async onSceneCommand(ctx: Context): Promise { + await ctx.scene.enter(HELLO_SCENE_ID); + } + + @On('message') + async onMessage(ctx: Context): Promise { + 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'); + } + } +} diff --git a/sample/echo.service.ts b/sample/echo.service.ts new file mode 100644 index 0000000..2603cc2 --- /dev/null +++ b/sample/echo.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class EchoService { + echo(text: string): string { + return `Echo: ${text}`; + } +} diff --git a/sample/interfaces/context.interface.ts b/sample/interfaces/context.interface.ts new file mode 100644 index 0000000..58f20ef --- /dev/null +++ b/sample/interfaces/context.interface.ts @@ -0,0 +1,4 @@ +import { SceneContextMessageUpdate } from 'telegraf/typings/stage'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface Context extends SceneContextMessageUpdate {} diff --git a/sample/main.ts b/sample/main.ts new file mode 100644 index 0000000..42c2fa5 --- /dev/null +++ b/sample/main.ts @@ -0,0 +1,7 @@ +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; + +async function bootstrap() { + await NestFactory.createApplicationContext(AppModule); +} +bootstrap(); diff --git a/sample/middleware/session.middleware.ts b/sample/middleware/session.middleware.ts new file mode 100644 index 0000000..c203f15 --- /dev/null +++ b/sample/middleware/session.middleware.ts @@ -0,0 +1,3 @@ +import { session } from 'telegraf'; + +export const sessionMiddleware = session(); diff --git a/sample/scenes/hello.scene.ts b/sample/scenes/hello.scene.ts new file mode 100644 index 0000000..f84a6f4 --- /dev/null +++ b/sample/scenes/hello.scene.ts @@ -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 { + console.log('Enter to scene'); + await ctx.reply('Welcome on scene ✋'); + } + + @SceneLeave() + async onSceneLeave(ctx: Context): Promise { + console.log('Leave from scene'); + await ctx.reply('Bye Bye 👋'); + } + + @Command('hello') + async onHelloCommand(ctx: Context): Promise { + console.log('Use say hello'); + await ctx.reply('Hi'); + } + + @Command('leave') + async onLeaveCommand(ctx: Context): Promise { + await ctx.scene.leave(); + } +}