mirror of
				https://github.com/Maks1mS/nestjs-telegraf.git
				synced 2025-11-03 23:41:23 +03:00 
			
		
		
		
	
							
								
								
									
										26
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  parser: '@typescript-eslint/parser',
 | 
			
		||||
  parserOptions: {
 | 
			
		||||
    project: 'tsconfig.json',
 | 
			
		||||
    sourceType: 'module',
 | 
			
		||||
  },
 | 
			
		||||
  plugins: ['@typescript-eslint/eslint-plugin'],
 | 
			
		||||
  extends: [
 | 
			
		||||
    'plugin:@typescript-eslint/recommended',
 | 
			
		||||
    'plugin:prettier/recommended',
 | 
			
		||||
  ],
 | 
			
		||||
  root: true,
 | 
			
		||||
  env: {
 | 
			
		||||
    node: true,
 | 
			
		||||
    jest: true,
 | 
			
		||||
  },
 | 
			
		||||
  ignorePatterns: ['.eslintrc.js'],
 | 
			
		||||
  rules: {
 | 
			
		||||
    '@typescript-eslint/interface-name-prefix': 'off',
 | 
			
		||||
    '@typescript-eslint/explicit-function-return-type': 'off',
 | 
			
		||||
    '@typescript-eslint/no-explicit-any': 'off',
 | 
			
		||||
    '@typescript-eslint/no-use-before-define': 'off',
 | 
			
		||||
    '@typescript-eslint/no-non-null-assertion': 'off',
 | 
			
		||||
    '@typescript-eslint/ban-types': 'off',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
export * from './update.decorator';
 | 
			
		||||
export * from './scene.decorator';
 | 
			
		||||
export * from './wizard.decorator';
 | 
			
		||||
export * from './inject-bot.decorator';
 | 
			
		||||
export * from './inject-all-bots.decorator';
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
import { Inject } from '@nestjs/common';
 | 
			
		||||
import { Bot } from 'grammy';
 | 
			
		||||
import { Telegraf } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
import { getAllBotsToken } from '../../utils/get-all-bots-token.util';
 | 
			
		||||
 | 
			
		||||
export type AllBotsMap = Map<string, Bot<any>>;
 | 
			
		||||
export type AllBotsMap = Map<string, Telegraf<any>>;
 | 
			
		||||
 | 
			
		||||
export const InjectAllBots = (): ParameterDecorator =>
 | 
			
		||||
  Inject(getAllBotsToken());
 | 
			
		||||
							
								
								
									
										14
									
								
								lib/decorators/core/scene.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/decorators/core/scene.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import { SetMetadata } from '@nestjs/common';
 | 
			
		||||
import { SceneOptions } from 'telegraf/typings/scenes/base';
 | 
			
		||||
import { SceneMetadata } from '../../interfaces';
 | 
			
		||||
import { SCENE_METADATA } from '../../telegraf.constants';
 | 
			
		||||
 | 
			
		||||
export const Scene = (
 | 
			
		||||
  sceneId: string,
 | 
			
		||||
  options?: SceneOptions<any>,
 | 
			
		||||
): ClassDecorator =>
 | 
			
		||||
  SetMetadata<string, SceneMetadata>(SCENE_METADATA, {
 | 
			
		||||
    sceneId,
 | 
			
		||||
    type: 'base',
 | 
			
		||||
    options,
 | 
			
		||||
  });
 | 
			
		||||
							
								
								
									
										14
									
								
								lib/decorators/core/wizard.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/decorators/core/wizard.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import { SetMetadata } from '@nestjs/common';
 | 
			
		||||
import { SceneOptions } from 'telegraf/typings/scenes/base';
 | 
			
		||||
import { SceneMetadata } from '../../interfaces';
 | 
			
		||||
import { SCENE_METADATA } from '../../telegraf.constants';
 | 
			
		||||
 | 
			
		||||
export const Wizard = (
 | 
			
		||||
  sceneId: string,
 | 
			
		||||
  options?: SceneOptions<any>,
 | 
			
		||||
): ClassDecorator =>
 | 
			
		||||
  SetMetadata<string, SceneMetadata>(SCENE_METADATA, {
 | 
			
		||||
    sceneId,
 | 
			
		||||
    type: 'wizard',
 | 
			
		||||
    options,
 | 
			
		||||
  });
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
export * from './core';
 | 
			
		||||
export * from './listeners';
 | 
			
		||||
export * from './scene';
 | 
			
		||||
export * from './params';
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/action.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/action.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Registers middleware for handling callback_data actions with regular expressions.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=action
 | 
			
		||||
 */
 | 
			
		||||
export const Action = createListenerDecorator('action');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/cashtag.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/cashtag.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cashtag handling.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=cashtag
 | 
			
		||||
 */
 | 
			
		||||
export const Cashtag = createListenerDecorator('cashtag');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/email.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/email.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Registers middleware for handling messages with email entity.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=telegraf-email
 | 
			
		||||
 */
 | 
			
		||||
export const Email = createListenerDecorator('email');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/hashtag.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/hashtag.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hashtag handling.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=hashtag
 | 
			
		||||
 */
 | 
			
		||||
export const Hashtag = createListenerDecorator('hashtag');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/help.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/help.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler for /help command.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=help
 | 
			
		||||
 */
 | 
			
		||||
export const Help = createListenerDecorator('help');
 | 
			
		||||
							
								
								
									
										18
									
								
								lib/decorators/listeners/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/decorators/listeners/index.ts
									
									
									
									
									
										Normal 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';
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/mention.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/mention.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mention handling.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=mention
 | 
			
		||||
 */
 | 
			
		||||
export const Mention = createListenerDecorator('mention');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/phone.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/phone.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Phone number handling.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=phone
 | 
			
		||||
 */
 | 
			
		||||
export const Phone = createListenerDecorator('phone');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/settings.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/settings.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler for /settings command.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=settings
 | 
			
		||||
 */
 | 
			
		||||
export const Settings = createListenerDecorator('settings');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/start.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/start.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler for /start command.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=start
 | 
			
		||||
 */
 | 
			
		||||
export const Start = createListenerDecorator('start');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/text-link.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/text-link.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Registers middleware for handling messages with text_link entity.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=telegraf-textlink
 | 
			
		||||
 */
 | 
			
		||||
export const TextLink = createListenerDecorator('textLink');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/text-mention.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/text-mention.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Registers middleware for handling messages with text_mention entity.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=telegraf-textlink
 | 
			
		||||
 */
 | 
			
		||||
export const TextMention = createListenerDecorator('textMention');
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/decorators/listeners/url.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/decorators/listeners/url.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Registers middleware for handling messages with url entity.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://telegraf.js.org/#/?id=telegraf-url
 | 
			
		||||
 */
 | 
			
		||||
export const Url = createListenerDecorator('url');
 | 
			
		||||
							
								
								
									
										3
									
								
								lib/decorators/scene/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								lib/decorators/scene/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export * from './scene-enter.decorator';
 | 
			
		||||
export * from './scene-leave.decorator';
 | 
			
		||||
export * from './wizard-step.decorator';
 | 
			
		||||
							
								
								
									
										5
									
								
								lib/decorators/scene/scene-enter.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/decorators/scene/scene-enter.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
import { Scenes } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
export const SceneEnter =
 | 
			
		||||
  createListenerDecorator<Scenes.BaseScene<never>>('enter');
 | 
			
		||||
							
								
								
									
										5
									
								
								lib/decorators/scene/scene-leave.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/decorators/scene/scene-leave.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
import { createListenerDecorator } from '../../utils';
 | 
			
		||||
import { Scenes } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
export const SceneLeave =
 | 
			
		||||
  createListenerDecorator<Scenes.BaseScene<never>>('leave');
 | 
			
		||||
							
								
								
									
										6
									
								
								lib/decorators/scene/wizard-step.decorator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/decorators/scene/wizard-step.decorator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import { SetMetadata } from '@nestjs/common';
 | 
			
		||||
import { WizardStepMetadata } from '../../interfaces';
 | 
			
		||||
import { WIZARD_STEP_METADATA } from '../../telegraf.constants';
 | 
			
		||||
 | 
			
		||||
export const WizardStep = (step: number) =>
 | 
			
		||||
  SetMetadata<string, WizardStepMetadata>(WIZARD_STEP_METADATA, { step });
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { ParamData } from '@nestjs/common';
 | 
			
		||||
import { ParamsFactory } from '@nestjs/core/helpers/external-context-creator';
 | 
			
		||||
import { Context } from 'grammy';
 | 
			
		||||
import { Context } from 'telegraf';
 | 
			
		||||
import { TelegrafParamtype } from '../enums/telegraf-paramtype.enum';
 | 
			
		||||
 | 
			
		||||
export class TelegrafParamsFactory implements ParamsFactory {
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
export * from './telegraf-options.interface';
 | 
			
		||||
export * from './listener-metadata.interface';
 | 
			
		||||
export * from './scene-metadata.interface';
 | 
			
		||||
export * from './telegraf-exception-filter.interface';
 | 
			
		||||
							
								
								
									
										11
									
								
								lib/interfaces/scene-metadata.interface.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/interfaces/scene-metadata.interface.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import { SceneOptions } from 'telegraf/typings/scenes/base';
 | 
			
		||||
 | 
			
		||||
export interface SceneMetadata {
 | 
			
		||||
  sceneId: string;
 | 
			
		||||
  type: 'base' | 'wizard';
 | 
			
		||||
  options?: SceneOptions<any>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface WizardStepMetadata {
 | 
			
		||||
  step: number;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
 | 
			
		||||
import { Middleware, PollingOptions, BotConfig } from 'grammy';
 | 
			
		||||
import { Middleware, Telegraf } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
export interface TelegrafModuleOptions {
 | 
			
		||||
  token: string;
 | 
			
		||||
  config?: BotConfig<any>;
 | 
			
		||||
  pollingOptions?: PollingOptions | false;
 | 
			
		||||
  botName?: string;
 | 
			
		||||
  options?: Partial<Telegraf.Options<any>>;
 | 
			
		||||
  launchOptions?: Telegraf.LaunchOptions | false;
 | 
			
		||||
  include?: Function[];
 | 
			
		||||
  middlewares?: ReadonlyArray<Middleware<any>>;
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,7 @@ import { MetadataScanner } from '@nestjs/core/metadata-scanner';
 | 
			
		||||
import { Module } from '@nestjs/core/injector/module';
 | 
			
		||||
import { ParamMetadata } from '@nestjs/core/helpers/interfaces';
 | 
			
		||||
import { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
 | 
			
		||||
import { Composer, Context, Bot } from 'grammy';
 | 
			
		||||
import { Composer, Context, Scenes, Telegraf } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
import { MetadataAccessorService } from './metadata-accessor.service';
 | 
			
		||||
import {
 | 
			
		||||
@@ -25,9 +25,11 @@ export class ListenersExplorerService
 | 
			
		||||
  implements OnModuleInit
 | 
			
		||||
{
 | 
			
		||||
  private readonly telegrafParamsFactory = new TelegrafParamsFactory();
 | 
			
		||||
  private bot: Bot;
 | 
			
		||||
  private bot: Telegraf<any>;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    @Inject(TELEGRAF_STAGE)
 | 
			
		||||
    private readonly stage: Scenes.Stage<any>,
 | 
			
		||||
    @Inject(TELEGRAF_MODULE_OPTIONS)
 | 
			
		||||
    private readonly telegrafOptions: TelegrafModuleOptions,
 | 
			
		||||
    @Inject(TELEGRAF_BOT_NAME)
 | 
			
		||||
@@ -43,9 +45,10 @@ export class ListenersExplorerService
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onModuleInit(): void {
 | 
			
		||||
    this.bot = this.moduleRef.get<Bot>(this.botName, {
 | 
			
		||||
    this.bot = this.moduleRef.get<Telegraf<any>>(this.botName, {
 | 
			
		||||
      strict: false,
 | 
			
		||||
    });
 | 
			
		||||
    this.bot.use(this.stage.middleware());
 | 
			
		||||
 | 
			
		||||
    this.explore();
 | 
			
		||||
  }
 | 
			
		||||
@@ -57,6 +60,7 @@ export class ListenersExplorerService
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    this.registerUpdates(modules);
 | 
			
		||||
    this.registerScenes(modules);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private registerUpdates(modules: Module[]): void {
 | 
			
		||||
@@ -66,6 +70,28 @@ export class ListenersExplorerService
 | 
			
		||||
    updates.forEach((wrapper) => this.registerListeners(this.bot, wrapper));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private registerScenes(modules: Module[]): void {
 | 
			
		||||
    const scenes = this.flatMap<InstanceWrapper>(modules, (wrapper) =>
 | 
			
		||||
      this.filterScenes(wrapper),
 | 
			
		||||
    );
 | 
			
		||||
    scenes.forEach((wrapper) => {
 | 
			
		||||
      const { sceneId, type, options } = this.metadataAccessor.getSceneMetadata(
 | 
			
		||||
        wrapper.instance.constructor,
 | 
			
		||||
      );
 | 
			
		||||
      const scene =
 | 
			
		||||
        type === 'base'
 | 
			
		||||
          ? new Scenes.BaseScene<any>(sceneId, options || ({} as any))
 | 
			
		||||
          : new Scenes.WizardScene<any>(sceneId, options || ({} as any));
 | 
			
		||||
      this.stage.register(scene);
 | 
			
		||||
 | 
			
		||||
      if (type === 'base') {
 | 
			
		||||
        this.registerListeners(scene, wrapper);
 | 
			
		||||
      } else {
 | 
			
		||||
        this.registerWizardListeners(scene as Scenes.WizardScene<any>, wrapper);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private filterUpdates(wrapper: InstanceWrapper): InstanceWrapper<unknown> {
 | 
			
		||||
    const { instance } = wrapper;
 | 
			
		||||
    if (!instance) return undefined;
 | 
			
		||||
@@ -76,6 +102,16 @@ export class ListenersExplorerService
 | 
			
		||||
    return wrapper;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private filterScenes(wrapper: InstanceWrapper): InstanceWrapper<unknown> {
 | 
			
		||||
    const { instance } = wrapper;
 | 
			
		||||
    if (!instance) return undefined;
 | 
			
		||||
 | 
			
		||||
    const isScene = this.metadataAccessor.isScene(wrapper.metatype);
 | 
			
		||||
    if (!isScene) return undefined;
 | 
			
		||||
 | 
			
		||||
    return wrapper;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private registerListeners(
 | 
			
		||||
    composer: Composer<any>,
 | 
			
		||||
    wrapper: InstanceWrapper<unknown>,
 | 
			
		||||
@@ -87,6 +123,60 @@ export class ListenersExplorerService
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private registerWizardListeners(
 | 
			
		||||
    wizard: Scenes.WizardScene<any>,
 | 
			
		||||
    wrapper: InstanceWrapper<unknown>,
 | 
			
		||||
  ): void {
 | 
			
		||||
    const { instance } = wrapper;
 | 
			
		||||
    const prototype = Object.getPrototypeOf(instance);
 | 
			
		||||
 | 
			
		||||
    type WizardMetadata = { step: number; methodName: string };
 | 
			
		||||
    const wizardSteps: WizardMetadata[] = [];
 | 
			
		||||
    const basicListeners = [];
 | 
			
		||||
 | 
			
		||||
    this.metadataScanner.scanFromPrototype(
 | 
			
		||||
      instance,
 | 
			
		||||
      prototype,
 | 
			
		||||
      (methodName) => {
 | 
			
		||||
        const methodRef = prototype[methodName];
 | 
			
		||||
        const metadata = this.metadataAccessor.getWizardStepMetadata(methodRef);
 | 
			
		||||
        if (!metadata) {
 | 
			
		||||
          basicListeners.push(methodName);
 | 
			
		||||
          return undefined;
 | 
			
		||||
        }
 | 
			
		||||
        wizardSteps.push({ step: metadata.step, methodName });
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    for (const methodName of basicListeners) {
 | 
			
		||||
      this.registerIfListener(wizard, instance, prototype, methodName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const group = wizardSteps
 | 
			
		||||
      .sort((a, b) => a.step - b.step)
 | 
			
		||||
      .reduce<{ [key: number]: WizardMetadata[] }>(
 | 
			
		||||
        (prev, cur) => ({
 | 
			
		||||
          ...prev,
 | 
			
		||||
          [cur.step]: [...(prev[cur.step] || []), cur],
 | 
			
		||||
        }),
 | 
			
		||||
        {},
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    wizard.steps = Object.values(group).map((stepsMetadata) => {
 | 
			
		||||
      const composer = new Composer();
 | 
			
		||||
      stepsMetadata.forEach((stepMethod) => {
 | 
			
		||||
        this.registerIfListener(
 | 
			
		||||
          composer,
 | 
			
		||||
          instance,
 | 
			
		||||
          prototype,
 | 
			
		||||
          stepMethod.methodName,
 | 
			
		||||
          [{ method: 'use', args: [] }],
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
      return composer.middleware();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private registerIfListener(
 | 
			
		||||
    composer: Composer<any>,
 | 
			
		||||
    instance: any,
 | 
			
		||||
							
								
								
									
										40
									
								
								lib/services/metadata-accessor.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								lib/services/metadata-accessor.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Reflector } from '@nestjs/core';
 | 
			
		||||
import {
 | 
			
		||||
  SCENE_METADATA,
 | 
			
		||||
  LISTENERS_METADATA,
 | 
			
		||||
  UPDATE_METADATA,
 | 
			
		||||
  WIZARD_STEP_METADATA,
 | 
			
		||||
} from '../telegraf.constants';
 | 
			
		||||
import {
 | 
			
		||||
  ListenerMetadata,
 | 
			
		||||
  SceneMetadata,
 | 
			
		||||
  WizardStepMetadata,
 | 
			
		||||
} 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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isScene(target: Function): boolean {
 | 
			
		||||
    if (!target) return false;
 | 
			
		||||
    return !!this.reflector.get(SCENE_METADATA, target);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getListenerMetadata(target: Function): ListenerMetadata[] | undefined {
 | 
			
		||||
    return this.reflector.get(LISTENERS_METADATA, target);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getSceneMetadata(target: Function): SceneMetadata | undefined {
 | 
			
		||||
    return this.reflector.get(SCENE_METADATA, target);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getWizardStepMetadata(target: Function): WizardStepMetadata | undefined {
 | 
			
		||||
    return this.reflector.get(WIZARD_STEP_METADATA, target);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/stage.provider.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/stage.provider.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { Provider } from '@nestjs/common';
 | 
			
		||||
import { Scenes } from 'telegraf';
 | 
			
		||||
import { TELEGRAF_STAGE } from './telegraf.constants';
 | 
			
		||||
 | 
			
		||||
export const telegrafStageProvider: Provider = {
 | 
			
		||||
  provide: TELEGRAF_STAGE,
 | 
			
		||||
  useClass: Scenes.Stage,
 | 
			
		||||
};
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
import { Provider } from '@nestjs/common';
 | 
			
		||||
import { Bot } from 'grammy';
 | 
			
		||||
import { Telegraf } from 'telegraf';
 | 
			
		||||
import { TELEGRAF_ALL_BOTS } from './telegraf.constants';
 | 
			
		||||
 | 
			
		||||
export const allBotsMap = new Map<string, Bot<any>>();
 | 
			
		||||
export const allBotsMap = new Map<string, Telegraf<any>>();
 | 
			
		||||
 | 
			
		||||
export const telegrafAllBotsProvider: Provider = {
 | 
			
		||||
  provide: TELEGRAF_ALL_BOTS,
 | 
			
		||||
@@ -18,6 +18,7 @@ import {
 | 
			
		||||
  TELEGRAF_MODULE_OPTIONS,
 | 
			
		||||
} from './telegraf.constants';
 | 
			
		||||
import { ListenersExplorerService, MetadataAccessorService } from './services';
 | 
			
		||||
import { telegrafStageProvider } from './stage.provider';
 | 
			
		||||
import {
 | 
			
		||||
  allBotsMap,
 | 
			
		||||
  telegrafAllBotsProvider,
 | 
			
		||||
@@ -60,11 +61,13 @@ export class TelegrafCoreModule implements OnApplicationShutdown {
 | 
			
		||||
          provide: TELEGRAF_MODULE_OPTIONS,
 | 
			
		||||
          useValue: options,
 | 
			
		||||
        },
 | 
			
		||||
        telegrafStageProvider,
 | 
			
		||||
        telegrafBotNameProvider,
 | 
			
		||||
        telegrafBotProvider,
 | 
			
		||||
        telegrafAllBotsProvider,
 | 
			
		||||
      ],
 | 
			
		||||
      exports: [
 | 
			
		||||
        telegrafStageProvider,
 | 
			
		||||
        telegrafBotNameProvider,
 | 
			
		||||
        telegrafBotProvider,
 | 
			
		||||
        telegrafAllBotsProvider,
 | 
			
		||||
@@ -98,11 +101,13 @@ export class TelegrafCoreModule implements OnApplicationShutdown {
 | 
			
		||||
      imports: options.imports,
 | 
			
		||||
      providers: [
 | 
			
		||||
        ...asyncProviders,
 | 
			
		||||
        telegrafStageProvider,
 | 
			
		||||
        telegrafBotNameProvider,
 | 
			
		||||
        telegrafBotProvider,
 | 
			
		||||
        telegrafAllBotsProvider,
 | 
			
		||||
      ],
 | 
			
		||||
      exports: [
 | 
			
		||||
        telegrafStageProvider,
 | 
			
		||||
        telegrafBotNameProvider,
 | 
			
		||||
        telegrafBotProvider,
 | 
			
		||||
        telegrafAllBotsProvider,
 | 
			
		||||
@@ -6,10 +6,10 @@ import {
 | 
			
		||||
} from './interfaces';
 | 
			
		||||
 | 
			
		||||
@Module({})
 | 
			
		||||
export class GrammyModule {
 | 
			
		||||
export class TelegrafModule {
 | 
			
		||||
  public static forRoot(options: TelegrafModuleOptions): DynamicModule {
 | 
			
		||||
    return {
 | 
			
		||||
      module: GrammyModule,
 | 
			
		||||
      module: TelegrafModule,
 | 
			
		||||
      imports: [TelegrafCoreModule.forRoot(options)],
 | 
			
		||||
      exports: [TelegrafCoreModule],
 | 
			
		||||
    };
 | 
			
		||||
@@ -19,7 +19,7 @@ export class GrammyModule {
 | 
			
		||||
    options: TelegrafModuleAsyncOptions,
 | 
			
		||||
  ): DynamicModule {
 | 
			
		||||
    return {
 | 
			
		||||
      module: GrammyModule,
 | 
			
		||||
      module: TelegrafModule,
 | 
			
		||||
      imports: [TelegrafCoreModule.forRootAsync(options)],
 | 
			
		||||
      exports: [TelegrafCoreModule],
 | 
			
		||||
    };
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { Composer, Middleware } from 'grammy';
 | 
			
		||||
import { Composer, Middleware } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
export type Filter<T extends any[], F> = T extends []
 | 
			
		||||
  ? []
 | 
			
		||||
							
								
								
									
										16
									
								
								lib/utils/create-bot-factory.util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/utils/create-bot-factory.util.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
import { Telegraf } from 'telegraf';
 | 
			
		||||
import { TelegrafModuleOptions } from '../interfaces';
 | 
			
		||||
 | 
			
		||||
export async function createBotFactory(
 | 
			
		||||
  options: TelegrafModuleOptions,
 | 
			
		||||
): Promise<Telegraf<any>> {
 | 
			
		||||
  const bot = new Telegraf<any>(options.token, options.options);
 | 
			
		||||
 | 
			
		||||
  bot.use(...(options.middlewares ?? []));
 | 
			
		||||
 | 
			
		||||
  if (options.launchOptions !== false) {
 | 
			
		||||
    await bot.launch(options.launchOptions);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return bot;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { Composer } from 'grammy';
 | 
			
		||||
import { Composer } from 'telegraf';
 | 
			
		||||
import { ComposerMethodArgs, OnlyFunctionPropertyNames } from '../types';
 | 
			
		||||
import { LISTENERS_METADATA } from '../telegraf.constants';
 | 
			
		||||
import { ListenerMetadata } from '../interfaces';
 | 
			
		||||
							
								
								
									
										2
									
								
								sample/01-complete-app/.env.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								sample/01-complete-app/.env.example
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
ECHO_BOT_TOKEN=
 | 
			
		||||
GREETER_BOT_TOKEN=
 | 
			
		||||
							
								
								
									
										24
									
								
								sample/01-complete-app/.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								sample/01-complete-app/.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  parser: '@typescript-eslint/parser',
 | 
			
		||||
  parserOptions: {
 | 
			
		||||
    project: 'tsconfig.json',
 | 
			
		||||
    sourceType: 'module',
 | 
			
		||||
  },
 | 
			
		||||
  plugins: ['@typescript-eslint/eslint-plugin'],
 | 
			
		||||
  extends: [
 | 
			
		||||
    'plugin:@typescript-eslint/recommended',
 | 
			
		||||
    'plugin:prettier/recommended',
 | 
			
		||||
  ],
 | 
			
		||||
  root: true,
 | 
			
		||||
  env: {
 | 
			
		||||
    node: true,
 | 
			
		||||
    jest: true,
 | 
			
		||||
  },
 | 
			
		||||
  ignorePatterns: ['.eslintrc.js'],
 | 
			
		||||
  rules: {
 | 
			
		||||
    '@typescript-eslint/interface-name-prefix': 'off',
 | 
			
		||||
    '@typescript-eslint/explicit-function-return-type': 'off',
 | 
			
		||||
    '@typescript-eslint/explicit-module-boundary-types': 'off',
 | 
			
		||||
    '@typescript-eslint/no-explicit-any': 'off',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										398
									
								
								sample/01-complete-app/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								sample/01-complete-app/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,398 @@
 | 
			
		||||
# Created by .ignore support plugin (hsz.mobi)
 | 
			
		||||
### JetBrains template
 | 
			
		||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
 | 
			
		||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
 | 
			
		||||
 | 
			
		||||
# User-specific stuff:
 | 
			
		||||
.idea/**/workspace.xml
 | 
			
		||||
.idea/**/tasks.xml
 | 
			
		||||
.idea/dictionaries
 | 
			
		||||
 | 
			
		||||
# Sensitive or high-churn files:
 | 
			
		||||
.idea/**/dataSources/
 | 
			
		||||
.idea/**/dataSources.ids
 | 
			
		||||
.idea/**/dataSources.xml
 | 
			
		||||
.idea/**/dataSources.local.xml
 | 
			
		||||
.idea/**/sqlDataSources.xml
 | 
			
		||||
.idea/**/dynamic.xml
 | 
			
		||||
.idea/**/uiDesigner.xml
 | 
			
		||||
 | 
			
		||||
# Gradle:
 | 
			
		||||
.idea/**/gradle.xml
 | 
			
		||||
.idea/**/libraries
 | 
			
		||||
 | 
			
		||||
# CMake
 | 
			
		||||
cmake-build-debug/
 | 
			
		||||
 | 
			
		||||
# Mongo Explorer plugin:
 | 
			
		||||
.idea/**/mongoSettings.xml
 | 
			
		||||
 | 
			
		||||
## File-based project format:
 | 
			
		||||
*.iws
 | 
			
		||||
 | 
			
		||||
## Plugin-specific files:
 | 
			
		||||
 | 
			
		||||
# IntelliJ
 | 
			
		||||
out/
 | 
			
		||||
 | 
			
		||||
# mpeltonen/sbt-idea plugin
 | 
			
		||||
.idea_modules/
 | 
			
		||||
 | 
			
		||||
# JIRA plugin
 | 
			
		||||
atlassian-ide-plugin.xml
 | 
			
		||||
 | 
			
		||||
# Cursive Clojure plugin
 | 
			
		||||
.idea/replstate.xml
 | 
			
		||||
 | 
			
		||||
# Crashlytics plugin (for Android Studio and IntelliJ)
 | 
			
		||||
com_crashlytics_export_strings.xml
 | 
			
		||||
crashlytics.properties
 | 
			
		||||
crashlytics-build.properties
 | 
			
		||||
fabric.properties
 | 
			
		||||
### VisualStudio template
 | 
			
		||||
## Ignore Visual Studio temporary files, build results, and
 | 
			
		||||
## files generated by popular Visual Studio add-ons.
 | 
			
		||||
##
 | 
			
		||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
 | 
			
		||||
 | 
			
		||||
# User-specific files
 | 
			
		||||
*.suo
 | 
			
		||||
*.user
 | 
			
		||||
*.userosscache
 | 
			
		||||
*.sln.docstates
 | 
			
		||||
 | 
			
		||||
# User-specific files (MonoDevelop/Xamarin Studio)
 | 
			
		||||
*.userprefs
 | 
			
		||||
 | 
			
		||||
# Build results
 | 
			
		||||
[Dd]ebug/
 | 
			
		||||
[Dd]ebugPublic/
 | 
			
		||||
[Rr]elease/
 | 
			
		||||
[Rr]eleases/
 | 
			
		||||
x64/
 | 
			
		||||
x86/
 | 
			
		||||
bld/
 | 
			
		||||
[Bb]in/
 | 
			
		||||
[Oo]bj/
 | 
			
		||||
[Ll]og/
 | 
			
		||||
 | 
			
		||||
# Visual Studio 2015 cache/options directory
 | 
			
		||||
.vs/
 | 
			
		||||
# Uncomment if you have tasks that create the project's static files in wwwroot
 | 
			
		||||
#wwwroot/
 | 
			
		||||
 | 
			
		||||
# MSTest test Results
 | 
			
		||||
[Tt]est[Rr]esult*/
 | 
			
		||||
[Bb]uild[Ll]og.*
 | 
			
		||||
 | 
			
		||||
# NUNIT
 | 
			
		||||
*.VisualState.xml
 | 
			
		||||
TestResult.xml
 | 
			
		||||
 | 
			
		||||
# Build Results of an ATL Project
 | 
			
		||||
[Dd]ebugPS/
 | 
			
		||||
[Rr]eleasePS/
 | 
			
		||||
dlldata.c
 | 
			
		||||
 | 
			
		||||
# Benchmark Results
 | 
			
		||||
BenchmarkDotNet.Artifacts/
 | 
			
		||||
 | 
			
		||||
# .NET Core
 | 
			
		||||
project.lock.json
 | 
			
		||||
project.fragment.lock.json
 | 
			
		||||
artifacts/
 | 
			
		||||
**/Properties/launchSettings.json
 | 
			
		||||
 | 
			
		||||
*_i.c
 | 
			
		||||
*_p.c
 | 
			
		||||
*_i.h
 | 
			
		||||
*.ilk
 | 
			
		||||
*.meta
 | 
			
		||||
*.obj
 | 
			
		||||
*.pch
 | 
			
		||||
*.pdb
 | 
			
		||||
*.pgc
 | 
			
		||||
*.pgd
 | 
			
		||||
*.rsp
 | 
			
		||||
*.sbr
 | 
			
		||||
*.tlb
 | 
			
		||||
*.tli
 | 
			
		||||
*.tlh
 | 
			
		||||
*.tmp
 | 
			
		||||
*.tmp_proj
 | 
			
		||||
*.log
 | 
			
		||||
*.vspscc
 | 
			
		||||
*.vssscc
 | 
			
		||||
.builds
 | 
			
		||||
*.pidb
 | 
			
		||||
*.svclog
 | 
			
		||||
*.scc
 | 
			
		||||
 | 
			
		||||
# Chutzpah Test files
 | 
			
		||||
_Chutzpah*
 | 
			
		||||
 | 
			
		||||
# Visual C++ cache files
 | 
			
		||||
ipch/
 | 
			
		||||
*.aps
 | 
			
		||||
*.ncb
 | 
			
		||||
*.opendb
 | 
			
		||||
*.opensdf
 | 
			
		||||
*.sdf
 | 
			
		||||
*.cachefile
 | 
			
		||||
*.VC.db
 | 
			
		||||
*.VC.VC.opendb
 | 
			
		||||
 | 
			
		||||
# Visual Studio profiler
 | 
			
		||||
*.psess
 | 
			
		||||
*.vsp
 | 
			
		||||
*.vspx
 | 
			
		||||
*.sap
 | 
			
		||||
 | 
			
		||||
# Visual Studio Trace Files
 | 
			
		||||
*.e2e
 | 
			
		||||
 | 
			
		||||
# TFS 2012 Local Workspace
 | 
			
		||||
$tf/
 | 
			
		||||
 | 
			
		||||
# Guidance Automation Toolkit
 | 
			
		||||
*.gpState
 | 
			
		||||
 | 
			
		||||
# ReSharper is a .NET coding add-in
 | 
			
		||||
_ReSharper*/
 | 
			
		||||
*.[Rr]e[Ss]harper
 | 
			
		||||
*.DotSettings.user
 | 
			
		||||
 | 
			
		||||
# JustCode is a .NET coding add-in
 | 
			
		||||
.JustCode
 | 
			
		||||
 | 
			
		||||
# TeamCity is a build add-in
 | 
			
		||||
_TeamCity*
 | 
			
		||||
 | 
			
		||||
# DotCover is a Code Coverage Tool
 | 
			
		||||
*.dotCover
 | 
			
		||||
 | 
			
		||||
# AxoCover is a Code Coverage Tool
 | 
			
		||||
.axoCover/*
 | 
			
		||||
!.axoCover/settings.json
 | 
			
		||||
 | 
			
		||||
# Visual Studio code coverage results
 | 
			
		||||
*.coverage
 | 
			
		||||
*.coveragexml
 | 
			
		||||
 | 
			
		||||
# NCrunch
 | 
			
		||||
_NCrunch_*
 | 
			
		||||
.*crunch*.local.xml
 | 
			
		||||
nCrunchTemp_*
 | 
			
		||||
 | 
			
		||||
# MightyMoose
 | 
			
		||||
*.mm.*
 | 
			
		||||
AutoTest.Net/
 | 
			
		||||
 | 
			
		||||
# Web workbench (sass)
 | 
			
		||||
.sass-cache/
 | 
			
		||||
 | 
			
		||||
# Installshield output folder
 | 
			
		||||
[Ee]xpress/
 | 
			
		||||
 | 
			
		||||
# DocProject is a documentation generator add-in
 | 
			
		||||
DocProject/buildhelp/
 | 
			
		||||
DocProject/Help/*.HxT
 | 
			
		||||
DocProject/Help/*.HxC
 | 
			
		||||
DocProject/Help/*.hhc
 | 
			
		||||
DocProject/Help/*.hhk
 | 
			
		||||
DocProject/Help/*.hhp
 | 
			
		||||
DocProject/Help/Html2
 | 
			
		||||
DocProject/Help/html
 | 
			
		||||
 | 
			
		||||
# Click-Once directory
 | 
			
		||||
publish/
 | 
			
		||||
 | 
			
		||||
# Publish Web Output
 | 
			
		||||
*.[Pp]ublish.xml
 | 
			
		||||
*.azurePubxml
 | 
			
		||||
# Note: Comment the next line if you want to checkin your web deploy settings,
 | 
			
		||||
# but database connection strings (with potential passwords) will be unencrypted
 | 
			
		||||
*.pubxml
 | 
			
		||||
*.publishproj
 | 
			
		||||
 | 
			
		||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
 | 
			
		||||
# checkin your Azure Web App publish settings, but sensitive information contained
 | 
			
		||||
# in these scripts will be unencrypted
 | 
			
		||||
PublishScripts/
 | 
			
		||||
 | 
			
		||||
# NuGet Packages
 | 
			
		||||
*.nupkg
 | 
			
		||||
# The packages folder can be ignored because of Package Restore
 | 
			
		||||
**/[Pp]ackages/*
 | 
			
		||||
# except build/, which is used as an MSBuild target.
 | 
			
		||||
!**/[Pp]ackages/build/
 | 
			
		||||
# Uncomment if necessary however generally it will be regenerated when needed
 | 
			
		||||
#!**/[Pp]ackages/repositories.config
 | 
			
		||||
# NuGet v3's project.json files produces more ignorable files
 | 
			
		||||
*.nuget.props
 | 
			
		||||
*.nuget.targets
 | 
			
		||||
 | 
			
		||||
# Microsoft Azure Build Output
 | 
			
		||||
csx/
 | 
			
		||||
*.build.csdef
 | 
			
		||||
 | 
			
		||||
# Microsoft Azure Emulator
 | 
			
		||||
ecf/
 | 
			
		||||
rcf/
 | 
			
		||||
 | 
			
		||||
# Windows Store app package directories and files
 | 
			
		||||
AppPackages/
 | 
			
		||||
BundleArtifacts/
 | 
			
		||||
Package.StoreAssociation.xml
 | 
			
		||||
_pkginfo.txt
 | 
			
		||||
*.appx
 | 
			
		||||
 | 
			
		||||
# Visual Studio cache files
 | 
			
		||||
# files ending in .cache can be ignored
 | 
			
		||||
*.[Cc]ache
 | 
			
		||||
# but keep track of directories ending in .cache
 | 
			
		||||
!*.[Cc]ache/
 | 
			
		||||
 | 
			
		||||
# Others
 | 
			
		||||
ClientBin/
 | 
			
		||||
~$*
 | 
			
		||||
*~
 | 
			
		||||
*.dbmdl
 | 
			
		||||
*.dbproj.schemaview
 | 
			
		||||
*.jfm
 | 
			
		||||
*.pfx
 | 
			
		||||
*.publishsettings
 | 
			
		||||
orleans.codegen.cs
 | 
			
		||||
 | 
			
		||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
 | 
			
		||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
 | 
			
		||||
#bower_components/
 | 
			
		||||
 | 
			
		||||
# RIA/Silverlight projects
 | 
			
		||||
Generated_Code/
 | 
			
		||||
 | 
			
		||||
# Backup & report files from converting an old project file
 | 
			
		||||
# to a newer Visual Studio version. Backup files are not needed,
 | 
			
		||||
# because we have git ;-)
 | 
			
		||||
_UpgradeReport_Files/
 | 
			
		||||
Backup*/
 | 
			
		||||
UpgradeLog*.XML
 | 
			
		||||
UpgradeLog*.htm
 | 
			
		||||
 | 
			
		||||
# SQL Server files
 | 
			
		||||
*.mdf
 | 
			
		||||
*.ldf
 | 
			
		||||
*.ndf
 | 
			
		||||
 | 
			
		||||
# Business Intelligence projects
 | 
			
		||||
*.rdl.data
 | 
			
		||||
*.bim.layout
 | 
			
		||||
*.bim_*.settings
 | 
			
		||||
 | 
			
		||||
# Microsoft Fakes
 | 
			
		||||
FakesAssemblies/
 | 
			
		||||
 | 
			
		||||
# GhostDoc plugin setting file
 | 
			
		||||
*.GhostDoc.xml
 | 
			
		||||
 | 
			
		||||
# Node.js Tools for Visual Studio
 | 
			
		||||
.ntvs_analysis.dat
 | 
			
		||||
node_modules/
 | 
			
		||||
 | 
			
		||||
# Typescript v1 declaration files
 | 
			
		||||
typings/
 | 
			
		||||
 | 
			
		||||
# Visual Studio 6 build log
 | 
			
		||||
*.plg
 | 
			
		||||
 | 
			
		||||
# Visual Studio 6 workspace options file
 | 
			
		||||
*.opt
 | 
			
		||||
 | 
			
		||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
 | 
			
		||||
*.vbw
 | 
			
		||||
 | 
			
		||||
# Visual Studio LightSwitch build output
 | 
			
		||||
**/*.HTMLClient/GeneratedArtifacts
 | 
			
		||||
**/*.DesktopClient/GeneratedArtifacts
 | 
			
		||||
**/*.DesktopClient/ModelManifest.xml
 | 
			
		||||
**/*.Server/GeneratedArtifacts
 | 
			
		||||
**/*.Server/ModelManifest.xml
 | 
			
		||||
_Pvt_Extensions
 | 
			
		||||
 | 
			
		||||
# Paket dependency manager
 | 
			
		||||
.paket/paket.exe
 | 
			
		||||
paket-files/
 | 
			
		||||
 | 
			
		||||
# FAKE - F# Make
 | 
			
		||||
.fake/
 | 
			
		||||
 | 
			
		||||
# JetBrains Rider
 | 
			
		||||
.idea/
 | 
			
		||||
*.sln.iml
 | 
			
		||||
 | 
			
		||||
# IDE - VSCode
 | 
			
		||||
.vscode/*
 | 
			
		||||
!.vscode/settings.json
 | 
			
		||||
!.vscode/tasks.json
 | 
			
		||||
!.vscode/launch.json
 | 
			
		||||
!.vscode/extensions.json
 | 
			
		||||
 | 
			
		||||
# CodeRush
 | 
			
		||||
.cr/
 | 
			
		||||
 | 
			
		||||
# Python Tools for Visual Studio (PTVS)
 | 
			
		||||
__pycache__/
 | 
			
		||||
*.pyc
 | 
			
		||||
 | 
			
		||||
# Cake - Uncomment if you are using it
 | 
			
		||||
# tools/**
 | 
			
		||||
# !tools/packages.config
 | 
			
		||||
 | 
			
		||||
# Tabs Studio
 | 
			
		||||
*.tss
 | 
			
		||||
 | 
			
		||||
# Telerik's JustMock configuration file
 | 
			
		||||
*.jmconfig
 | 
			
		||||
 | 
			
		||||
# BizTalk build output
 | 
			
		||||
*.btp.cs
 | 
			
		||||
*.btm.cs
 | 
			
		||||
*.odx.cs
 | 
			
		||||
*.xsd.cs
 | 
			
		||||
 | 
			
		||||
# OpenCover UI analysis results
 | 
			
		||||
OpenCover/
 | 
			
		||||
coverage/
 | 
			
		||||
 | 
			
		||||
### macOS template
 | 
			
		||||
# General
 | 
			
		||||
.DS_Store
 | 
			
		||||
.AppleDouble
 | 
			
		||||
.LSOverride
 | 
			
		||||
 | 
			
		||||
# Icon must end with two \r
 | 
			
		||||
Icon
 | 
			
		||||
 | 
			
		||||
# Thumbnails
 | 
			
		||||
._*
 | 
			
		||||
 | 
			
		||||
# Files that might appear in the root of a volume
 | 
			
		||||
.DocumentRevisions-V100
 | 
			
		||||
.fseventsd
 | 
			
		||||
.Spotlight-V100
 | 
			
		||||
.TemporaryItems
 | 
			
		||||
.Trashes
 | 
			
		||||
.VolumeIcon.icns
 | 
			
		||||
.com.apple.timemachine.donotpresent
 | 
			
		||||
 | 
			
		||||
# Directories potentially created on remote AFP share
 | 
			
		||||
.AppleDB
 | 
			
		||||
.AppleDesktop
 | 
			
		||||
Network Trash Folder
 | 
			
		||||
Temporary Items
 | 
			
		||||
.apdisk
 | 
			
		||||
 | 
			
		||||
=======
 | 
			
		||||
# Local
 | 
			
		||||
.env
 | 
			
		||||
dist
 | 
			
		||||
							
								
								
									
										14
									
								
								sample/01-complete-app/jest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								sample/01-complete-app/jest.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
{
 | 
			
		||||
  "moduleFileExtensions": [
 | 
			
		||||
    "ts",
 | 
			
		||||
    "tsx",
 | 
			
		||||
    "js",
 | 
			
		||||
    "json"
 | 
			
		||||
  ],
 | 
			
		||||
  "transform": {
 | 
			
		||||
    "^.+\\.tsx?$": "ts-jest"
 | 
			
		||||
  },
 | 
			
		||||
  "testRegex": "/src/.*\\.(test|spec).(ts|tsx|js)$",
 | 
			
		||||
  "collectCoverageFrom" : ["src/**/*.{js,jsx,tsx,ts}", "!**/node_modules/**", "!**/vendor/**"],
 | 
			
		||||
  "coverageReporters": ["json", "lcov"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15862
									
								
								sample/01-complete-app/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										15862
									
								
								sample/01-complete-app/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										71
									
								
								sample/01-complete-app/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								sample/01-complete-app/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "nest-typescript-starter",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "Nest TypeScript starter repository",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "prebuild": "rimraf dist",
 | 
			
		||||
    "build": "nest build",
 | 
			
		||||
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
 | 
			
		||||
    "start": "nest start",
 | 
			
		||||
    "start:dev": "nest start --watch",
 | 
			
		||||
    "start:debug": "nest start --debug --watch",
 | 
			
		||||
    "start:prod": "node dist/main",
 | 
			
		||||
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
 | 
			
		||||
    "test": "jest",
 | 
			
		||||
    "test:watch": "jest --watch",
 | 
			
		||||
    "test:cov": "jest --coverage",
 | 
			
		||||
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
 | 
			
		||||
    "test:e2e": "jest --config ./test/jest-e2e.json"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@nestjs/common": "8.0.9",
 | 
			
		||||
    "@nestjs/core": "8.0.9",
 | 
			
		||||
    "@nestjs/platform-express": "8.0.9",
 | 
			
		||||
    "dotenv": "10.0.0",
 | 
			
		||||
    "nestjs-telegraf": "2.4.0",
 | 
			
		||||
    "reflect-metadata": "0.1.13",
 | 
			
		||||
    "rimraf": "3.0.2",
 | 
			
		||||
    "telegraf": "4.4.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@nestjs/cli": "8.2.8",
 | 
			
		||||
    "@nestjs/schematics": "8.0.5",
 | 
			
		||||
    "@nestjs/testing": "8.0.9",
 | 
			
		||||
    "@types/express": "4.17.13",
 | 
			
		||||
    "@types/jest": "27.4.0",
 | 
			
		||||
    "@types/node": "16.11.22",
 | 
			
		||||
    "@types/supertest": "2.0.11",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "5.11.0",
 | 
			
		||||
    "@typescript-eslint/parser": "5.11.0",
 | 
			
		||||
    "eslint": "8.8.0",
 | 
			
		||||
    "eslint-config-prettier": "8.3.0",
 | 
			
		||||
    "eslint-plugin-prettier": "4.0.0",
 | 
			
		||||
    "jest": "27.5.1",
 | 
			
		||||
    "prettier": "2.5.1",
 | 
			
		||||
    "supertest": "6.2.2",
 | 
			
		||||
    "ts-jest": "27.1.3",
 | 
			
		||||
    "ts-loader": "9.2.6",
 | 
			
		||||
    "ts-node": "10.5.0",
 | 
			
		||||
    "tsconfig-paths": "3.12.0",
 | 
			
		||||
    "typescript": "4.4.4"
 | 
			
		||||
  },
 | 
			
		||||
  "jest": {
 | 
			
		||||
    "moduleFileExtensions": [
 | 
			
		||||
      "js",
 | 
			
		||||
      "json",
 | 
			
		||||
      "ts"
 | 
			
		||||
    ],
 | 
			
		||||
    "rootDir": "src",
 | 
			
		||||
    "testRegex": ".*\\.spec\\.ts$",
 | 
			
		||||
    "transform": {
 | 
			
		||||
      "^.+\\.(t|j)s$": "ts-jest"
 | 
			
		||||
    },
 | 
			
		||||
    "collectCoverageFrom": [
 | 
			
		||||
      "**/*.(t|j)s"
 | 
			
		||||
    ],
 | 
			
		||||
    "coverageDirectory": "../coverage",
 | 
			
		||||
    "testEnvironment": "node"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								sample/01-complete-app/src/app.constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								sample/01-complete-app/src/app.constants.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export const HELLO_SCENE_ID = 'HELLO_SCENE_ID';
 | 
			
		||||
 | 
			
		||||
export const GreeterBotName = 'greeter';
 | 
			
		||||
							
								
								
									
										26
									
								
								sample/01-complete-app/src/app.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sample/01-complete-app/src/app.module.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { TelegrafModule } from 'nestjs-telegraf';
 | 
			
		||||
import { EchoModule } from './echo/echo.module';
 | 
			
		||||
import { GreeterModule } from './greeter/greeter.module';
 | 
			
		||||
import { sessionMiddleware } from './middleware/session.middleware';
 | 
			
		||||
import { GreeterBotName } from './app.constants';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  imports: [
 | 
			
		||||
    TelegrafModule.forRoot({
 | 
			
		||||
      token: process.env.ECHO_BOT_TOKEN,
 | 
			
		||||
      include: [EchoModule],
 | 
			
		||||
    }),
 | 
			
		||||
    TelegrafModule.forRootAsync({
 | 
			
		||||
      botName: GreeterBotName,
 | 
			
		||||
      useFactory: () => ({
 | 
			
		||||
        token: process.env.GREETER_BOT_TOKEN,
 | 
			
		||||
        middlewares: [sessionMiddleware],
 | 
			
		||||
        include: [GreeterModule],
 | 
			
		||||
      }),
 | 
			
		||||
    }),
 | 
			
		||||
    EchoModule,
 | 
			
		||||
    GreeterModule,
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class AppModule {}
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
 | 
			
		||||
import { TelegrafExecutionContext } from 'nestjs-telegraf';
 | 
			
		||||
 | 
			
		||||
export const UpdateType = createParamDecorator(
 | 
			
		||||
  (_, ctx: ExecutionContext) =>
 | 
			
		||||
    TelegrafExecutionContext.create(ctx).getContext().updateType,
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
 | 
			
		||||
import { TelegrafArgumentsHost } from 'nestjs-telegraf';
 | 
			
		||||
import { Context } from '../../interfaces/context.interface';
 | 
			
		||||
 | 
			
		||||
@Catch()
 | 
			
		||||
export class TelegrafExceptionFilter implements ExceptionFilter {
 | 
			
		||||
  async catch(exception: Error, host: ArgumentsHost): Promise<void> {
 | 
			
		||||
    const telegrafHost = TelegrafArgumentsHost.create(host);
 | 
			
		||||
    const ctx = telegrafHost.getContext<Context>();
 | 
			
		||||
 | 
			
		||||
    await ctx.replyWithHTML(`<b>Error</b>: ${exception.message}`);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								sample/01-complete-app/src/common/guards/admin.guard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sample/01-complete-app/src/common/guards/admin.guard.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
 | 
			
		||||
import { TelegrafExecutionContext, TelegrafException } from 'nestjs-telegraf';
 | 
			
		||||
import { Context } from '../../interfaces/context.interface';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AdminGuard implements CanActivate {
 | 
			
		||||
  private readonly ADMIN_IDS = [];
 | 
			
		||||
 | 
			
		||||
  canActivate(context: ExecutionContext): boolean {
 | 
			
		||||
    const ctx = TelegrafExecutionContext.create(context);
 | 
			
		||||
    const { from } = ctx.getContext<Context>();
 | 
			
		||||
 | 
			
		||||
    const isAdmin = this.ADMIN_IDS.includes(from.id);
 | 
			
		||||
    if (!isAdmin) {
 | 
			
		||||
      throw new TelegrafException('You are not admin 😡');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
import {
 | 
			
		||||
  CallHandler,
 | 
			
		||||
  ExecutionContext,
 | 
			
		||||
  Injectable,
 | 
			
		||||
  NestInterceptor,
 | 
			
		||||
} from '@nestjs/common';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { tap } from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class ResponseTimeInterceptor implements NestInterceptor {
 | 
			
		||||
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
 | 
			
		||||
    console.log('Before...');
 | 
			
		||||
 | 
			
		||||
    const start = Date.now();
 | 
			
		||||
    return next
 | 
			
		||||
      .handle()
 | 
			
		||||
      .pipe(tap(() => console.log(`Response time: ${Date.now() - start}ms`)));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
import { Injectable, PipeTransform } from '@nestjs/common';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class ReverseTextPipe implements PipeTransform {
 | 
			
		||||
  transform(value: string): string {
 | 
			
		||||
    return value.split('').reverse().join('');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								sample/01-complete-app/src/echo/echo.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								sample/01-complete-app/src/echo/echo.module.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { EchoUpdate } from './echo.update';
 | 
			
		||||
import { EchoService } from './echo.service';
 | 
			
		||||
import { RandomNumberScene } from '../greeter/scenes/random-number.scene';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  providers: [EchoUpdate, EchoService, RandomNumberScene],
 | 
			
		||||
})
 | 
			
		||||
export class EchoModule {}
 | 
			
		||||
							
								
								
									
										8
									
								
								sample/01-complete-app/src/echo/echo.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								sample/01-complete-app/src/echo/echo.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class EchoService {
 | 
			
		||||
  echo(text: string): string {
 | 
			
		||||
    return `Echo: ${text}`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								sample/01-complete-app/src/echo/echo.update.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								sample/01-complete-app/src/echo/echo.update.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
import { UseFilters, UseGuards, UseInterceptors } from '@nestjs/common';
 | 
			
		||||
import {
 | 
			
		||||
  Help,
 | 
			
		||||
  InjectBot,
 | 
			
		||||
  On,
 | 
			
		||||
  Message,
 | 
			
		||||
  Start,
 | 
			
		||||
  Update,
 | 
			
		||||
  Command,
 | 
			
		||||
} from 'nestjs-telegraf';
 | 
			
		||||
import { Telegraf } from 'telegraf';
 | 
			
		||||
import { EchoService } from './echo.service';
 | 
			
		||||
import { GreeterBotName } from '../app.constants';
 | 
			
		||||
import { Context } from '../interfaces/context.interface';
 | 
			
		||||
import { ReverseTextPipe } from '../common/pipes/reverse-text.pipe';
 | 
			
		||||
import { ResponseTimeInterceptor } from '../common/interceptors/response-time.interceptor';
 | 
			
		||||
import { AdminGuard } from '../common/guards/admin.guard';
 | 
			
		||||
import { TelegrafExceptionFilter } from '../common/filters/telegraf-exception.filter';
 | 
			
		||||
 | 
			
		||||
@Update()
 | 
			
		||||
@UseInterceptors(ResponseTimeInterceptor)
 | 
			
		||||
@UseFilters(TelegrafExceptionFilter)
 | 
			
		||||
export class EchoUpdate {
 | 
			
		||||
  constructor(
 | 
			
		||||
    @InjectBot(GreeterBotName)
 | 
			
		||||
    private readonly bot: Telegraf<Context>,
 | 
			
		||||
    private readonly echoService: EchoService,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  @Start()
 | 
			
		||||
  async onStart(): Promise<string> {
 | 
			
		||||
    const me = await this.bot.telegram.getMe();
 | 
			
		||||
    return `Hey, I'm ${me.first_name}`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Help()
 | 
			
		||||
  async onHelp(): Promise<string> {
 | 
			
		||||
    return 'Send me any text';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Command('admin')
 | 
			
		||||
  @UseGuards(AdminGuard)
 | 
			
		||||
  onAdminCommand(): string {
 | 
			
		||||
    return 'Welcome judge';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @On('text')
 | 
			
		||||
  onMessage(
 | 
			
		||||
    @Message('text', new ReverseTextPipe()) reversedText: string,
 | 
			
		||||
  ): string {
 | 
			
		||||
    return this.echoService.echo(reversedText);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								sample/01-complete-app/src/greeter/greeter.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								sample/01-complete-app/src/greeter/greeter.module.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { Module } from '@nestjs/common';
 | 
			
		||||
import { GreeterUpdate } from './greeter.update';
 | 
			
		||||
import { RandomNumberScene } from './scenes/random-number.scene';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  providers: [GreeterUpdate, RandomNumberScene],
 | 
			
		||||
})
 | 
			
		||||
export class GreeterModule {}
 | 
			
		||||
							
								
								
									
										26
									
								
								sample/01-complete-app/src/greeter/greeter.update.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sample/01-complete-app/src/greeter/greeter.update.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
import { Command, Ctx, Hears, Start, Update, Sender } from 'nestjs-telegraf';
 | 
			
		||||
import { UpdateType as TelegrafUpdateType } from 'telegraf/typings/telegram-types';
 | 
			
		||||
import { Context } from '../interfaces/context.interface';
 | 
			
		||||
import { HELLO_SCENE_ID } from '../app.constants';
 | 
			
		||||
import { UpdateType } from '../common/decorators/update-type.decorator';
 | 
			
		||||
 | 
			
		||||
@Update()
 | 
			
		||||
export class GreeterUpdate {
 | 
			
		||||
  @Start()
 | 
			
		||||
  onStart(): string {
 | 
			
		||||
    return 'Say hello to me';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Hears(['hi', 'hello', 'hey', 'qq'])
 | 
			
		||||
  onGreetings(
 | 
			
		||||
    @UpdateType() updateType: TelegrafUpdateType,
 | 
			
		||||
    @Sender('first_name') firstName: string,
 | 
			
		||||
  ): string {
 | 
			
		||||
    return `Hey ${firstName}`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Command('scene')
 | 
			
		||||
  async onSceneCommand(@Ctx() ctx: Context): Promise<void> {
 | 
			
		||||
    await ctx.scene.enter(HELLO_SCENE_ID);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
import { Scene, SceneEnter, SceneLeave, Command } from 'nestjs-telegraf';
 | 
			
		||||
import { HELLO_SCENE_ID } from '../../app.constants';
 | 
			
		||||
import { Context } from '../../interfaces/context.interface';
 | 
			
		||||
 | 
			
		||||
@Scene(HELLO_SCENE_ID)
 | 
			
		||||
export class RandomNumberScene {
 | 
			
		||||
  @SceneEnter()
 | 
			
		||||
  onSceneEnter(): string {
 | 
			
		||||
    console.log('Enter to scene');
 | 
			
		||||
    return 'Welcome on scene ✋';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @SceneLeave()
 | 
			
		||||
  onSceneLeave(): string {
 | 
			
		||||
    console.log('Leave from scene');
 | 
			
		||||
    return 'Bye Bye 👋';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Command(['rng', 'random'])
 | 
			
		||||
  onRandomCommand(): number {
 | 
			
		||||
    console.log('Use "random" command');
 | 
			
		||||
    return Math.floor(Math.random() * 11);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Command('leave')
 | 
			
		||||
  async onLeaveCommand(ctx: Context): Promise<void> {
 | 
			
		||||
    await ctx.scene.leave();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
import { Scenes } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
 | 
			
		||||
export interface Context extends Scenes.SceneContext {}
 | 
			
		||||
							
								
								
									
										8
									
								
								sample/01-complete-app/src/main.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								sample/01-complete-app/src/main.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import 'dotenv/config';
 | 
			
		||||
import { NestFactory } from '@nestjs/core';
 | 
			
		||||
import { AppModule } from './app.module';
 | 
			
		||||
 | 
			
		||||
async function bootstrap() {
 | 
			
		||||
  await NestFactory.createApplicationContext(AppModule);
 | 
			
		||||
}
 | 
			
		||||
bootstrap();
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
import { session } from 'telegraf';
 | 
			
		||||
 | 
			
		||||
export const sessionMiddleware = session();
 | 
			
		||||
							
								
								
									
										4
									
								
								sample/01-complete-app/tsconfig.build.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								sample/01-complete-app/tsconfig.build.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "./tsconfig.json",
 | 
			
		||||
  "exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								sample/01-complete-app/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sample/01-complete-app/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "module": "commonjs",
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "removeComments": true,
 | 
			
		||||
    "emitDecoratorMetadata": true,
 | 
			
		||||
    "experimentalDecorators": true,
 | 
			
		||||
    "allowSyntheticDefaultImports": true,
 | 
			
		||||
    "target": "es2017",
 | 
			
		||||
    "sourceMap": true,
 | 
			
		||||
    "outDir": "./dist",
 | 
			
		||||
    "baseUrl": "./src",
 | 
			
		||||
    "incremental": true
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["src/**/*"]
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
export * from './on.decorator';
 | 
			
		||||
export * from './use.decorator';
 | 
			
		||||
export * from './command.decorator';
 | 
			
		||||
export * from './game-query.decorator';
 | 
			
		||||
export * from './hears.decorator';
 | 
			
		||||
export * from './inline-query.decorator';
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import { Reflector } from '@nestjs/core';
 | 
			
		||||
import { LISTENERS_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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getListenerMetadata(target: Function): ListenerMetadata[] | undefined {
 | 
			
		||||
    return this.reflector.get(LISTENERS_METADATA, target);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
import { Bot } from 'grammy';
 | 
			
		||||
import { TelegrafModuleOptions } from '../interfaces';
 | 
			
		||||
 | 
			
		||||
export async function createBotFactory(
 | 
			
		||||
  options: TelegrafModuleOptions,
 | 
			
		||||
): Promise<Bot> {
 | 
			
		||||
  const bot = new Bot(options.token, options.config);
 | 
			
		||||
 | 
			
		||||
  bot.use(...(options.middlewares ?? []));
 | 
			
		||||
 | 
			
		||||
  if (options.pollingOptions !== false) {
 | 
			
		||||
    bot.start(options.pollingOptions);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return bot;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "../../tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "outDir": "../../dist/libs/grammy"
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["src/**/*"],
 | 
			
		||||
  "exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user