chore(release): v1.0.0-alpha.1 (#39)

This commit is contained in:
Aleksandr Bukhalo 2020-03-19 22:08:12 +03:00 committed by GitHub
commit 29e489f619
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 987 additions and 601 deletions

View File

@ -1,5 +1,4 @@
{ {
"trailingComma": "es5", "trailingComma": "all",
"singleQuote": true, "singleQuote": true
"semi": false
} }

245
README.md
View File

@ -27,213 +27,126 @@
## Installation ## Installation
```bash ```bash
$ npm i nestjs-telegraf telegraf $ npm i nestjs-telegraf
``` ```
## Usage Once the installation process is complete, we can import the TelegrafModule into the root AppModule.
### An example of package usage
```typescript ```typescript
/* bot.module.ts */ /* app.module.ts */
import { Module, OnModuleInit, Logger } from '@nestjs/common' import { Module } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core' import { TelegrafModule } from 'nestjs-telegraf';
import { ConfigModule } from '@nestjs/config'
import { TelegrafModule, TelegrafService } from 'nestjs-telegraf'
import botConfig from './bot.config'
import { TelegrafConfigService } from './telegraf-config.service'
import { BotService } from './bot.service'
@Module({ @Module({
imports: [ imports: [
TelegrafModule.fromFactory({ TelegrafModule.forRoot({
imports: [ConfigModule.forFeature(botConfig)], token: 'TELEGRAM_BOT_TOKEN',
useClass: TelegrafConfigService, })
}),
], ],
exports: [TelegrafModule],
providers: [BotService],
}) })
export class BotModule implements OnModuleInit { export class AppModule {}
constructor(
private readonly moduleRef: ModuleRef,
private readonly telegrafService: TelegrafService
) {}
onModuleInit() {
this.telegrafService.init(this.moduleRef)
this.telegrafService.startPolling()
}
}
``` ```
```typescript The `forRoot()` method accepts the same configuration object as Telegraf class constructor from the Telegraf package, as described [here](https://telegraf.js.org/#/?id=constructor).
/* telegraf-config.service.ts */
import { Injectable } from '@nestjs/common' ## Telegraf methods
import { TelegrafOptionsFactory, TelegrafModuleOptions } from 'nestjs-telegraf'
import { ConfigService } from '@nestjs/config' Each Telegraf instance method described [here](https://telegraf.js.org/#/?id=telegraf) has own decorator in `nestjs-telegraf` package. The name of the decorator corresponds to the name of the Telegraf method and starts with `Telegraf`. For example [`@TelegrafHears`](https://telegraf.js.org/#/?id=hears), [`@TelegrafOn`](https://telegraf.js.org/#/?id=on), [`@TelegrafAction`](https://telegraf.js.org/#/?id=action) and so on.
Now let's try to repeat the example from the Telegraf [documentation page](https://telegraf.js.org/#/?id=example).
```typescript
/* app.service.ts */
import { Injectable } from '@nestjs/common';
import {
TelegrafStart,
TelegrafHelp,
TelegrafOn,
TelegrafHears,
ContextMessageUpdate,
} from 'nestjs-telegraf';
@Injectable() @Injectable()
export class TelegrafConfigService implements TelegrafOptionsFactory { export class AppService {
constructor(private readonly configService: ConfigService) {} @TelegrafStart()
start(ctx: ContextMessageUpdate) {
ctx.reply('Welcome');
}
createTelegrafOptions(): TelegrafModuleOptions { @TelegrafHelp()
return { help(ctx: ContextMessageUpdate) {
token: this.configService.get('bot.token'), ctx.reply('Send me a sticker');
} }
@TelegrafOn('sticker')
on(ctx: ContextMessageUpdate) {
ctx.reply('👍');
}
@TelegrafHears('hi')
hears(ctx: ContextMessageUpdate) {
ctx.reply('Hey there');
} }
} }
``` ```
```typescript ## Async configuration
/* bot.config.ts */ When you need to pass module options asynchronously instead of statically, use the forRootAsync() method. As with most dynamic modules, Nest provides several techniques to deal with async configuration.
import { registerAs } from '@nestjs/config' One technique is to use a factory function:
interface Config {
token: string
}
export default registerAs(
'bot',
(): Config => ({
token: process.env.TELEGRAM_BOT_TOKEN,
})
)
```
### Telegraf
#### Telegraf methods usage
You can decorate any `Telegraf` method with `@TelegramActionHandler` decorator.
```typescript ```typescript
/* bot.service.ts */ TelegrafModule.forRootAsync({
useFactory: () => ({
import { Injectable } from '@nestjs/common' token: 'TELEGRAM_BOT_TOKEN',
import { TelegrafTelegramService } from 'nestjs-telegraf'
import { ContextMessageUpdate } from 'telegraf'
@Injectable()
export class BotService {
/* This decorator handle /start command */
@TelegramActionHandler({ onStart: true })
async onStart(ctx: ContextMessageUpdate) {
await ctx.reply('/start command reply')
}
}
```
##### Today available actions for decorator:
- [`onStart`](https://telegraf.js.org/#/?id=start) Handler for /start command.
- [`command`](https://telegraf.js.org/#/?id=command) Command handling.
- [`message`](https://telegraf.js.org/#/?id=hears) Registers middleware for handling text messages.
- [`action`](https://telegraf.js.org/#/?id=action) Registers middleware for handling `callback_data` actions with regular expressions.
#### Telegraf middlewares usage
See https://github.com/bukhalo/nestjs-telegraf/issues/7#issuecomment-577582322
#### Telegraf proxy usage
```typescript
/* bot.config.ts */
import { registerAs } from '@nestjs/config'
interface Config {
token: string
socksHost: string
socksPort: string | number
socksUser: string
socksPassword: string
}
export default registerAs(
'bot',
(): Config => ({
token: process.env.TELEGRAM_BOT_TOKEN,
socksHost: process.env.TELEGRAM_BOT_SOCKS_HOST,
socksPort: process.env.TELEGRAM_BOT_SOCKS_PORT,
socksUser: process.env.TELEGRAM_BOT_SOCKS_USER,
socksPassword: process.env.TELEGRAM_BOT_SOCKS_PASS,
}), }),
); });
``` ```
Like other [factory providers](https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory), our factory function can be async and can inject dependencies through inject.
```typescript ```typescript
TelegrafModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
token: configService.getString('TELEGRAM_BOT_TOKEN'),
}),
inject: [ConfigService],
});
```
/* telegraf-config.service.ts */ Alternatively, you can configure the TelegrafModule using a class instead of a factory, as shown below:
import { Injectable } from '@nestjs/common' ```typescript
import { ConfigService } from '@nestjs/config' TelegrafModule.forRootAsync({
import { TelegrafModuleOptions, TelegrafOptionsFactory } from 'nestjs-telegraf' useClass: TelegrafConfigService,
import { SocksProxyAgent } from 'socks-proxy-agent' });
```
The construction above instantiates `TelegrafConfigService` inside `TelegrafModule`, using it to create the required options object. Note that in this example, the `TelegrafConfigService` has to implement the `TelegrafOptionsFactory` interface, as shown below. The `TelegrafModule` will call the `createTelegrafOptions()` method on the instantiated object of the supplied class.
```typescript
@Injectable() @Injectable()
export class TelegrafConfigService implements TelegrafOptionsFactory { class TelegrafConfigService implements TelegrafOptionsFactory {
private agent createMongooseOptions(): TelegrafModuleOptions {
constructor(private readonly configService: ConfigService) {}
createTelegrafOptions(): TelegrafModuleOptions {
const proxyConfig = {
host: this.configService.get('bot.socksHost'),
port: this.configService.get('bot.socksPort'),
userId: this.configService.get('bot.socksUser'),
password: this.configService.get('bot.socksPassword'),
}
this.agent = new SocksProxyAgent(proxyConfig)
return { return {
token: this.configService.get('bot.token'), token: 'TELEGRAM_BOT_TOKEN',
telegrafOptions: { telegram: { agent: this.agent } },
}; };
} }
} }
``` ```
### Telegram If you want to reuse an existing options provider instead of creating a private copy inside the `TelegrafModule`, use the `useExisting` syntax.
#### Telegram methods usage
Inject `TelegrafTelegramService` from `nestjs-telegraf` package for use [Telegram instance](https://telegraf.js.org/#/?id=telegram) from `telegraf` package.
```typescript ```typescript
/* bot.service.ts */ TelegrafModule.forRootAsync({
imports: [ConfigModule],
import { Injectable } from '@nestjs/common' useExisting: ConfigService,
import { TelegrafTelegramService, TelegramActionHandler } from 'nestjs-telegraf' });
import { ContextMessageUpdate } from 'telegraf'
@Injectable()
export class BotService {
constructor(
private readonly telegrafTelegramService: TelegrafTelegramService
) {}
@TelegramActionHandler({ onStart: true })
async start(ctx: ContextMessageUpdate) {
const me = await this.telegrafTelegramService.getMe()
console.log(me)
}
}
``` ```
## Examples
You can see the basic use of the package in this repository:
https://github.com/bukhalo/nestjs-telegraf-sample
## Support ## Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).

View File

@ -1,3 +1,15 @@
export * from './pipe-context.decorator' export * from './telegraf-use.decorator';
export * from './telegram-action-handler.decorator' export * from './telegraf-on.decorator';
export * from './telegram-catch.decorator' export * from './telegraf-hears.decorator';
export * from './telegraf-command.decorator';
export * from './telegraf-start.decorator';
export * from './telegraf-help.decorator';
export * from './telegraf-settings.decorator';
export * from './telegraf-entity.decorator';
export * from './telegraf-mention.decorator';
export * from './telegraf-phone.decorator';
export * from './telegraf-hashtag.decorator';
export * from './telegraf-cashtag.decorator';
export * from './telegraf-action.decorator';
export * from './telegraf-inline-query.decorator';
export * from './telegraf-game-query.decorator';

View File

@ -1,18 +0,0 @@
import { Type } from '@nestjs/common'
import { ContextTransformer } from '../interfaces'
import { addHandlerToStore } from './'
export const PipeContext = <T>(transform: Type<ContextTransformer<T>>) => (
target: Object,
propertyKey: string,
parameterIndex: number,
) => {
addHandlerToStore(target, propertyKey, {
transformations: [
{
index: parameterIndex,
transform,
},
],
})
}

View File

@ -0,0 +1,21 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import { HearsTriggers } from 'telegraf';
export type TelegrafActionTriggers = HearsTriggers;
export interface TelegrafActionMetadata {
triggers: TelegrafActionTriggers;
}
/**
* Registers middleware for handling callback_data actions with regular expressions.
* @param triggers Triggers
*
* https://telegraf.js.org/#/?id=action
*/
export function TelegrafAction(
triggers: TelegrafActionTriggers,
): MethodDecorator {
return SetMetadata(DECORATORS.ACTION, { triggers });
}

View File

@ -0,0 +1,20 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafCashtagCashtag = string | string[];
export interface TelegrafCashtagMetadata {
cashtag: TelegrafCashtagCashtag;
}
/**
* Cashtag handling.
* @param cashtag Cashtag
*
* https://telegraf.js.org/#/?id=cashtag
*/
export function TelegrafCashtag(
cashtag: TelegrafCashtagCashtag,
): MethodDecorator {
return SetMetadata(DECORATORS.CASHTAG, { cashtag });
}

View File

@ -0,0 +1,20 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafCommandCommands = string | string[];
export interface TelegrafCommandMetadata {
commands: TelegrafCommandCommands;
}
/**
* Command handling.
* @param commands Commands
*
* https://telegraf.js.org/#/?id=command
*/
export function TelegrafCommand(
commands: TelegrafCommandCommands,
): MethodDecorator {
return SetMetadata(DECORATORS.COMMAND, { commands });
}

View File

@ -0,0 +1,23 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafEntityEntity =
| string
| string[]
| RegExp
| RegExp[]
| Function;
export interface TelegrafEntityMetadata {
entity: TelegrafEntityEntity;
}
/**
* Entity handling.
* @param entity Entity name
*
* https://telegraf.js.org/#/?id=entity
*/
export function TelegrafEntity(entity: TelegrafEntityEntity): MethodDecorator {
return SetMetadata(DECORATORS.ENTITY, { entity });
}

View File

@ -0,0 +1,11 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Registers middleware for handling callback_data actions with game query.
*
* https://telegraf.js.org/#/?id=inlinequery
*/
export function TelegrafGameQuery(): MethodDecorator {
return SetMetadata(DECORATORS.GAME_QUERY, {});
}

View File

@ -0,0 +1,20 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafHashtagHashtag = string | string[];
export interface TelegrafHashtagMetadata {
hashtag: TelegrafHashtagHashtag;
}
/**
* Hashtag handling.
* @param hashtag Hashtag
*
* https://telegraf.js.org/#/?id=hashtag
*/
export function TelegrafHashtag(
hashtag: TelegrafHashtagHashtag,
): MethodDecorator {
return SetMetadata(DECORATORS.HASHTAG, { hashtag });
}

View File

@ -0,0 +1,21 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
import { HearsTriggers } from 'telegraf';
export type TelegrafHearsTriggers = HearsTriggers;
export interface TelegrafHearsMetadata {
triggers: TelegrafHearsTriggers;
}
/**
* Registers middleware for handling text messages.
* @param triggers Triggers
*
* https://telegraf.js.org/#/?id=hears
*/
export function TelegrafHears(
triggers: TelegrafHearsTriggers,
): MethodDecorator {
return SetMetadata(DECORATORS.HEARS, { triggers: triggers });
}

View File

@ -0,0 +1,11 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Handler for /help command.
*
* https://telegraf.js.org/#/?id=help
*/
export function TelegrafHelp(): MethodDecorator {
return SetMetadata(DECORATORS.HELP, {});
}

View File

@ -0,0 +1,20 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafInlineQueryTriggers = string | string[] | RegExp | RegExp[];
export interface TelegrafInlineQueryMetadata {
triggers: TelegrafInlineQueryTriggers;
}
/**
* Registers middleware for handling inline_query actions with regular expressions.
* @param triggers Triggers
*
* https://telegraf.js.org/#/?id=inlinequery
*/
export function TelegrafInlineQuery(
triggers: TelegrafInlineQueryTriggers,
): MethodDecorator {
return SetMetadata(DECORATORS.INLINE_QUERY, { triggers });
}

View File

@ -0,0 +1,20 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafMentionUsername = string | string[];
export interface TelegrafMentionMetadata {
username: TelegrafMentionUsername;
}
/**
* Mention handling.
* @param username Username
*
* https://telegraf.js.org/#/?id=mention
*/
export function TelegrafMention(
username: TelegrafMentionUsername,
): MethodDecorator {
return SetMetadata(DECORATORS.MENTION, { username });
}

View File

@ -0,0 +1,25 @@
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 TelegrafOnMetadata {
updateTypes: TelegrafOnUpdateTypes;
}
/**
* Registers middleware for provided update type.
* @param updateTypes Update type
*
* https://telegraf.js.org/#/?id=on
*/
export function TelegrafOn(
updateTypes: TelegrafOnUpdateTypes,
): MethodDecorator {
return SetMetadata(DECORATORS.ON, { updateTypes: updateTypes });
}

View File

@ -0,0 +1,18 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
export type TelegrafPhonePhone = string | string[];
export interface TelegrafPhoneMetadata {
phone: TelegrafPhonePhone;
}
/**
* Phone number handling.
* @param phone Phone number
*
* https://telegraf.js.org/#/?id=phone
*/
export function TelegrafPhone(phone: TelegrafPhonePhone): MethodDecorator {
return SetMetadata(DECORATORS.PHONE, { phone });
}

View File

@ -0,0 +1,11 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Handler for /settings command.
*
* https://telegraf.js.org/#/?id=settings
*/
export function TelegrafSettings(): MethodDecorator {
return SetMetadata(DECORATORS.SETTINGS, {});
}

View File

@ -0,0 +1,11 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Handler for /start command.
*
* https://telegraf.js.org/#/?id=start
*/
export function TelegrafStart(): MethodDecorator {
return SetMetadata(DECORATORS.START, {});
}

View File

@ -0,0 +1,11 @@
import { SetMetadata } from '@nestjs/common';
import { DECORATORS } from '../telegraf.constants';
/**
* Registers a middleware.
*
* https://telegraf.js.org/#/?id=use
*/
export function TelegrafUse(): MethodDecorator {
return SetMetadata(DECORATORS.USE, {});
}

View File

@ -1,44 +0,0 @@
import { HandleParameters } from '../interfaces'
type Decorator = (
params: HandleParameters,
) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void
type HandlerDecorator = Decorator & {
handlers?: Map<any, Map<string, HandleParameters>>
}
export const TelegramActionHandler: HandlerDecorator = (
parameters: HandleParameters,
) => (target: any, propertyKey: string) => {
// eslint-disable-next-line no-use-before-define
addHandlerToStore(target, propertyKey, parameters)
}
export const addHandlerToStore = (
instance: Object,
name: string,
config: HandleParameters,
) => {
const handlerClass = instance.constructor
if (!TelegramActionHandler.handlers) {
TelegramActionHandler.handlers = new Map()
}
if (!TelegramActionHandler.handlers.get(handlerClass)) {
TelegramActionHandler.handlers.set(handlerClass, new Map())
}
const oldParameters =
TelegramActionHandler.handlers.get(handlerClass).get(name) || {}
TelegramActionHandler.handlers.get(handlerClass).set(name, {
...oldParameters,
...config,
transformations: [
...(oldParameters.transformations || []),
...(config.transformations || []),
],
})
}

View File

@ -1,18 +0,0 @@
import { Type } from '@nestjs/common'
import { TelegramErrorHandler } from '../interfaces'
type Decorator = (error: any) => ClassDecorator
type HandlerDecorator = Decorator & {
handlers?: Map<Error, Type<TelegramErrorHandler>>
}
export const TelegramCatch: HandlerDecorator = error => target => {
if (!TelegramCatch.handlers) {
TelegramCatch.handlers = new Map()
}
TelegramCatch.handlers.set(error, target as any)
return target
}

View File

@ -1 +0,0 @@
export * from './invalid-configuration.exeption'

View File

@ -1,10 +0,0 @@
export class InvalidConfigurationException extends Error {
public constructor(
public readonly invalidField,
public readonly invalidCause,
) {
super(
`Options validation failed, "${invalidField}" invalid — ${invalidCause}`,
)
}
}

View File

@ -1,5 +1,3 @@
export * from './telegraf.module' export * from './telegraf.module';
export * from './interfaces' export * from './interfaces';
export * from './decorators' export * from './decorators';
export * from './telegraf.service'
export * from './telegraf-telegram.service'

View File

@ -1,5 +0,0 @@
import { ContextMessageUpdate } from 'telegraf'
export interface ContextTransformer<T = any> {
transform: (ctx: ContextMessageUpdate) => Promise<T>
}

View File

@ -1,18 +0,0 @@
import { ContextTransformer } from './'
import { HearsTriggers } from 'telegraf'
import { UpdateType, MessageSubTypes } from 'telegraf/typings/telegram-types'
import { Type } from '@nestjs/common'
interface ArgumentTransformation {
index: number
transform: Type<ContextTransformer>
}
export interface HandleParameters {
onStart?: boolean
on?: UpdateType | UpdateType[] | MessageSubTypes | MessageSubTypes[]
command?: string
message?: string | RegExp
action?: HearsTriggers
transformations?: ArgumentTransformation[]
}

View File

@ -1,6 +0,0 @@
import { HandleParameters } from './'
export interface Handler {
handle: (...args: any[]) => Promise<void>
config: HandleParameters
}

View File

@ -1,5 +1,2 @@
export * from './telegraf-options.interface' export { ContextMessageUpdate } from 'telegraf';
export * from './handler.interface' export * from './telegraf-options.interface';
export * from './handle-parameters.interface'
export * from './telegram-error-handler.interface'
export * from './context-transformer.interface'

View File

@ -1,22 +1,21 @@
import { ModuleMetadata, Type } from '@nestjs/common/interfaces' import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
import { TelegrafOptions } from 'telegraf' import { TelegrafOptions } from 'telegraf';
export interface TelegrafModuleOptions { export interface TelegrafModuleOptions {
token: string token: string;
sitePublicUrl?: string options?: TelegrafOptions;
telegrafOptions?: TelegrafOptions
} }
export interface TelegrafOptionsFactory { export interface TelegrafOptionsFactory {
createTelegrafOptions(): TelegrafModuleOptions createTelegrafOptions(): TelegrafModuleOptions;
} }
export interface TelegrafModuleAsyncOptions export interface TelegrafModuleAsyncOptions
extends Pick<ModuleMetadata, 'imports'> { extends Pick<ModuleMetadata, 'imports'> {
useExisting?: Type<TelegrafOptionsFactory> useExisting?: Type<TelegrafOptionsFactory>;
useClass?: Type<TelegrafOptionsFactory> useClass?: Type<TelegrafOptionsFactory>;
useFactory?: ( useFactory?: (
...args: any[] ...args: any[]
) => Promise<TelegrafModuleOptions> | TelegrafModuleOptions ) => Promise<TelegrafModuleOptions> | TelegrafModuleOptions;
inject?: any[] inject?: any[];
} }

View File

@ -1,5 +0,0 @@
import { ContextMessageUpdate } from 'telegraf'
export interface TelegramErrorHandler<E = any> {
catch(ctx: ContextMessageUpdate, error: E): Promise<void>
}

View File

@ -0,0 +1,91 @@
import { Module, DynamicModule, Provider, Type } from '@nestjs/common';
import {
TelegrafModuleOptions,
TelegrafModuleAsyncOptions,
TelegrafOptionsFactory,
} from './interfaces';
import {
TELEGRAF_MODULE_OPTIONS,
TELEGRAF_PROVIDER,
} from './telegraf.constants';
import { TelegrafMetadataAccessor } from './telegraf-metadata.accessor';
import { TelegrafExplorer } from './telegraf.explorer';
import { DiscoveryModule } from '@nestjs/core';
import { TelegrafProvider } from './telegraf.provider';
@Module({
imports: [DiscoveryModule],
providers: [TelegrafMetadataAccessor, TelegrafExplorer],
})
export class TelegrafCoreModule {
public static forRoot(options: TelegrafModuleOptions): DynamicModule {
const telegrafProvider = {
provide: TELEGRAF_PROVIDER,
useClass: TelegrafProvider,
inject: [TELEGRAF_MODULE_OPTIONS],
};
return {
module: TelegrafCoreModule,
providers: [
{ provide: TELEGRAF_MODULE_OPTIONS, useValue: options },
telegrafProvider,
],
exports: [telegrafProvider],
};
}
public static forRootAsync(
options: TelegrafModuleAsyncOptions,
): DynamicModule {
const telegrafProvider = {
provide: TELEGRAF_PROVIDER,
useClass: TelegrafProvider,
inject: [TELEGRAF_MODULE_OPTIONS],
};
const asyncProviders = this.createAsyncProviders(options);
return {
module: TelegrafCoreModule,
imports: options.imports,
providers: [...asyncProviders, telegrafProvider],
exports: [telegrafProvider],
};
}
private static createAsyncProviders(
options: TelegrafModuleAsyncOptions,
): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}
const useClass = options.useClass as Type<TelegrafOptionsFactory>;
return [
this.createAsyncOptionsProvider(options),
{
provide: useClass,
useClass,
},
];
}
private static createAsyncOptionsProvider(
options: TelegrafModuleAsyncOptions,
): Provider {
if (options.useFactory) {
return {
provide: TELEGRAF_MODULE_OPTIONS,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
// `as Type<TelegrafOptionsFactory>` is a workaround for microsoft/TypeScript#31603
const inject = [
(options.useClass || options.useExisting) as Type<TelegrafOptionsFactory>,
];
return {
provide: TELEGRAF_MODULE_OPTIONS,
useFactory: async (optionsFactory: TelegrafOptionsFactory) =>
await optionsFactory.createTelegrafOptions(),
inject,
};
}
}

View File

@ -0,0 +1,186 @@
import { Injectable, Type } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import {
TelegrafActionMetadata,
TelegrafCashtagMetadata,
TelegrafCommandMetadata,
TelegrafEntityMetadata,
TelegrafHashtagMetadata,
TelegrafHearsMetadata,
TelegrafInlineQueryMetadata,
TelegrafMentionMetadata,
TelegrafOnMetadata,
TelegrafPhoneMetadata,
TelegrafStart,
} from './decorators';
import { DECORATORS } from './telegraf.constants';
@Injectable()
export class TelegrafMetadataAccessor {
constructor(private readonly reflector: Reflector) {}
isTelegrafUse(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.USE, target);
}
isTelegrafOn(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.ON, target);
}
getTelegrafOnMetadata(
target: Type<any> | Function,
): TelegrafOnMetadata | undefined {
return this.reflector.get(DECORATORS.ON, target);
}
isTelegrafHears(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.HEARS, target);
}
getTelegrafHearsMetadata(
target: Type<any> | Function,
): TelegrafHearsMetadata | undefined {
return this.reflector.get(DECORATORS.HEARS, target);
}
isTelegrafCommand(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.COMMAND, target);
}
getTelegrafCommandMetadata(
target: Type<any> | Function,
): TelegrafCommandMetadata | undefined {
return this.reflector.get(DECORATORS.COMMAND, target);
}
isTelegrafStart(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.START, target);
}
isTelegrafHelp(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.HELP, target);
}
isTelegrafSettings(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.SETTINGS, target);
}
isTelegrafEntity(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.ENTITY, target);
}
getTelegrafEntityMetadata(
target: Type<any> | Function,
): TelegrafEntityMetadata | undefined {
return this.reflector.get(DECORATORS.ENTITY, target);
}
isTelegrafMention(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.MENTION, target);
}
getTelegrafMentionMetadata(
target: Type<any> | Function,
): TelegrafMentionMetadata | undefined {
return this.reflector.get(DECORATORS.MENTION, target);
}
isTelegrafPhone(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.PHONE, target);
}
getTelegrafPhoneMetadata(
target: Type<any> | Function,
): TelegrafPhoneMetadata | undefined {
return this.reflector.get(DECORATORS.PHONE, target);
}
isTelegrafHashtag(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.HASHTAG, target);
}
getTelegrafHashtagMetadata(
target: Type<any> | Function,
): TelegrafHashtagMetadata | undefined {
return this.reflector.get(DECORATORS.HASHTAG, target);
}
isTelegrafCashtag(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.CASHTAG, target);
}
getTelegrafCashtagMetadata(
target: Type<any> | Function,
): TelegrafCashtagMetadata | undefined {
return this.reflector.get(DECORATORS.CASHTAG, target);
}
isTelegrafAction(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.ACTION, target);
}
getTelegrafActionMetadata(
target: Type<any> | Function,
): TelegrafActionMetadata | undefined {
return this.reflector.get(DECORATORS.ACTION, target);
}
isTelegrafInlineQuery(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.INLINE_QUERY, target);
}
getTelegrafInlineQueryMetadata(
target: Type<any> | Function,
): TelegrafInlineQueryMetadata | undefined {
return this.reflector.get(DECORATORS.INLINE_QUERY, target);
}
isTelegrafGameQuery(target: Type<any> | Function): boolean {
if (!target) {
return false;
}
return !!this.reflector.get(DECORATORS.GAME_QUERY, target);
}
}

View File

@ -1,13 +0,0 @@
import { Injectable, Inject } from '@nestjs/common';
const Telegram = require('telegraf/telegram');
import { Telegram as TelegramClient } from 'telegraf';
import { TELEGRAF_MODULE_OPTIONS } from './telegraf.constants';
import { TelegrafModuleOptions } from './interfaces';
@Injectable()
export class TelegrafTelegramService extends TelegramClient {
constructor(@Inject(TELEGRAF_MODULE_OPTIONS) options: TelegrafModuleOptions) {
super(options.token, {});
}
}

View File

@ -1,2 +1,21 @@
export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS' export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
export const TokenInjectionToken = Symbol('TokenInjectionToken') export const TELEGRAF_PROVIDER = 'TELEGRAF_PROVIDER';
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`,
};

258
lib/telegraf.explorer.ts Normal file
View File

@ -0,0 +1,258 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { DiscoveryService, ModuleRef } from '@nestjs/core';
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import Telegraf from 'telegraf';
import { TelegrafMetadataAccessor } from './telegraf-metadata.accessor';
import { TelegrafProvider } from './telegraf.provider';
import { TELEGRAF_PROVIDER } from './telegraf.constants';
import { ContextMessageUpdate } from 'telegraf';
import {
TelegrafActionMetadata,
TelegrafCashtagMetadata,
TelegrafCommandMetadata,
TelegrafEntityMetadata,
TelegrafHashtagMetadata,
TelegrafHearsMetadata,
TelegrafInlineQueryMetadata,
TelegrafMentionMetadata,
TelegrafOnMetadata,
TelegrafPhoneMetadata,
} from './decorators';
@Injectable()
export class TelegrafExplorer implements OnModuleInit {
constructor(
private readonly moduleRef: ModuleRef,
private readonly discoveryService: DiscoveryService,
private readonly metadataAccessor: TelegrafMetadataAccessor,
private readonly metadataScanner: MetadataScanner,
) {}
onModuleInit() {
this.explore();
}
explore() {
const providers: InstanceWrapper[] = this.discoveryService.getProviders();
providers.forEach((wrapper: InstanceWrapper) => {
const { instance } = wrapper;
if (!instance) {
return;
}
const telegraf = this.moduleRef.get<TelegrafProvider<any>>(
TELEGRAF_PROVIDER,
{ strict: false },
);
this.metadataScanner.scanFromPrototype(
instance,
Object.getPrototypeOf(instance),
(key: string) => {
if (this.metadataAccessor.isTelegrafUse(instance[key])) {
this.handleTelegrafUse(instance, key, telegraf);
} else if (this.metadataAccessor.isTelegrafOn(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafOnMetadata(
instance[key],
);
this.handleTelegrafOn(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafHears(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafHearsMetadata(
instance[key],
);
this.handleTelegrafHears(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafCommand(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafCommandMetadata(
instance[key],
);
this.handleTelegrafCommand(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafStart(instance[key])) {
this.handleTelegrafStart(instance, key, telegraf);
} else if (this.metadataAccessor.isTelegrafHelp(instance[key])) {
this.handleTelegrafHelp(instance, key, telegraf);
} else if (this.metadataAccessor.isTelegrafSettings(instance[key])) {
this.handleTelegrafSettings(instance, key, telegraf);
} else if (this.metadataAccessor.isTelegrafEntity(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafEntityMetadata(
instance[key],
);
this.handleTelegrafEntity(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafMention(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafMentionMetadata(
instance[key],
);
this.handleTelegrafMention(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafPhone(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafPhoneMetadata(
instance[key],
);
this.handleTelegrafPhone(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafHashtag(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafHashtagMetadata(
instance[key],
);
this.handleTelegrafHashtag(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafCashtag(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafCashtagMetadata(
instance[key],
);
this.handleTelegrafCashtag(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafAction(instance[key])) {
const metadata = this.metadataAccessor.getTelegrafActionMetadata(
instance[key],
);
this.handleTelegrafAction(instance, key, telegraf, metadata);
} else if (
this.metadataAccessor.isTelegrafInlineQuery(instance[key])
) {
const metadata = this.metadataAccessor.getTelegrafInlineQueryMetadata(
instance[key],
);
this.handleTelegrafInlineQuery(instance, key, telegraf, metadata);
} else if (this.metadataAccessor.isTelegrafGameQuery(instance[key])) {
this.handleTelegrafGameQuery(instance, key, telegraf);
}
},
);
});
}
handleTelegrafUse(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
) {
telegraf.use(instance[key].bind(instance));
}
handleTelegrafOn(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafOnMetadata,
) {
telegraf.on(metadata.updateTypes, instance[key].bind(instance));
}
handleTelegrafHears(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafHearsMetadata,
) {
telegraf.hears(metadata.triggers, instance[key].bind(instance));
}
handleTelegrafCommand(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafCommandMetadata,
) {
telegraf.command(metadata.commands, instance[key].bind(instance));
}
handleTelegrafStart(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
) {
telegraf.start(instance[key].bind(instance));
}
handleTelegrafHelp(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
) {
telegraf.help(instance[key].bind(instance));
}
handleTelegrafSettings(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
) {
// @ts-ignore
telegraf.settings(instance[key].bind(instance));
}
handleTelegrafEntity(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafEntityMetadata,
) {
// @ts-ignore
telegraf.entity(metadata.entity, instance[key].bind(instance));
}
handleTelegrafMention(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafMentionMetadata,
) {
// @ts-ignore
telegraf.mention(metadata.username, instance[key].bind(instance));
}
handleTelegrafPhone(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafPhoneMetadata,
) {
// @ts-ignore
telegraf.phone(metadata.phone, instance[key].bind(instance));
}
handleTelegrafHashtag(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafHashtagMetadata,
) {
// @ts-ignore
telegraf.hashtag(metadata.hashtag, instance[key].bind(instance));
}
handleTelegrafCashtag(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafCashtagMetadata,
) {
// @ts-ignore
telegraf.cashtag(metadata.cashtag, instance[key].bind(instance));
}
handleTelegrafAction(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafActionMetadata,
) {
telegraf.action(metadata.triggers, instance[key].bind(instance));
}
handleTelegrafInlineQuery(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
metadata: TelegrafInlineQueryMetadata,
) {
// @ts-ignore
telegraf.inlineQuery(metadata.triggers, instance[key].bind(instance));
}
handleTelegrafGameQuery(
instance: object,
key: string,
telegraf: Telegraf<ContextMessageUpdate>,
) {
telegraf.gameQuery(instance[key].bind(instance));
}
}

View File

@ -1,63 +1,25 @@
import { Module, DynamicModule, Provider } from '@nestjs/common'; import { Module, DynamicModule } from '@nestjs/common';
import { TelegrafCoreModule } from './telegraf-core.module';
import { import {
TelegrafModuleOptions,
TelegrafModuleAsyncOptions, TelegrafModuleAsyncOptions,
TelegrafOptionsFactory
} from './interfaces'; } from './interfaces';
import {
TELEGRAF_MODULE_OPTIONS,
TokenInjectionToken
} from './telegraf.constants';
import { TelegrafService, TelegrafTelegramService } from './';
@Module({}) @Module({})
export class TelegrafModule { export class TelegrafModule {
static fromFactory(options: TelegrafModuleAsyncOptions): DynamicModule { public static forRoot(options?: TelegrafModuleOptions): DynamicModule {
return { return {
module: TelegrafModule, module: TelegrafModule,
imports: options.imports || [], imports: [TelegrafCoreModule.forRoot(options)],
providers: [
...this.createAsyncProviders(options),
TelegrafService,
TelegrafTelegramService,
{
provide: TokenInjectionToken,
useClass: options.useClass
}
],
exports: [TelegrafService, TelegrafTelegramService]
}; };
} }
private static createAsyncProviders( public static forRootAsync(
options: TelegrafModuleAsyncOptions options: TelegrafModuleAsyncOptions,
): Provider[] { ): DynamicModule {
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 { return {
provide: TELEGRAF_MODULE_OPTIONS, module: TelegrafModule,
useFactory: async (optionsFactory: TelegrafOptionsFactory) => imports: [TelegrafCoreModule.forRootAsync(options)],
await optionsFactory.createTelegrafOptions(),
inject: [options.useExisting || options.useClass]
}; };
} }
} }

33
lib/telegraf.provider.ts Normal file
View File

@ -0,0 +1,33 @@
import {
Injectable,
Inject,
OnApplicationBootstrap,
Logger,
OnApplicationShutdown,
} from '@nestjs/common';
import Telegraf, { ContextMessageUpdate } from 'telegraf';
import { TELEGRAF_MODULE_OPTIONS } from './telegraf.constants';
import { TelegrafModuleOptions } from './interfaces';
@Injectable()
// @ts-ignore
export class TelegrafProvider<TContext extends ContextMessageUpdate>
extends Telegraf<TContext>
implements OnApplicationBootstrap, OnApplicationShutdown {
private logger = new Logger('Telegraf');
constructor(@Inject(TELEGRAF_MODULE_OPTIONS) options: TelegrafModuleOptions) {
super(options.token, options.options);
}
onApplicationBootstrap() {
this.catch(e => {
this.logger.error(e);
});
this.startPolling();
}
async onApplicationShutdown(signal?: string) {
await this.stop();
}
}

View File

@ -1,183 +0,0 @@
import { Inject, Injectable, Logger } from '@nestjs/common'
import { ModuleRef } from '@nestjs/core'
import { flatten, head } from 'lodash'
import Telegraf, { ContextMessageUpdate } from 'telegraf'
import { TelegramActionHandler, TelegramCatch } from './decorators'
import { InvalidConfigurationException } from './exeptions'
import {
ContextTransformer,
Handler,
TelegrafOptionsFactory,
TelegramErrorHandler,
} from './interfaces'
import { TokenInjectionToken } from './telegraf.constants'
@Injectable()
export class TelegrafService {
private readonly logger = new Logger(TelegrafService.name, true)
private readonly sitePublicUrl?: string
public readonly bot: Telegraf<ContextMessageUpdate>
private ref: ModuleRef
public constructor(
@Inject(TokenInjectionToken) options: TelegrafOptionsFactory
) {
const {
token,
sitePublicUrl,
telegrafOptions,
} = options.createTelegrafOptions()
this.sitePublicUrl = sitePublicUrl
this.bot = new Telegraf(token, telegrafOptions)
}
public init(ref: ModuleRef, devMode: boolean = false) {
this.ref = ref
const handlers = this.createHandlers()
this.setupOnStart(handlers)
this.setupOn(handlers)
this.setupOnMessage(handlers)
this.setupOnCommand(handlers)
this.setupActions(handlers)
if (devMode) {
this.startPolling()
}
}
public getMiddleware(path: string) {
if (!this.sitePublicUrl) {
throw new InvalidConfigurationException(
'sitePublicUrl',
'does not exist, but webook used'
)
}
const url = `${this.sitePublicUrl}/${path}`
this.bot.telegram
.setWebhook(url)
.then(() => this.logger.log(`Webhook set success @ ${url}`))
return this.bot.webhookCallback(`/${path}`)
}
public startPolling() {
this.bot.telegram.deleteWebhook().then(
() => this.bot.startPolling(),
() => {
// okay, never mind
}
)
}
private createHandlers(): Handler[] {
return flatten(
Array.from((TelegramActionHandler.handlers || new Map()).entries()).map(
([handlerClass, classConfig]) => {
const handlerInstance = this.ref.get(handlerClass, { strict: false })
return Array.from(classConfig.entries()).map(
([methodName, methodCondig]) => ({
handle: handlerInstance[methodName].bind(handlerInstance),
config: methodCondig,
})
)
}
)
)
}
private setupOnStart(handlers: Handler[]): void {
const onStart = handlers.filter(({ config }) => config.onStart)
if (onStart.length !== 1) {
throw new Error()
}
this.bot.start(this.adoptHandle(head(onStart)))
}
private setupOn(handlers: Handler[]): void {
const onHandlers = handlers.filter(({ config }) => config.on)
onHandlers.forEach(handler => {
this.bot.on(handler.config.on, this.adoptHandle(handler))
})
}
private setupOnMessage(handlers: Handler[]): void {
const onMessageHandlers = handlers.filter(
({ config }) => config.message !== undefined
)
onMessageHandlers.forEach(handler => {
if (handler.config.message) {
this.bot.hears(handler.config.message, this.adoptHandle(handler))
} else {
this.bot.on('message', this.adoptHandle(handler))
}
})
}
private setupOnCommand(handlers: Handler[]): void {
const commandHandlers = handlers.filter(({ config }) => config.command)
commandHandlers.forEach(handler => {
this.bot.command(handler.config.command, this.adoptHandle(handler))
})
}
private setupActions(handlers: Handler[]): void {
const commandHandlers = handlers.filter(({ config }) => config.action)
commandHandlers.forEach(handler => {
this.bot.action(handler.config.action, this.adoptHandle(handler))
})
}
private adoptHandle({ handle, config }: Handler) {
const errorHandler = this.createCatch()
return async (ctx: ContextMessageUpdate) => {
const args = await Promise.all(
(config.transformations || [])
.sort((a, b) => a.index - b.index)
.map(({ transform }) =>
this.ref
.get<ContextTransformer>(transform, { strict: false })
.transform(ctx)
)
)
return handle(ctx, ...args).catch(errorHandler(ctx))
}
}
private createCatch() {
const handlers = Array.from(
(TelegramCatch.handlers || new Map()).entries()
).map(([errorType, handlerType]) => {
const handler = this.ref.get<TelegramErrorHandler>(handlerType, {
strict: false,
})
return {
errorType,
handler,
}
})
return (ctx: ContextMessageUpdate) => (e: any) => {
for (const { errorType, handler } of handlers) {
if (e instanceof (errorType as any)) {
return handler.catch(ctx, e)
}
}
throw e
}
}
}

44
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "nestjs-telegraf", "name": "nestjs-telegraf",
"version": "0.7.3", "version": "1.0.0-alpha.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -102,17 +102,10 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true "dev": true
}, },
"@types/lodash": {
"version": "4.14.149",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
"integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==",
"dev": true
},
"@types/node": { "@types/node": {
"version": "13.1.6", "version": "13.9.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.2.tgz",
"integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg==", "integrity": "sha512-bnoqK579sAYrQbp73wwglccjJ4sfRdKU7WNEZ5FW4K2U6Kc0/eZ5kvXG0JKsEKFB50zrFmfFt52/cvBbZa7eXg=="
"dev": true
}, },
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@ -902,11 +895,6 @@
"p-locate": "^4.1.0" "p-locate": "^4.1.0"
} }
}, },
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"log-symbols": { "log-symbols": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
@ -975,16 +963,14 @@
"dev": true "dev": true
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"dev": true
}, },
"module-alias": { "module-alias": {
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz",
"integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==", "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q=="
"dev": true
}, },
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
@ -1001,8 +987,7 @@
"node-fetch": { "node-fetch": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
"dev": true
}, },
"normalize-path": { "normalize-path": {
"version": "3.0.0", "version": "3.0.0",
@ -1239,8 +1224,7 @@
"sandwich-stream": { "sandwich-stream": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-2.0.2.tgz", "resolved": "https://registry.npmjs.org/sandwich-stream/-/sandwich-stream-2.0.2.tgz",
"integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==", "integrity": "sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ=="
"dev": true
}, },
"semver-compare": { "semver-compare": {
"version": "1.0.0", "version": "1.0.0",
@ -1349,7 +1333,6 @@
"version": "3.36.0", "version": "3.36.0",
"resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.36.0.tgz", "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.36.0.tgz",
"integrity": "sha512-9o6AJKRiTm5vMWYI6WpTfBHzu4FMpWBNKxvnMxRds/cbMY9RnsVVjdi8i4bFFlfd+xbi73EbrnI3dybayryICA==", "integrity": "sha512-9o6AJKRiTm5vMWYI6WpTfBHzu4FMpWBNKxvnMxRds/cbMY9RnsVVjdi8i4bFFlfd+xbi73EbrnI3dybayryICA==",
"dev": true,
"requires": { "requires": {
"@types/node": "^13.1.0", "@types/node": "^13.1.0",
"debug": "^4.0.1", "debug": "^4.0.1",
@ -1364,7 +1347,6 @@
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": { "requires": {
"ms": "^2.1.1" "ms": "^2.1.1"
} }
@ -1372,16 +1354,14 @@
"ms": { "ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
"dev": true
} }
} }
}, },
"telegram-typings": { "telegram-typings": {
"version": "3.6.1", "version": "3.6.1",
"resolved": "https://registry.npmjs.org/telegram-typings/-/telegram-typings-3.6.1.tgz", "resolved": "https://registry.npmjs.org/telegram-typings/-/telegram-typings-3.6.1.tgz",
"integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw==", "integrity": "sha512-njVv1EAhIZnmQVLocZEADYUyqA1WIXuVcDYlsp+mXua/XB0pxx+PKtMSPeZ/EE4wPWTw9h/hA9ASTT6yQelkiw=="
"dev": true
}, },
"timers-ext": { "timers-ext": {
"version": "0.1.7", "version": "0.1.7",

View File

@ -1,6 +1,6 @@
{ {
"name": "nestjs-telegraf", "name": "nestjs-telegraf",
"version": "0.7.3", "version": "1.0.0-alpha.1",
"description": "Telegraf module for Nest framework", "description": "Telegraf module for Nest framework",
"keywords": [ "keywords": [
"nest", "nest",
@ -34,24 +34,21 @@
"publish:npm": "npm publish --access public" "publish:npm": "npm publish --access public"
}, },
"dependencies": { "dependencies": {
"lodash": "4.17.15" "telegraf": "^3.36.0"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/common": "6.11.11", "@nestjs/common": "6.11.11",
"@nestjs/core": "6.11.11", "@nestjs/core": "6.11.11",
"@types/lodash": "4.14.149",
"husky": "4.2.3", "husky": "4.2.3",
"lint-staged": "10.0.8", "lint-staged": "10.0.8",
"prettier": "1.19.1", "prettier": "1.19.1",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"telegraf": "3.36.0",
"typescript": "3.8.3" "typescript": "3.8.3"
}, },
"peerDependencies": { "peerDependencies": {
"@nestjs/common": "^6.7.0", "@nestjs/common": "^6.7.0",
"@nestjs/core": "^6.7.0", "@nestjs/core": "^6.7.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13"
"telegraf": "^3.35.0"
}, },
"husky": { "husky": {
"hooks": { "hooks": {