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",
"singleQuote": true,
"semi": false
"trailingComma": "all",
"singleQuote": true
}

245
README.md
View File

@ -27,213 +27,126 @@
## Installation
```bash
$ npm i nestjs-telegraf telegraf
$ npm i nestjs-telegraf
```
## Usage
### An example of package usage
Once the installation process is complete, we can import the TelegrafModule into the root AppModule.
```typescript
/* bot.module.ts */
/* app.module.ts */
import { Module, OnModuleInit, Logger } from '@nestjs/common'
import { ModuleRef } from '@nestjs/core'
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'
import { Module } from '@nestjs/common';
import { TelegrafModule } from 'nestjs-telegraf';
@Module({
imports: [
TelegrafModule.fromFactory({
imports: [ConfigModule.forFeature(botConfig)],
useClass: TelegrafConfigService,
}),
TelegrafModule.forRoot({
token: 'TELEGRAM_BOT_TOKEN',
})
],
exports: [TelegrafModule],
providers: [BotService],
})
export class BotModule implements OnModuleInit {
constructor(
private readonly moduleRef: ModuleRef,
private readonly telegrafService: TelegrafService
) {}
onModuleInit() {
this.telegrafService.init(this.moduleRef)
this.telegrafService.startPolling()
}
}
export class AppModule {}
```
```typescript
/* telegraf-config.service.ts */
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).
import { Injectable } from '@nestjs/common'
import { TelegrafOptionsFactory, TelegrafModuleOptions } from 'nestjs-telegraf'
import { ConfigService } from '@nestjs/config'
## Telegraf methods
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()
export class TelegrafConfigService implements TelegrafOptionsFactory {
constructor(private readonly configService: ConfigService) {}
export class AppService {
@TelegrafStart()
start(ctx: ContextMessageUpdate) {
ctx.reply('Welcome');
}
createTelegrafOptions(): TelegrafModuleOptions {
return {
token: this.configService.get('bot.token'),
}
@TelegrafHelp()
help(ctx: ContextMessageUpdate) {
ctx.reply('Send me a sticker');
}
@TelegrafOn('sticker')
on(ctx: ContextMessageUpdate) {
ctx.reply('👍');
}
@TelegrafHears('hi')
hears(ctx: ContextMessageUpdate) {
ctx.reply('Hey there');
}
}
```
```typescript
/* bot.config.ts */
## Async configuration
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'
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.
One technique is to use a factory function:
```typescript
/* bot.service.ts */
import { Injectable } from '@nestjs/common'
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,
TelegrafModule.forRootAsync({
useFactory: () => ({
token: 'TELEGRAM_BOT_TOKEN',
}),
);
});
```
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
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'
import { ConfigService } from '@nestjs/config'
import { TelegrafModuleOptions, TelegrafOptionsFactory } from 'nestjs-telegraf'
import { SocksProxyAgent } from 'socks-proxy-agent'
```typescript
TelegrafModule.forRootAsync({
useClass: TelegrafConfigService,
});
```
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()
export class TelegrafConfigService implements TelegrafOptionsFactory {
private agent
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)
class TelegrafConfigService implements TelegrafOptionsFactory {
createMongooseOptions(): TelegrafModuleOptions {
return {
token: this.configService.get('bot.token'),
telegrafOptions: { telegram: { agent: this.agent } },
token: 'TELEGRAM_BOT_TOKEN',
};
}
}
```
### Telegram
#### Telegram methods usage
Inject `TelegrafTelegramService` from `nestjs-telegraf` package for use [Telegram instance](https://telegraf.js.org/#/?id=telegram) from `telegraf` package.
If you want to reuse an existing options provider instead of creating a private copy inside the `TelegrafModule`, use the `useExisting` syntax.
```typescript
/* bot.service.ts */
import { Injectable } from '@nestjs/common'
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)
}
}
TelegrafModule.forRootAsync({
imports: [ConfigModule],
useExisting: ConfigService,
});
```
## Examples
You can see the basic use of the package in this repository:
https://github.com/bukhalo/nestjs-telegraf-sample
## 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 './telegram-action-handler.decorator'
export * from './telegram-catch.decorator'
export * from './telegraf-use.decorator';
export * from './telegraf-on.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 './interfaces'
export * from './decorators'
export * from './telegraf.service'
export * from './telegraf-telegram.service'
export * from './telegraf.module';
export * from './interfaces';
export * from './decorators';

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 * from './handler.interface'
export * from './handle-parameters.interface'
export * from './telegram-error-handler.interface'
export * from './context-transformer.interface'
export { ContextMessageUpdate } from 'telegraf';
export * from './telegraf-options.interface';

View File

@ -1,22 +1,21 @@
import { ModuleMetadata, Type } from '@nestjs/common/interfaces'
import { TelegrafOptions } from 'telegraf'
import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
import { TelegrafOptions } from 'telegraf';
export interface TelegrafModuleOptions {
token: string
sitePublicUrl?: string
telegrafOptions?: TelegrafOptions
token: string;
options?: TelegrafOptions;
}
export interface TelegrafOptionsFactory {
createTelegrafOptions(): TelegrafModuleOptions
createTelegrafOptions(): TelegrafModuleOptions;
}
export interface TelegrafModuleAsyncOptions
extends Pick<ModuleMetadata, 'imports'> {
useExisting?: Type<TelegrafOptionsFactory>
useClass?: Type<TelegrafOptionsFactory>
useExisting?: Type<TelegrafOptionsFactory>;
useClass?: Type<TelegrafOptionsFactory>;
useFactory?: (
...args: any[]
) => Promise<TelegrafModuleOptions> | TelegrafModuleOptions
inject?: any[]
) => Promise<TelegrafModuleOptions> | TelegrafModuleOptions;
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 TokenInjectionToken = Symbol('TokenInjectionToken')
export const TELEGRAF_MODULE_OPTIONS = 'TELEGRAF_MODULE_OPTIONS';
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 {
TelegrafModuleOptions,
TelegrafModuleAsyncOptions,
TelegrafOptionsFactory
} from './interfaces';
import {
TELEGRAF_MODULE_OPTIONS,
TokenInjectionToken
} from './telegraf.constants';
import { TelegrafService, TelegrafTelegramService } from './';
@Module({})
export class TelegrafModule {
static fromFactory(options: TelegrafModuleAsyncOptions): DynamicModule {
public static forRoot(options?: TelegrafModuleOptions): DynamicModule {
return {
module: TelegrafModule,
imports: options.imports || [],
providers: [
...this.createAsyncProviders(options),
TelegrafService,
TelegrafTelegramService,
{
provide: TokenInjectionToken,
useClass: options.useClass
}
],
exports: [TelegrafService, TelegrafTelegramService]
imports: [TelegrafCoreModule.forRoot(options)],
};
}
private static createAsyncProviders(
options: TelegrafModuleAsyncOptions
): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}
return [
this.createAsyncOptionsProvider(options),
{
provide: options.useClass,
useClass: options.useClass
}
];
}
private static createAsyncOptionsProvider(
options: TelegrafModuleAsyncOptions
): Provider {
if (options.useFactory) {
return {
provide: TELEGRAF_MODULE_OPTIONS,
useFactory: options.useFactory,
inject: options.inject || []
};
}
public static forRootAsync(
options: TelegrafModuleAsyncOptions,
): DynamicModule {
return {
provide: TELEGRAF_MODULE_OPTIONS,
useFactory: async (optionsFactory: TelegrafOptionsFactory) =>
await optionsFactory.createTelegrafOptions(),
inject: [options.useExisting || options.useClass]
module: TelegrafModule,
imports: [TelegrafCoreModule.forRootAsync(options)],
};
}
}

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

View File

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