npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

koishi-nestjs

v6.1.0

Published

Koishi.js as Nest.js Module

Downloads

67

Readme

koishi-nestjs

Nest.js 下的 Koishi 模块。koishi-nestjs 在 Nest.js 下使用 Koishi 打造规模化的机器人应用。

安装

npm install koishi-nestjs koishi

配置模块

koishi-nestjs 中,Koishi 以 NestJS 的模块的形式引入到项目工程中。我们支持同步和异步两种配置方式。

另外,KoishiModule 会被注册为 全局模块。在项目的任何模块中注册 KoishiModule 后,在项目的任何位置均能使用 Koishi 的功能。

同步

import { Module } from '@nestjs/common'
import { KoishiModule, PluginDef } from 'koishi-nestjs'
import PluginOnebot from '@koishijs/plugin-onebot'

@Module({
  imports: [
    KoishiModule.register({
      // 在这里填写 Koishi 配置参数
      prefix: '.',
      usePlugins: [
        // 预安装的插件
        PluginDef(PluginOnebot, {
      	  protocol: 'ws',
          endpoint: 'ws://localhost:6700',
          selfId: '111514',
          token: 'koishi',
        }),
      ],
    }),
  ],
})
export class AppModule {}

异步

import { Module } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { KoishiModule, PluginDef } from 'koishi-nestjs'
import PluginOnebot from '@koishijs/plugin-adapter-onebot'

@Module({
  imports: [
    KoishiModule.registerAsync({
      imports: [ConfigModule.forRoot()],
      inject: [ConfigService],
      useFactory: async (config: ConfigService) => ({
        // 在这里填写 Koishi 配置参数
        prefix: '.',
        usePlugins: [
          // 预安装的插件
          PluginDef(PluginOnebot, {
            protocol: 'ws',
            endpoint: config.get('CQ_ENDPOINT'),
            selfId: config.get('CQ_SELFID'),
            token: config.get('CQ_TOKEN'),
          }),
        ],
      }),
    }),
  ],
})
export class AppModule {}

配置项

koishi-nestjs 的配置项和 Koishi 配置项 基本一致,下面是 koishi-nestjs 特有的配置项:

  • loggerPrefix: string Nest 日志中 Logger 的前缀。默认 koishi
  • loggerColor: number Nest 日志中 Logger 的颜色支持。默认 0
  • usePlugins: KoishiModulePlugin[] 可选。预先安装的 Koishi 插件列表。使用 PluginDef(plugin, options, select) 方法生成该项的定义。该配置项的成员参数如下。
    • plugin: Koishi 插件。
    • options: Koishi 插件配置。等同于 ctx.plugin(plugin, options)
    • select: 可选,Selection 对象,指定插件的 上下文选择器
  • moduleSelection: KoishiModuleSelection[] 可选。指定 Nest 实例加载的其他 Nest 模块注入的 Koishi 上下文选择器,参数如下:
  • useWs: boolean 是否启用 WebSocket 网关。异步配置该项应写入异步配置项中,而不是写在 useFactory 中。默认 false
  • actionErrorMessage: string 指令中发生未知错误时,机器人返回的信息。默认 Internal Server Error
  • templateParams: 定义注册的 插值上下文对象

不支持的配置项

由于 koishi-nestjs 复用了 NestJS 实例的 HttpServer 对象,因此下列关于 HttpServer 监听的选项将不受支持:

  • port
  • host

WebSocket 服务器

和直接运行 Koishi 不同,Nest.js 中的 Koishi 模块并不会直接注册 HttpServer,而是将 HttpServer 与 NestJS 中的 HttpServer 进行绑定。而 WebSocket 使用的也是 NestJS 中的 WebSocket 网关。因此若要使用到如 consoleadapter-onebot 的反向 WebSocket 功能的插件,需要在 NestJS 实例注册时进行一些额外的配置。

为了与 Koishi 更好地适配 NestJS 的 WebSocket 功能,koishi-nestjs 提供了基于 @nestjs/platform-ws 的专用 NestJS WebSocket 适配器。我们需要在 Koishi 模块配置中设置 useWstrue,并加载专用 WebSocket 适配器:

// app.module.ts
import { Module } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { KoishiModule, PluginDef } from 'koishi-nestjs'
import PluginOnebot from '@koishijs/plugin-adapter-onebot'

@Module({
  imports: [
    KoishiModule.registerAsync({
      imports: [ConfigModule.forRoot()],
      inject: [ConfigService],
      useWs: true,
      useFactory: async (config: ConfigService) => ({
        // 在这里填写 Koishi 配置参数
        prefix: '.',
        usePlugins: [
          // 预安装的插件
          PluginDef(PluginOnebot, {
            protocol: 'ws',
            endpoint: config.get('CQ_ENDPOINT'),
            selfId: config.get('CQ_SELFID'),
            token: config.get('CQ_TOKEN'),
          }),
        ],
      }),
    }),
  ]
})
export class AppModule {}

// main.ts
const app = await NestFactory.create(AppModule)
app.useWebSocketAdapter(new KoishiWsAdapter(app))

该适配器拥有和 @nestjs/platform-ws 适配器基本一致的功能。在 NestJS 工程内您可以如同正常的 WebSocket 适配器一般使用它。

注入 Koishi 实例

作为开发方式的一种,您可以在 NestJS 的控制器或提供者类中直接对 Koishi 实例或上下文进行注入操作。

这种情况下,建议让 Nest 提供者类实现 OnModuleInit 接口,并在该事件方法中进行 Koishi 指令注册操作。

koishi-nestjs 将在 NestJS 应用启动时启动 Koishi 实例。

注入上下文

@Injectable()
export class AppService implements OnModuleInit {
  constructor(@InjectContext() private ctx: Context) {}

  onModuleInit() {
    this.ctx.on('message', (session) => {})
  }
}

注入某一特定上下文

@Injectable()
export class AppService implements OnModuleInit {
  constructor(@InjectContextGuild('1111111111') private ctx: Context) {}

  onModuleInit() {
    this.ctx.on('message', (session) => {})
  }
}

装饰器定义

在 Nest 提供者构造函数参数列表中使用下列装饰器即可进行注入操作。

  • @InjectContext() 注入全体上下文。等价于 ctx.any()
  • @InjectContextPrivate(...values[]: string) 注入私聊上下文。等价于 ctx.private(...values)
  • @InjectContextChannel(...values[]: string) 注入频道上下文。等价于 ctx.channel(...values)
  • @InjectContextGuild(...values[]: string) 注入群组上下文。等价于 ctx.guild(...values)
  • @InjectContextSelf(...values[]: string) 注入机器人账户上下文。等价于 ctx.self(...values)
  • @InjectContextUser(...values[]: string) 注入用户上下文。等价于 ctx.user(...values)
  • @InjectContextPlatform(...values[]: string) 注入平台上下文。等价于 ctx.platform(...values)

在自定义提供者注入 Koishi 上下文

您将需要使用函数 getContextProvideToken() 进行注入操作,如下例。

import { Module } from '@nestjs/common'
import { KoishiModule, getContextProvideToken } from 'koishi-nestjs'
import { AppService } from './app.service'
import { Context } from 'koishi'

@Module({
  imports: [
    KoishiModule.register({...})
  ],
  providers: [
    {
      provide: AppService,
      inject: [getContextProvideToken()],
      useFactory: (ctx: Context) => new AppService(ctx),
    },
  ],
})
export class AppModule {}

函数定义

function getContextProvideToken(scopeType?: ContextScopeTypes, values: string[] = [])
  • scopeType: 选择器类型,可以是 private channel guild self user platform 之一。留空表示全局上下文。
  • values: 选择器值。例如 getContextProvideToken('platform', ['onebot']) 等价于 ctx.platform('onebot')

在提供者类中注册方法

您也可以在提供者类中,使用装饰器进行 Koishi 的中间件,事件,指令等方法注册,也可以加载插件。

@Injectable()
export class AppService {
  // 注册中间件
  @UseMiddleware()
  simpleMiddleware(session: Session, next: NextFunction) {
    if (session.content === 'pang') {
      return 'peng'
    }
    return next()
  }

  // 注册事件监听器
  @UseEvent('message')
  async onMessage(session: Session) {
    if (session.content === 'ping') {
      await session.send('pong')
    }
  }

  // 注册指令
  @UseCommand('dress', '穿裙子')
  @CommandUsage('今天穿裙子了吗?')
  onDressCommand(
    @PutOption('color', '-c <color:string>  裙子的颜色') color: string,
    @PutUserName() name: string,
  ) {
    return `${name} 今天穿的裙子的颜色是 ${color}。`
  }
}

装饰器定义与 koishi-thirdeye 中一致。但是下列存在于 koishi-thirdeye 的功能由于 NestJS 已经提供,因此在 koishi-nestjs 中不受支持。

  • @Get 等 HTTP 路由注册方法。请使用 NestJS 的控制器。
  • @Ws 请使用 NestJS 的 WebSocket 网关。

错误处理

在 koishi-nestjs 的指令处理中,若抛出 NestJS 中的 HttpExceptionWsException 的异常时,系统将会以其中的返回信息作为机器人发送给用户的错误信息。

若遇到未知的错误,机器人则会返回给用户 Internal Server Error 信息。要改变这一错误信息,可以使用 actionErrorMessage 配置选项。设置成空字符串可以完全禁用这一行为。

@Injectable()
export class AppService {
  @UseCommand('dress', '穿裙子')
  @CommandUsage('今天穿裙子了吗?')
  onDressCommand(
    @PutOption('color', '-c <color:string>  裙子的颜色') color: string,
    @PutUserName() name: string,
  ) {
    throw new NotFoundException(`${name} 今天没有穿裙子!`)
  }
}

选择器

选择器装饰器可以注册在提供者类顶部,也可以注册在提供者方法函数。定义与 koishi-thirdeye 相同。

具有选择器定义的 NestJS 提供者类注入的 Koishi 上下文对象,也会受到这些选择器定义的影响。

@OnPlatform('onebot')
@Injectable()
export class AppService implements OnModuleInit {
  constructor(@InjectContext() private ctx: Context) {}

  onModuleInit() {
    // 只对 OneBot 平台生效
    this.ctx.on('message', (session) => {})
  }
}

插值定义

koishi-thirdeye 类似,koishi-nestjs 也提供了插值定义的功能,以灵活给地为。

koishi-nestjs 的选择器和指令方法注册装饰器均支持插值,插值上下文由配置的 templateParams 属性提供。

// app.service.ts
@Injectable()
export class AppService {
  @UseCommand('{{dress.commandName}}')
  onDressCommand(
    @PutValue('{{dress.color}}') color: string,
    @PutValue('{{dress.size}}') size: string,
  ) {
    return `您穿的裙子是 ${color} 色的,大小是 ${size}。`
  }
}

// app.module.ts
@Module({
  imports: [
    KoishiModule.register({
      templateParams: {
        dress: {
          commandName: 'dress',
          color: '红色',
          size: 'XL',
        },
      },
    }),
  ],
  providers: [
    AppService,
  ],
})
export class AppModule {}

使用服务

您也可以在 NestJS 的提供者类中,使用 @WireContextService() 装饰器在 NestJS 提供者类中注入 Koishi 的服务对象。

@Injectable()
export class AppService implements OnApplicationBootstrap {
  // 注入服务对象
  @WireContextService('cache')
  private database: DatabaseService

  // 成员变量名与服务名称一致时 name 可省略。
  @WireContextService()
  private database2: DatabaseService

  async onApplicationBootstrap() {
    // onApplicationBootstrap 钩子方法中,插件已经加载完毕,因此在这里可以确保能访问服务对象
    const user = await this.database.getUser('114514')
  }
}