diff --git a/README.md b/README.md index 14eeb657f4..b1e8adbc04 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,11 @@ koishi run - [Mrs4s/go-cqhttp](https://github.com/Mrs4s/go-cqhttp) - [yyuueexxiinngg/cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai) -请注意:尽管 Koishi 使用的协议是 [MIT](https://choosealicense.com/licenses/mit/) 协议,但上面陈述的三种途径的相关框架都使用了基于 [AGPL 3.0](https://choosealicense.com/licenses/agpl-3.0/) 的协议。因此如果你使用 koishi-adapter-cqhttp 运行你的机器人,你将可能受到 AGPL 3.0 协议的限制,**必须将你的代码开源并保持同协议**。Koishi 及其作者对使用上述框架或违反上述限制的行为所可能造成的一切后果概不负责。 +请注意:尽管 Koishi 使用的协议是 [MIT](https://choosealicense.com/licenses/mit/) 协议,但上面陈述的三种途径的相关框架都使用了基于 [AGPL 3.0](https://choosealicense.com/licenses/agpl-3.0/) 的协议。因此**如果你使用 koishi-adapter-cqhttp 运行你的机器人,你将可能受到 AGPL 3.0 协议的限制,必须将你的代码开源并保持同协议**。Koishi 及其作者对使用上述框架或违反上述限制的行为所可能造成的一切后果概不负责。 + +### [koishi-adapter-tomon](./packages/adapter-tomon) [![npm](https://img.shields.io/npm/v/koishi-adapter-tomon?style=flat-square)](https://www.npmjs.com/package/koishi-adapter-tomon) + +**[开发中]** [Tomon](https://tomon.fun) 平台支持。 ## 数据库支持 @@ -79,7 +83,7 @@ MySQL 5.7 支持。 ### [koishi-plugin-chess](./packages/plugin-chess) [![npm](https://img.shields.io/npm/v/koishi-plugin-chess/next?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-chess) -### [koishi-plugin-common](./packages/plugin-common) [![npm](https://img.shields.io/npm/v/koishi-plugin-common/next?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-common) +### [koishi-plugin-common](./packages/plugin-common) [![npm](https://img.shields.io/npm/v/koishi-plugin-common?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-common) koishi-plugin-common 包含了一些常用功能,它们在你使用 koishi 库时是默认安装的。包含下列功能: diff --git a/packages/adapter-cqhttp/package.json b/packages/adapter-cqhttp/package.json index efa427b405..5a494076aa 100644 --- a/packages/adapter-cqhttp/package.json +++ b/packages/adapter-cqhttp/package.json @@ -1,7 +1,7 @@ { "name": "koishi-adapter-cqhttp", "description": "CQHTTP adapter for Koishi", - "version": "1.0.3", + "version": "1.0.4", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -31,7 +31,7 @@ "koishi" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "devDependencies": { "@types/ms": "^0.7.31", diff --git a/packages/adapter-cqhttp/src/api.ts b/packages/adapter-cqhttp/src/api.ts index 11a184310a..93ecbe14a4 100644 --- a/packages/adapter-cqhttp/src/api.ts +++ b/packages/adapter-cqhttp/src/api.ts @@ -74,6 +74,27 @@ export interface VersionInfo { pluginBuildConfiguration: 'debug' | 'release' } +export type HonorType = 'talkative' | 'performer' | 'legend' | 'strong_newbie' | 'emotion' + +export interface TalkativeMemberInfo extends AccountInfo { + avatar: string + dayCount: number +} + +export interface HonoredMemberInfo { + avatar: string + description: string +} + +export interface HonorInfo { + currentTalkative: TalkativeMemberInfo + talkativeList: HonoredMemberInfo[] + performerList: HonoredMemberInfo[] + legendList: HonoredMemberInfo[] + strongNewbieList: HonoredMemberInfo[] + emotionList: HonoredMemberInfo[] +} + declare module 'koishi-core/dist/server' { interface Bot { _request?(action: string, params: Record): Promise @@ -116,6 +137,7 @@ declare module 'koishi-core/dist/server' { getGroupInfo(groupId: number, noCache?: boolean): Promise getGroupMemberInfo(groupId: number, userId: number, noCache?: boolean): Promise getGroupMemberList(groupId: number): Promise + getGroupHonorInfo(groupId: number, type: HonorType): Promise getCookies(domain?: string): Promise getCsrfToken(): Promise getCredentials(domain?: string): Promise @@ -301,6 +323,7 @@ defineSync('get_group_list') defineSync('get_group_info', 'group_id', 'no_cache') defineSync('get_group_member_info', 'group_id', 'user_id', 'no_cache') defineSync('get_group_member_list', 'group_id') +defineSync('get_group_honor_info', 'group_id', 'type') defineExtract('get_cookies', 'cookies', 'domain') defineExtract('get_csrf_token', 'token') defineSync('get_credentials', 'domain') diff --git a/packages/adapter-cqhttp/tests/sender.spec.ts b/packages/adapter-cqhttp/tests/sender.spec.ts index 3aba8628db..c9d9ae0ddd 100644 --- a/packages/adapter-cqhttp/tests/sender.spec.ts +++ b/packages/adapter-cqhttp/tests/sender.spec.ts @@ -2,21 +2,21 @@ import { createHttpServer, HttpServer } from 'koishi-test-utils' import { Sender } from 'koishi-core' let server: HttpServer -let sender: Sender +let bot: Sender -beforeAll(async () => { +before(async () => { server = await createHttpServer() const app = server.createBoundApp() await app.start() - sender = app.sender + bot = app.sender }) -afterAll(() => server.close()) +after(() => server.close()) describe('Sender API', () => { beforeEach(() => { server.clearRequests() - sender.app.server.version = {} as any + bot.app.server.version = {} as any }) const foo = { foo: 'foo' } @@ -24,345 +24,345 @@ describe('Sender API', () => { test('get', async () => { server.setResponse('bar', bar) - await expect(sender.get('bar')).resolves.to.have.shape(bar) + await expect(bot.get('bar')).resolves.to.have.shape(bar) server.setResponse('bar', bar, 102) - await expect(sender.get('bar')).rejects.toHaveProperty('name', 'SenderError') + await expect(bot.get('bar')).rejects.toHaveProperty('name', 'SenderError') server.setResponse('bar', bar, -99) - await expect(sender.get('bar')).rejects.toHaveProperty('name', 'SenderError') + await expect(bot.get('bar')).rejects.toHaveProperty('name', 'SenderError') }) test('getAsync', async () => { server.setResponse('foo_async', foo, 1) - await expect(sender.getAsync('foo')).resolves.toBeUndefined() + await expect(bot.getAsync('foo')).resolves.toBeUndefined() server.setResponse('foo_async', foo, 102) - await expect(sender.getAsync('foo')).rejects.toHaveProperty('name', 'SenderError') + await expect(bot.getAsync('foo')).rejects.toHaveProperty('name', 'SenderError') // < 4.0.0 - sender.app.version.pluginMajorVersion = 3 - sender.app.version.pluginMinorVersion = 4 + bot.app.version.pluginMajorVersion = 3 + bot.app.version.pluginMinorVersion = 4 server.setResponse('foo', foo) - await expect(sender.getAsync('foo')).resolves.toBeUndefined() + await expect(bot.getAsync('foo')).resolves.toBeUndefined() server.setResponse('foo', foo, -99) - await expect(sender.getAsync('foo')).resolves.toBeUndefined() + await expect(bot.getAsync('foo')).resolves.toBeUndefined() }) const messageId = 456 test('sendMsg', async () => { - await expect(sender.sendMsg(undefined, undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: type') - await expect(sender.sendMsg('foo' as any, undefined, undefined)).rejects.toHaveProperty('message', 'invalid argument: type') - await expect(sender.sendMsg('private', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.sendMsg('group', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.sendMsg('discuss', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') - await expect(sender.sendMsgAsync(undefined, undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: type') - await expect(sender.sendMsgAsync('foo' as any, undefined, undefined)).rejects.toHaveProperty('message', 'invalid argument: type') - await expect(sender.sendMsgAsync('private', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.sendMsgAsync('group', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.sendMsgAsync('discuss', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') + await expect(bot.sendMsg(undefined, undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: type') + await expect(bot.sendMsg('foo' as any, undefined, undefined)).rejects.toHaveProperty('message', 'invalid argument: type') + await expect(bot.sendMsg('private', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.sendMsg('group', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.sendMsg('discuss', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') + await expect(bot.sendMsgAsync(undefined, undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: type') + await expect(bot.sendMsgAsync('foo' as any, undefined, undefined)).rejects.toHaveProperty('message', 'invalid argument: type') + await expect(bot.sendMsgAsync('private', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.sendMsgAsync('group', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.sendMsgAsync('discuss', undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') server.setResponse('send_msg', { messageId }) - await expect(sender.sendMsg('group', 123, '')).resolves.toBeUndefined() + await expect(bot.sendMsg('group', 123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendMsg('group', 123, 'foo')).resolves.to.equal(messageId) + await expect(bot.sendMsg('group', 123, 'foo')).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_msg', { groupId: '123', message: 'foo' }) - await expect(sender.sendMsg('private', 123, 'foo')).resolves.to.equal(messageId) + await expect(bot.sendMsg('private', 123, 'foo')).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_msg', { userId: '123', message: 'foo' }) - await expect(sender.sendMsg('private', 123, 'foo', true)).resolves.to.equal(messageId) + await expect(bot.sendMsg('private', 123, 'foo', true)).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_msg', { userId: '123', message: 'foo', autoEscape: 'true' }) - await expect(sender.sendMsgAsync('group', 123, '')).resolves.toBeUndefined() + await expect(bot.sendMsgAsync('group', 123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendMsgAsync('group', 123, 'foo')).resolves.toBeUndefined() + await expect(bot.sendMsgAsync('group', 123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('send_msg_async', { groupId: '123', message: 'foo' }) - await expect(sender.sendMsgAsync('private', 123, 'foo')).resolves.toBeUndefined() + await expect(bot.sendMsgAsync('private', 123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('send_msg_async', { userId: '123', message: 'foo' }) - await expect(sender.sendMsgAsync('private', 123, 'foo', true)).resolves.toBeUndefined() + await expect(bot.sendMsgAsync('private', 123, 'foo', true)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_msg_async', { userId: '123', message: 'foo', autoEscape: 'true' }) }) test('sendGroupMsg', async () => { - await expect(sender.sendGroupMsg(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.sendGroupMsgAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.sendGroupMsg(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.sendGroupMsgAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') server.setResponse('send_group_msg', { messageId }) - await expect(sender.sendGroupMsg(123, '')).resolves.toBeUndefined() + await expect(bot.sendGroupMsg(123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendGroupMsg(123, 'foo')).resolves.to.equal(messageId) + await expect(bot.sendGroupMsg(123, 'foo')).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_group_msg', { groupId: '123', message: 'foo' }) - await expect(sender.sendGroupMsg(123, 'foo', true)).resolves.to.equal(messageId) + await expect(bot.sendGroupMsg(123, 'foo', true)).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_group_msg', { groupId: '123', message: 'foo', autoEscape: 'true' }) - await expect(sender.sendGroupMsgAsync(123, '')).resolves.toBeUndefined() + await expect(bot.sendGroupMsgAsync(123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendGroupMsgAsync(123, 'foo')).resolves.toBeUndefined() + await expect(bot.sendGroupMsgAsync(123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('send_group_msg_async', { groupId: '123', message: 'foo' }) - await expect(sender.sendGroupMsgAsync(123, 'foo', true)).resolves.toBeUndefined() + await expect(bot.sendGroupMsgAsync(123, 'foo', true)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_group_msg_async', { groupId: '123', message: 'foo', autoEscape: 'true' }) }) test('sendDiscussMsg', async () => { - await expect(sender.sendDiscussMsg(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') - await expect(sender.sendDiscussMsgAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') + await expect(bot.sendDiscussMsg(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') + await expect(bot.sendDiscussMsgAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') server.setResponse('send_discuss_msg', { messageId }) - await expect(sender.sendDiscussMsg(123, '')).resolves.toBeUndefined() + await expect(bot.sendDiscussMsg(123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendDiscussMsg(123, 'foo')).resolves.to.equal(messageId) + await expect(bot.sendDiscussMsg(123, 'foo')).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_discuss_msg', { discussId: '123', message: 'foo' }) - await expect(sender.sendDiscussMsg(123, 'foo', true)).resolves.to.equal(messageId) + await expect(bot.sendDiscussMsg(123, 'foo', true)).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_discuss_msg', { discussId: '123', message: 'foo', autoEscape: 'true' }) - await expect(sender.sendDiscussMsgAsync(123, '')).resolves.toBeUndefined() + await expect(bot.sendDiscussMsgAsync(123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendDiscussMsgAsync(123, 'foo')).resolves.toBeUndefined() + await expect(bot.sendDiscussMsgAsync(123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('send_discuss_msg_async', { discussId: '123', message: 'foo' }) - await expect(sender.sendDiscussMsgAsync(123, 'foo', true)).resolves.toBeUndefined() + await expect(bot.sendDiscussMsgAsync(123, 'foo', true)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_discuss_msg_async', { discussId: '123', message: 'foo', autoEscape: 'true' }) }) test('sendPrivateMsg', async () => { - await expect(sender.sendPrivateMsg(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.sendPrivateMsgAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.sendPrivateMsg(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.sendPrivateMsgAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') server.setResponse('send_private_msg', { messageId }) - await expect(sender.sendPrivateMsg(123, '')).resolves.toBeUndefined() + await expect(bot.sendPrivateMsg(123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendPrivateMsg(123, 'foo')).resolves.to.equal(messageId) + await expect(bot.sendPrivateMsg(123, 'foo')).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_private_msg', { userId: '123', message: 'foo' }) - await expect(sender.sendPrivateMsg(123, 'foo', true)).resolves.to.equal(messageId) + await expect(bot.sendPrivateMsg(123, 'foo', true)).resolves.to.equal(messageId) server.shouldHaveLastRequest('send_private_msg', { userId: '123', message: 'foo', autoEscape: 'true' }) - await expect(sender.sendPrivateMsgAsync(123, '')).resolves.toBeUndefined() + await expect(bot.sendPrivateMsgAsync(123, '')).resolves.toBeUndefined() server.shouldHaveNoRequests() - await expect(sender.sendPrivateMsgAsync(123, 'foo')).resolves.toBeUndefined() + await expect(bot.sendPrivateMsgAsync(123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('send_private_msg_async', { userId: '123', message: 'foo' }) - await expect(sender.sendPrivateMsgAsync(123, 'foo', true)).resolves.toBeUndefined() + await expect(bot.sendPrivateMsgAsync(123, 'foo', true)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_private_msg_async', { userId: '123', message: 'foo', autoEscape: 'true' }) }) test('deleteMsg', async () => { - await expect(sender.deleteMsg(undefined)).rejects.toHaveProperty('message', 'missing argument: messageId') - await expect(sender.deleteMsgAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: messageId') + await expect(bot.deleteMsg(undefined)).rejects.toHaveProperty('message', 'missing argument: messageId') + await expect(bot.deleteMsgAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: messageId') - await expect(sender.deleteMsg(456)).resolves.toBeUndefined() + await expect(bot.deleteMsg(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('delete_msg', { messageId: '456' }) - await expect(sender.deleteMsgAsync(456)).resolves.toBeUndefined() + await expect(bot.deleteMsgAsync(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('delete_msg_async', { messageId: '456' }) }) test('sendLike', async () => { - await expect(sender.sendLike(undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.sendLike(123, 0.1)).rejects.toHaveProperty('message', 'invalid argument: times') - await expect(sender.sendLikeAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.sendLikeAsync(123, 0.1)).rejects.toHaveProperty('message', 'invalid argument: times') + await expect(bot.sendLike(undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.sendLike(123, 0.1)).rejects.toHaveProperty('message', 'invalid argument: times') + await expect(bot.sendLikeAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.sendLikeAsync(123, 0.1)).rejects.toHaveProperty('message', 'invalid argument: times') - await expect(sender.sendLike(123)).resolves.toBeUndefined() + await expect(bot.sendLike(123)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_like', { userId: '123', times: '1' }) - await expect(sender.sendLike(123, 5)).resolves.toBeUndefined() + await expect(bot.sendLike(123, 5)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_like', { userId: '123', times: '5' }) - await expect(sender.sendLikeAsync(123)).resolves.toBeUndefined() + await expect(bot.sendLikeAsync(123)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_like_async', { userId: '123', times: '1' }) - await expect(sender.sendLikeAsync(123, 5)).resolves.toBeUndefined() + await expect(bot.sendLikeAsync(123, 5)).resolves.toBeUndefined() server.shouldHaveLastRequest('send_like_async', { userId: '123', times: '5' }) }) test('setGroupKick', async () => { - await expect(sender.setGroupKick(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupKick(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupKickAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupKickAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupKick(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupKick(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupKickAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupKickAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupKick(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupKick(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_kick', { userId: '123', groupId: '456' }) - await expect(sender.setGroupKick(456, 123, true)).resolves.toBeUndefined() + await expect(bot.setGroupKick(456, 123, true)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_kick', { userId: '123', groupId: '456', rejectAddRequest: 'true' }) - await expect(sender.setGroupKickAsync(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupKickAsync(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_kick_async', { userId: '123', groupId: '456' }) - await expect(sender.setGroupKickAsync(456, 123, true)).resolves.toBeUndefined() + await expect(bot.setGroupKickAsync(456, 123, true)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_kick_async', { userId: '123', groupId: '456', rejectAddRequest: 'true' }) }) test('setGroupBan', async () => { - await expect(sender.setGroupBan(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupBan(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupBanAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupBanAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupBan(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupBan(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupBanAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupBanAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupBan(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupBan(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_ban', { userId: '123', groupId: '456' }) - await expect(sender.setGroupBan(456, 123, 1000)).resolves.toBeUndefined() + await expect(bot.setGroupBan(456, 123, 1000)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_ban', { userId: '123', groupId: '456', duration: '1000' }) - await expect(sender.setGroupBanAsync(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupBanAsync(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_ban_async', { userId: '123', groupId: '456' }) - await expect(sender.setGroupBanAsync(456, 123, 1000)).resolves.toBeUndefined() + await expect(bot.setGroupBanAsync(456, 123, 1000)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_ban_async', { userId: '123', groupId: '456', duration: '1000' }) }) test('setGroupAnonymousBan', async () => { - await expect(sender.setGroupAnonymousBan(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupAnonymousBan(456, undefined)).rejects.toHaveProperty('message', 'missing argument: anonymous or flag') - await expect(sender.setGroupAnonymousBanAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupAnonymousBanAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: anonymous or flag') + await expect(bot.setGroupAnonymousBan(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupAnonymousBan(456, undefined)).rejects.toHaveProperty('message', 'missing argument: anonymous or flag') + await expect(bot.setGroupAnonymousBanAsync(undefined, undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupAnonymousBanAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: anonymous or flag') - await expect(sender.setGroupAnonymousBan(456, 'foo')).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBan(456, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban', { flag: 'foo', groupId: '456' }) - await expect(sender.setGroupAnonymousBan(456, 'foo', 1000)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBan(456, 'foo', 1000)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban', { flag: 'foo', groupId: '456', duration: '1000' }) - await expect(sender.setGroupAnonymousBanAsync(456, 'foo')).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBanAsync(456, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban_async', { flag: 'foo', groupId: '456' }) - await expect(sender.setGroupAnonymousBanAsync(456, 'foo', 1000)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBanAsync(456, 'foo', 1000)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban_async', { flag: 'foo', groupId: '456', duration: '1000' }) const anonymous = { flag: 'foo' } const serialized = JSON.stringify(anonymous) - await expect(sender.setGroupAnonymousBan(456, anonymous)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBan(456, anonymous)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban', { anonymous: serialized, groupId: '456' }) - await expect(sender.setGroupAnonymousBan(456, anonymous, 1000)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBan(456, anonymous, 1000)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban', { anonymous: serialized, groupId: '456', duration: '1000' }) - await expect(sender.setGroupAnonymousBanAsync(456, anonymous)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBanAsync(456, anonymous)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban_async', { anonymous: serialized, groupId: '456' }) - await expect(sender.setGroupAnonymousBanAsync(456, anonymous, 1000)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousBanAsync(456, anonymous, 1000)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_ban_async', { anonymous: serialized, groupId: '456', duration: '1000' }) }) test('setGroupWholeBan', async () => { - await expect(sender.setGroupWholeBan(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupWholeBanAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupWholeBan(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupWholeBanAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupWholeBan(456)).resolves.toBeUndefined() + await expect(bot.setGroupWholeBan(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_whole_ban', { groupId: '456', enable: 'true' }) - await expect(sender.setGroupWholeBan(456, false)).resolves.toBeUndefined() + await expect(bot.setGroupWholeBan(456, false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_whole_ban', { groupId: '456', enable: 'false' }) - await expect(sender.setGroupWholeBanAsync(456)).resolves.toBeUndefined() + await expect(bot.setGroupWholeBanAsync(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_whole_ban_async', { groupId: '456', enable: 'true' }) - await expect(sender.setGroupWholeBanAsync(456, false)).resolves.toBeUndefined() + await expect(bot.setGroupWholeBanAsync(456, false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_whole_ban_async', { groupId: '456', enable: 'false' }) }) test('setGroupAdmin', async () => { - await expect(sender.setGroupAdmin(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupAdmin(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupAdminAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupAdminAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupAdmin(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupAdmin(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupAdminAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupAdminAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupAdmin(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupAdmin(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_admin', { userId: '123', groupId: '456', enable: 'true' }) - await expect(sender.setGroupAdmin(456, 123, false)).resolves.toBeUndefined() + await expect(bot.setGroupAdmin(456, 123, false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_admin', { userId: '123', groupId: '456', enable: 'false' }) - await expect(sender.setGroupAdminAsync(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupAdminAsync(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_admin_async', { userId: '123', groupId: '456', enable: 'true' }) - await expect(sender.setGroupAdminAsync(456, 123, false)).resolves.toBeUndefined() + await expect(bot.setGroupAdminAsync(456, 123, false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_admin_async', { userId: '123', groupId: '456', enable: 'false' }) }) test('setGroupAnonymous', async () => { - await expect(sender.setGroupAnonymous(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupAnonymousAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupAnonymous(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupAnonymousAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupAnonymous(456)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymous(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous', { groupId: '456', enable: 'true' }) - await expect(sender.setGroupAnonymous(456, false)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymous(456, false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous', { groupId: '456', enable: 'false' }) - await expect(sender.setGroupAnonymousAsync(456)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousAsync(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_async', { groupId: '456', enable: 'true' }) - await expect(sender.setGroupAnonymousAsync(456, false)).resolves.toBeUndefined() + await expect(bot.setGroupAnonymousAsync(456, false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_anonymous_async', { groupId: '456', enable: 'false' }) }) test('setGroupCard', async () => { - await expect(sender.setGroupCard(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupCard(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupCardAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupCardAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupCard(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupCard(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupCardAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupCardAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupCard(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupCard(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_card', { userId: '123', groupId: '456', card: '' }) - await expect(sender.setGroupCard(456, 123, 'foo')).resolves.toBeUndefined() + await expect(bot.setGroupCard(456, 123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_card', { userId: '123', groupId: '456', card: 'foo' }) - await expect(sender.setGroupCardAsync(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupCardAsync(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_card_async', { userId: '123', groupId: '456', card: '' }) - await expect(sender.setGroupCardAsync(456, 123, 'foo')).resolves.toBeUndefined() + await expect(bot.setGroupCardAsync(456, 123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_card_async', { userId: '123', groupId: '456', card: 'foo' }) }) test('setGroupSpecialTitle', async () => { - await expect(sender.setGroupSpecialTitle(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupSpecialTitle(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupSpecialTitleAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupSpecialTitleAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupSpecialTitle(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupSpecialTitle(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.setGroupSpecialTitleAsync(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupSpecialTitleAsync(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') - await expect(sender.setGroupSpecialTitle(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupSpecialTitle(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_special_title', { userId: '123', groupId: '456', specialTitle: '' }) - await expect(sender.setGroupSpecialTitle(456, 123, 'foo')).resolves.toBeUndefined() + await expect(bot.setGroupSpecialTitle(456, 123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_special_title', { userId: '123', groupId: '456', specialTitle: 'foo' }) - await expect(sender.setGroupSpecialTitleAsync(456, 123)).resolves.toBeUndefined() + await expect(bot.setGroupSpecialTitleAsync(456, 123)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_special_title_async', { userId: '123', groupId: '456', specialTitle: '' }) - await expect(sender.setGroupSpecialTitleAsync(456, 123, 'foo')).resolves.toBeUndefined() + await expect(bot.setGroupSpecialTitleAsync(456, 123, 'foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_special_title_async', { userId: '123', groupId: '456', specialTitle: 'foo' }) }) test('setGroupLeave', async () => { - await expect(sender.setGroupLeave(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupLeaveAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupLeave(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.setGroupLeaveAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.setGroupLeave(456)).resolves.toBeUndefined() + await expect(bot.setGroupLeave(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_leave', { groupId: '456' }) - await expect(sender.setGroupLeave(456, true)).resolves.toBeUndefined() + await expect(bot.setGroupLeave(456, true)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_leave', { groupId: '456', isDismiss: 'true' }) - await expect(sender.setGroupLeaveAsync(456)).resolves.toBeUndefined() + await expect(bot.setGroupLeaveAsync(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_leave_async', { groupId: '456' }) - await expect(sender.setGroupLeaveAsync(456, true)).resolves.toBeUndefined() + await expect(bot.setGroupLeaveAsync(456, true)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_leave_async', { groupId: '456', isDismiss: 'true' }) }) test('setDiscussLeave', async () => { - await expect(sender.setDiscussLeave(undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') - await expect(sender.setDiscussLeaveAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') + await expect(bot.setDiscussLeave(undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') + await expect(bot.setDiscussLeaveAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: discussId') - await expect(sender.setDiscussLeave(456)).resolves.toBeUndefined() + await expect(bot.setDiscussLeave(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_discuss_leave', { discussId: '456' }) - await expect(sender.setDiscussLeaveAsync(456)).resolves.toBeUndefined() + await expect(bot.setDiscussLeaveAsync(456)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_discuss_leave_async', { discussId: '456' }) }) test('setFriendAddRequest', async () => { - await expect(sender.setFriendAddRequest(undefined)).rejects.toHaveProperty('message', 'missing argument: flag') - await expect(sender.setFriendAddRequestAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: flag') + await expect(bot.setFriendAddRequest(undefined)).rejects.toHaveProperty('message', 'missing argument: flag') + await expect(bot.setFriendAddRequestAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: flag') - await expect(sender.setFriendAddRequest('foo')).resolves.toBeUndefined() + await expect(bot.setFriendAddRequest('foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_friend_add_request', { flag: 'foo', approve: 'true' }) - await expect(sender.setFriendAddRequest('foo', false)).resolves.toBeUndefined() + await expect(bot.setFriendAddRequest('foo', false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_friend_add_request', { flag: 'foo', approve: 'false' }) - await expect(sender.setFriendAddRequest('foo', 'bar')).resolves.toBeUndefined() + await expect(bot.setFriendAddRequest('foo', 'bar')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_friend_add_request', { flag: 'foo', approve: 'true', remark: 'bar' }) - await expect(sender.setFriendAddRequestAsync('foo')).resolves.toBeUndefined() + await expect(bot.setFriendAddRequestAsync('foo')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_friend_add_request_async', { flag: 'foo', approve: 'true' }) - await expect(sender.setFriendAddRequestAsync('foo', false)).resolves.toBeUndefined() + await expect(bot.setFriendAddRequestAsync('foo', false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_friend_add_request_async', { flag: 'foo', approve: 'false' }) - await expect(sender.setFriendAddRequestAsync('foo', 'bar')).resolves.toBeUndefined() + await expect(bot.setFriendAddRequestAsync('foo', 'bar')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_friend_add_request_async', { flag: 'foo', approve: 'true', remark: 'bar' }) }) test('setGroupAddRequest', async () => { - await expect(sender.setGroupAddRequest(undefined, 'add')).rejects.toHaveProperty('message', 'missing argument: flag') - await expect(sender.setGroupAddRequest('foo', undefined)).rejects.toHaveProperty('message', 'missing argument: subType') - await expect(sender.setGroupAddRequest('foo', 'bar' as any)).rejects.toHaveProperty('message', 'invalid argument: subType') - await expect(sender.setGroupAddRequestAsync(undefined, 'add')).rejects.toHaveProperty('message', 'missing argument: flag') - await expect(sender.setGroupAddRequestAsync('foo', undefined)).rejects.toHaveProperty('message', 'missing argument: subType') - await expect(sender.setGroupAddRequestAsync('foo', 'bar' as any)).rejects.toHaveProperty('message', 'invalid argument: subType') - - await expect(sender.setGroupAddRequest('foo', 'add')).resolves.toBeUndefined() + await expect(bot.setGroupAddRequest(undefined, 'add')).rejects.toHaveProperty('message', 'missing argument: flag') + await expect(bot.setGroupAddRequest('foo', undefined)).rejects.toHaveProperty('message', 'missing argument: subType') + await expect(bot.setGroupAddRequest('foo', 'bar' as any)).rejects.toHaveProperty('message', 'invalid argument: subType') + await expect(bot.setGroupAddRequestAsync(undefined, 'add')).rejects.toHaveProperty('message', 'missing argument: flag') + await expect(bot.setGroupAddRequestAsync('foo', undefined)).rejects.toHaveProperty('message', 'missing argument: subType') + await expect(bot.setGroupAddRequestAsync('foo', 'bar' as any)).rejects.toHaveProperty('message', 'invalid argument: subType') + + await expect(bot.setGroupAddRequest('foo', 'add')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_add_request', { flag: 'foo', subType: 'add', approve: 'true' }) - await expect(sender.setGroupAddRequest('foo', 'add', false)).resolves.toBeUndefined() + await expect(bot.setGroupAddRequest('foo', 'add', false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_add_request', { flag: 'foo', subType: 'add', approve: 'false' }) - await expect(sender.setGroupAddRequest('foo', 'add', 'bar')).resolves.toBeUndefined() + await expect(bot.setGroupAddRequest('foo', 'add', 'bar')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_add_request', { flag: 'foo', subType: 'add', approve: 'false', reason: 'bar' }) - await expect(sender.setGroupAddRequestAsync('foo', 'add')).resolves.toBeUndefined() + await expect(bot.setGroupAddRequestAsync('foo', 'add')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_add_request_async', { flag: 'foo', subType: 'add', approve: 'true' }) - await expect(sender.setGroupAddRequestAsync('foo', 'add', false)).resolves.toBeUndefined() + await expect(bot.setGroupAddRequestAsync('foo', 'add', false)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_add_request_async', { flag: 'foo', subType: 'add', approve: 'false' }) - await expect(sender.setGroupAddRequestAsync('foo', 'add', 'bar')).resolves.toBeUndefined() + await expect(bot.setGroupAddRequestAsync('foo', 'add', 'bar')).resolves.toBeUndefined() server.shouldHaveLastRequest('set_group_add_request_async', { flag: 'foo', subType: 'add', approve: 'false', reason: 'bar' }) }) @@ -371,100 +371,100 @@ describe('Sender API', () => { test('getLoginInfo', async () => { server.setResponse('get_login_info', userInfo) - await expect(sender.getLoginInfo()).resolves.to.have.shape(userInfo) + await expect(bot.getLoginInfo()).resolves.to.have.shape(userInfo) server.shouldHaveLastRequest('get_login_info', {}) }) test('getVipInfo', async () => { server.setResponse('_get_vip_info', userInfo) - await expect(sender.getVipInfo()).resolves.to.have.shape(userInfo) + await expect(bot.getVipInfo()).resolves.to.have.shape(userInfo) server.shouldHaveLastRequest('_get_vip_info', {}) }) test('getStrangerInfo', async () => { - await expect(sender.getStrangerInfo(undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.getStrangerInfo(undefined)).rejects.toHaveProperty('message', 'missing argument: userId') server.setResponse('get_stranger_info', userInfo) - await expect(sender.getStrangerInfo(123)).resolves.to.have.shape(userInfo) + await expect(bot.getStrangerInfo(123)).resolves.to.have.shape(userInfo) server.shouldHaveLastRequest('get_stranger_info', { userId: '123' }) - await expect(sender.getStrangerInfo(123, true)).resolves.to.have.shape(userInfo) + await expect(bot.getStrangerInfo(123, true)).resolves.to.have.shape(userInfo) server.shouldHaveLastRequest('get_stranger_info', { userId: '123', noCache: 'true' }) }) test('getFriendList', async () => { server.setResponse('get_friend_list', [userInfo]) - await expect(sender.getFriendList()).resolves.to.have.shape([userInfo]) + await expect(bot.getFriendList()).resolves.to.have.shape([userInfo]) server.shouldHaveLastRequest('get_friend_list', {}) }) test('getGroupInfo', async () => { - await expect(sender.getGroupInfo(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.getGroupInfo(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') server.setResponse('get_group_info', groupInfo) - await expect(sender.getGroupInfo(456)).resolves.to.have.shape(groupInfo) + await expect(bot.getGroupInfo(456)).resolves.to.have.shape(groupInfo) server.shouldHaveLastRequest('get_group_info', { groupId: '456' }) - await expect(sender.getGroupInfo(456, true)).resolves.to.have.shape(groupInfo) + await expect(bot.getGroupInfo(456, true)).resolves.to.have.shape(groupInfo) server.shouldHaveLastRequest('get_group_info', { groupId: '456', noCache: 'true' }) // < 4.12.0 - sender.app.version.pluginMajorVersion = 4 - sender.app.version.pluginMinorVersion = 11 + bot.app.version.pluginMajorVersion = 4 + bot.app.version.pluginMinorVersion = 11 server.setResponse('_get_group_info', groupInfo) - await expect(sender.getGroupInfo(456)).resolves.to.have.shape(groupInfo) + await expect(bot.getGroupInfo(456)).resolves.to.have.shape(groupInfo) server.shouldHaveLastRequest('_get_group_info', { groupId: '456' }) - await expect(sender.getGroupInfo(456, true)).resolves.to.have.shape(groupInfo) + await expect(bot.getGroupInfo(456, true)).resolves.to.have.shape(groupInfo) server.shouldHaveLastRequest('_get_group_info', { groupId: '456', noCache: 'true' }) // < 4.0.1 - sender.app.version.pluginMajorVersion = 3 - sender.app.version.pluginMinorVersion = 4 - await expect(sender.getGroupInfo(456)).rejects.toHaveProperty('message', 'sender.getGroupInfo() requires CQHTTP version >= 4.0.1') + bot.app.version.pluginMajorVersion = 3 + bot.app.version.pluginMinorVersion = 4 + await expect(bot.getGroupInfo(456)).rejects.toHaveProperty('message', 'bot.getGroupInfo() requires CQHTTP version >= 4.0.1') }) test('getGroupList', async () => { server.setResponse('get_group_list', [groupInfo]) - await expect(sender.getGroupList()).resolves.to.have.shape([groupInfo]) + await expect(bot.getGroupList()).resolves.to.have.shape([groupInfo]) server.shouldHaveLastRequest('get_group_list', {}) }) test('getGroupMemberInfo', async () => { - await expect(sender.getGroupMemberInfo(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.getGroupMemberInfo(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') + await expect(bot.getGroupMemberInfo(undefined, 123)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.getGroupMemberInfo(456, undefined)).rejects.toHaveProperty('message', 'missing argument: userId') server.setResponse('get_group_member_info', userInfo) - await expect(sender.getGroupMemberInfo(456, 123)).resolves.to.have.shape(userInfo) + await expect(bot.getGroupMemberInfo(456, 123)).resolves.to.have.shape(userInfo) server.shouldHaveLastRequest('get_group_member_info', { groupId: '456', userId: '123' }) - await expect(sender.getGroupMemberInfo(456, 123, true)).resolves.to.have.shape(userInfo) + await expect(bot.getGroupMemberInfo(456, 123, true)).resolves.to.have.shape(userInfo) server.shouldHaveLastRequest('get_group_member_info', { groupId: '456', userId: '123', noCache: 'true' }) }) test('getGroupMemberList', async () => { - await expect(sender.getGroupMemberList(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.getGroupMemberList(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') server.setResponse('get_group_member_list', [userInfo]) - await expect(sender.getGroupMemberList(456)).resolves.to.have.shape([userInfo]) + await expect(bot.getGroupMemberList(456)).resolves.to.have.shape([userInfo]) server.shouldHaveLastRequest('get_group_member_list', { groupId: '456' }) }) test('getGroupNotice', async () => { - await expect(sender.getGroupNotice(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.getGroupNotice(undefined)).rejects.toHaveProperty('message', 'missing argument: groupId') server.setResponse('_get_group_notice', groupInfo) - await expect(sender.getGroupNotice(456)).resolves.to.have.shape(groupInfo) + await expect(bot.getGroupNotice(456)).resolves.to.have.shape(groupInfo) server.shouldHaveLastRequest('_get_group_notice', { groupId: '456' }) }) test('sendGroupNotice', async () => { - await expect(sender.sendGroupNotice(undefined, 'foo', 'bar')).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.sendGroupNotice(456, undefined, 'bar')).rejects.toHaveProperty('message', 'missing argument: title') - await expect(sender.sendGroupNotice(456, 'foo', undefined)).rejects.toHaveProperty('message', 'missing argument: content') - await expect(sender.sendGroupNoticeAsync(undefined, 'foo', 'bar')).rejects.toHaveProperty('message', 'missing argument: groupId') - await expect(sender.sendGroupNoticeAsync(456, undefined, 'bar')).rejects.toHaveProperty('message', 'missing argument: title') - await expect(sender.sendGroupNoticeAsync(456, 'foo', undefined)).rejects.toHaveProperty('message', 'missing argument: content') - - await expect(sender.sendGroupNotice(456, 'foo', 'bar')).resolves.toBeUndefined() + await expect(bot.sendGroupNotice(undefined, 'foo', 'bar')).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.sendGroupNotice(456, undefined, 'bar')).rejects.toHaveProperty('message', 'missing argument: title') + await expect(bot.sendGroupNotice(456, 'foo', undefined)).rejects.toHaveProperty('message', 'missing argument: content') + await expect(bot.sendGroupNoticeAsync(undefined, 'foo', 'bar')).rejects.toHaveProperty('message', 'missing argument: groupId') + await expect(bot.sendGroupNoticeAsync(456, undefined, 'bar')).rejects.toHaveProperty('message', 'missing argument: title') + await expect(bot.sendGroupNoticeAsync(456, 'foo', undefined)).rejects.toHaveProperty('message', 'missing argument: content') + + await expect(bot.sendGroupNotice(456, 'foo', 'bar')).resolves.toBeUndefined() server.shouldHaveLastRequest('_send_group_notice', { groupId: '456', title: 'foo', content: 'bar' }) - await expect(sender.sendGroupNoticeAsync(456, 'foo', 'bar')).resolves.toBeUndefined() + await expect(bot.sendGroupNoticeAsync(456, 'foo', 'bar')).resolves.toBeUndefined() server.shouldHaveLastRequest('_send_group_notice_async', { groupId: '456', title: 'foo', content: 'bar' }) }) @@ -473,68 +473,68 @@ describe('Sender API', () => { test('getCookies', async () => { server.setResponse('get_cookies', { cookies }) - await expect(sender.getCookies()).resolves.to.equal(cookies) + await expect(bot.getCookies()).resolves.to.equal(cookies) server.shouldHaveLastRequest('get_cookies', {}) - await expect(sender.getCookies('foo')).resolves.to.equal(cookies) + await expect(bot.getCookies('foo')).resolves.to.equal(cookies) server.shouldHaveLastRequest('get_cookies', { domain: 'foo' }) }) test('getCsrfToken', async () => { server.setResponse('get_csrf_token', { token }) - await expect(sender.getCsrfToken()).resolves.to.equal(token) + await expect(bot.getCsrfToken()).resolves.to.equal(token) server.shouldHaveLastRequest('get_csrf_token', {}) }) test('getCredentials', async () => { const credentials = { cookies, token } server.setResponse('get_credentials', credentials) - await expect(sender.getCredentials()).resolves.to.have.shape(credentials) + await expect(bot.getCredentials()).resolves.to.have.shape(credentials) server.shouldHaveLastRequest('get_credentials', {}) }) const file = 'filename' test('getRecord', async () => { - await expect(sender.getRecord(undefined, 'mp3')).rejects.toHaveProperty('message', 'missing argument: file') - await expect(sender.getRecord('foo', undefined)).rejects.toHaveProperty('message', 'missing argument: outFormat') + await expect(bot.getRecord(undefined, 'mp3')).rejects.toHaveProperty('message', 'missing argument: file') + await expect(bot.getRecord('foo', undefined)).rejects.toHaveProperty('message', 'missing argument: outFormat') server.setResponse('get_record', { file }) - await expect(sender.getRecord('foo', 'mp3')).resolves.to.equal(file) + await expect(bot.getRecord('foo', 'mp3')).resolves.to.equal(file) server.shouldHaveLastRequest('get_record', { file: 'foo', outFormat: 'mp3' }) - await expect(sender.getRecord('foo', 'mp3', true)).resolves.to.equal(file) + await expect(bot.getRecord('foo', 'mp3', true)).resolves.to.equal(file) server.shouldHaveLastRequest('get_record', { file: 'foo', outFormat: 'mp3', fullPath: 'true' }) }) test('getImage', async () => { - await expect(sender.getImage(undefined)).rejects.toHaveProperty('message', 'missing argument: file') + await expect(bot.getImage(undefined)).rejects.toHaveProperty('message', 'missing argument: file') server.setResponse('get_image', { file }) - await expect(sender.getImage('foo')).resolves.to.equal(file) + await expect(bot.getImage('foo')).resolves.to.equal(file) server.shouldHaveLastRequest('get_image', { file: 'foo' }) }) test('canSendRecord', async () => { server.setResponse('can_send_record', { yes: true }) - await expect(sender.canSendRecord()).resolves.to.equal(true) + await expect(bot.canSendRecord()).resolves.to.equal(true) server.shouldHaveLastRequest('can_send_record', {}) }) test('canSendImage', async () => { server.setResponse('can_send_image', { yes: true }) - await expect(sender.canSendImage()).resolves.to.equal(true) + await expect(bot.canSendImage()).resolves.to.equal(true) server.shouldHaveLastRequest('can_send_image', {}) }) test('getStatus', async () => { const status = { good: true } server.setResponse('get_status', status) - await expect(sender.getStatus()).resolves.to.have.shape(status) + await expect(bot.getStatus()).resolves.to.have.shape(status) server.shouldHaveLastRequest('get_status', {}) }) test('getVersionInfo', async () => { server.setResponse('get_version_info', { pluginVersion: '4.12.3' }) - await expect(sender.getVersionInfo()).resolves.to.have.shape({ + await expect(bot.getVersionInfo()).resolves.to.have.shape({ pluginVersion: '4.12.3', pluginMajorVersion: 4, pluginMinorVersion: 12, @@ -544,33 +544,33 @@ describe('Sender API', () => { }) test('getStatus', async () => { - await expect(sender.setRestart()).resolves.toBeUndefined() + await expect(bot.setRestart()).resolves.toBeUndefined() server.shouldHaveLastRequest('_set_restart', { cleanLog: 'false', cleanCache: 'false', cleanEvent: 'false' }) - await expect(sender.setRestart(true, true, true)).resolves.toBeUndefined() + await expect(bot.setRestart(true, true, true)).resolves.toBeUndefined() server.shouldHaveLastRequest('_set_restart', { cleanLog: 'true', cleanCache: 'true', cleanEvent: 'true' }) }) test('setRestartPlugin', async () => { - await expect(sender.setRestartPlugin(10)).resolves.toBeUndefined() + await expect(bot.setRestartPlugin(10)).resolves.toBeUndefined() server.shouldHaveLastRequest('set_restart_plugin', { delay: '10' }) }) test('cleanDataDir', async () => { - await expect(sender.cleanDataDir(undefined)).rejects.toHaveProperty('message', 'missing argument: dataDir') - await expect(sender.cleanDataDir('foo' as any)).rejects.toHaveProperty('message', 'invalid argument: dataDir') - await expect(sender.cleanDataDirAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: dataDir') - await expect(sender.cleanDataDirAsync('foo' as any)).rejects.toHaveProperty('message', 'invalid argument: dataDir') + await expect(bot.cleanDataDir(undefined)).rejects.toHaveProperty('message', 'missing argument: dataDir') + await expect(bot.cleanDataDir('foo' as any)).rejects.toHaveProperty('message', 'invalid argument: dataDir') + await expect(bot.cleanDataDirAsync(undefined)).rejects.toHaveProperty('message', 'missing argument: dataDir') + await expect(bot.cleanDataDirAsync('foo' as any)).rejects.toHaveProperty('message', 'invalid argument: dataDir') - await expect(sender.cleanDataDir('image')).resolves.toBeUndefined() + await expect(bot.cleanDataDir('image')).resolves.toBeUndefined() server.shouldHaveLastRequest('clean_data_dir', { dataDir: 'image' }) - await expect(sender.cleanDataDirAsync('image')).resolves.toBeUndefined() + await expect(bot.cleanDataDirAsync('image')).resolves.toBeUndefined() server.shouldHaveLastRequest('clean_data_dir_async', { dataDir: 'image' }) }) test('cleanPluginLog', async () => { - await expect(sender.cleanPluginLog()).resolves.toBeUndefined() + await expect(bot.cleanPluginLog()).resolves.toBeUndefined() server.shouldHaveLastRequest('clean_plugin_log', {}) - await expect(sender.cleanPluginLogAsync()).resolves.toBeUndefined() + await expect(bot.cleanPluginLogAsync()).resolves.toBeUndefined() server.shouldHaveLastRequest('clean_plugin_log_async', {}) }) }) diff --git a/packages/adapter-tomon/package.json b/packages/adapter-tomon/package.json new file mode 100644 index 0000000000..4ddb316764 --- /dev/null +++ b/packages/adapter-tomon/package.json @@ -0,0 +1,41 @@ +{ + "name": "koishi-adapter-tomon", + "description": "Tomon adapter for Koishi", + "version": "0.1.0", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "files": [ + "dist" + ], + "author": "Shigma <1700011071@pku.edu.cn>", + "license": "MIT", + "scripts": { + "lint": "eslint src --ext .ts", + "precommit": "yarn lint", + "prepack": "tsc -b" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/koishijs/koishi.git" + }, + "bugs": { + "url": "https://github.com/koishijs/koishi/issues" + }, + "homepage": "https://github.com/koishijs/koishi/tree/master/packages/koishi-core#readme", + "keywords": [ + "bot", + "tomon", + "chatbot", + "koishi" + ], + "peerDependencies": { + "koishi-core": "^2.3.0" + }, + "devDependencies": { + "koishi-test-utils": "^5.0.1" + }, + "dependencies": { + "koishi-utils": "^3.1.5", + "tomon-sdk": "^0.2.0" + } +} diff --git a/packages/adapter-tomon/src/api.ts b/packages/adapter-tomon/src/api.ts new file mode 100644 index 0000000000..8973c742b3 --- /dev/null +++ b/packages/adapter-tomon/src/api.ts @@ -0,0 +1,13 @@ +import { Bot, Session } from 'koishi-core' + +Bot.prototype.sendGroupMsg = Bot.prototype.sendPrivateMsg = async function (this: Bot, channelId, content) { + if (!content) return + const data = await this.tomon.api.route(`/channels/${channelId}/messages`).post({ data: { content } }) + console.log(data) + return 0 +} + +Session.prototype.$send = async function $send(this: Session, message: string) { + if (!message) return + await this.$bot.sendPrivateMsg(this.channelId, message) +} diff --git a/packages/adapter-tomon/src/index.ts b/packages/adapter-tomon/src/index.ts new file mode 100644 index 0000000000..935e1edc42 --- /dev/null +++ b/packages/adapter-tomon/src/index.ts @@ -0,0 +1,49 @@ +import Tomon from 'tomon-sdk' +import { Bot, Server } from 'koishi-core' + +export * from './api' + +declare module 'koishi-core/dist/server' { + interface BotOptions { + token?: string + } + + interface Bot { + tomon?: Tomon + } +} + +declare module 'koishi-core/dist/session' { + interface Session { + channelId?: number + } +} + +Server.types.tomon = class TomonServer extends Server { + async __listen(bot: Bot) { + const tomon = bot.tomon = new Tomon() + await tomon.start(bot.token) + bot.ready = true + const selfId = bot.selfId = +tomon.discriminator + tomon.on('MESSAGE_CREATE', async ({ d }) => { + const userId = +d.author.discriminator + if (userId === selfId) return + const session = this.prepare({ + ...d, + selfId, + userId, + message: d.content, + postType: 'message', + messageType: d['guild_id'] ? 'group' : 'private', + groupId: d['guild_id'], + }) + this.dispatch(session) + }) + } + + async _listen() { + await Promise.all(this.bots.map(bot => this.__listen(bot))) + } + + _close() {} +} diff --git a/packages/adapter-tomon/tsconfig.json b/packages/adapter-tomon/tsconfig.json new file mode 100644 index 0000000000..a497f05e83 --- /dev/null +++ b/packages/adapter-tomon/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + }, + "include": [ + "src", + ], +} \ No newline at end of file diff --git a/packages/koishi-core/package.json b/packages/koishi-core/package.json index d1152edf91..7772992e41 100644 --- a/packages/koishi-core/package.json +++ b/packages/koishi-core/package.json @@ -1,7 +1,7 @@ { "name": "koishi-core", "description": "Core features for Koishi", - "version": "2.2.2", + "version": "2.3.0", "main": "dist/index.js", "typings": "dist/index.d.ts", "engines": { diff --git a/packages/koishi-core/src/context.ts b/packages/koishi-core/src/context.ts index 81ec3f8984..4b50aa82c7 100644 --- a/packages/koishi-core/src/context.ts +++ b/packages/koishi-core/src/context.ts @@ -308,57 +308,59 @@ export interface EventMap { [Context.MIDDLEWARE_EVENT]: Middleware // CQHTTP events - 'message' (session: RawSession<'message'>): void - 'message/normal' (session: RawSession<'message'>): void - 'message/notice' (session: RawSession<'message'>): void - 'message/anonymous' (session: RawSession<'message'>): void - 'message/friend' (session: RawSession<'message'>): void - 'message/group' (session: RawSession<'message'>): void - 'message/other' (session: RawSession<'message'>): void - 'friend-add' (session: RawSession<'notice'>): void - 'group-increase' (session: RawSession<'notice'>): void - 'group-increase/invite' (session: RawSession<'notice'>): void - 'group-increase/approve' (session: RawSession<'notice'>): void - 'group-decrease' (session: RawSession<'notice'>): void - 'group-decrease/leave' (session: RawSession<'notice'>): void - 'group-decrease/kick' (session: RawSession<'notice'>): void - 'group-decrease/kick-me' (session: RawSession<'notice'>): void - 'group-upload' (session: RawSession<'notice'>): void - 'group-admin' (session: RawSession<'notice'>): void - 'group-admin/set' (session: RawSession<'notice'>): void - 'group-admin/unset' (session: RawSession<'notice'>): void - 'group-ban' (session: RawSession<'notice'>): void - 'group-ban/ban' (session: RawSession<'notice'>): void - 'group-ban/lift-ban' (session: RawSession<'notice'>): void - 'group_recall' (session: RawSession<'notice'>): void - 'request/friend' (session: RawSession<'request'>): void - 'request/group/add' (session: RawSession<'request'>): void - 'request/group/invite' (session: RawSession<'request'>): void - 'heartbeat' (session: RawSession<'meta_event'>): void - 'lifecycle' (session: RawSession<'meta_event'>): void - 'lifecycle/enable' (session: RawSession<'meta_event'>): void - 'lifecycle/disable' (session: RawSession<'meta_event'>): void - 'lifecycle/connect' (session: RawSession<'meta_event'>): void + 'message'(session: RawSession<'message'>): void + 'message/normal'(session: RawSession<'message'>): void + 'message/notice'(session: RawSession<'message'>): void + 'message/anonymous'(session: RawSession<'message'>): void + 'message/friend'(session: RawSession<'message'>): void + 'message/group'(session: RawSession<'message'>): void + 'message/other'(session: RawSession<'message'>): void + 'friend-add'(session: RawSession<'notice'>): void + 'group-increase'(session: RawSession<'notice'>): void + 'group-increase/invite'(session: RawSession<'notice'>): void + 'group-increase/approve'(session: RawSession<'notice'>): void + 'group-decrease'(session: RawSession<'notice'>): void + 'group-decrease/leave'(session: RawSession<'notice'>): void + 'group-decrease/kick'(session: RawSession<'notice'>): void + 'group-decrease/kick-me'(session: RawSession<'notice'>): void + 'group-upload'(session: RawSession<'notice'>): void + 'group-admin'(session: RawSession<'notice'>): void + 'group-admin/set'(session: RawSession<'notice'>): void + 'group-admin/unset'(session: RawSession<'notice'>): void + 'group-ban'(session: RawSession<'notice'>): void + 'group-ban/ban'(session: RawSession<'notice'>): void + 'group-ban/lift-ban'(session: RawSession<'notice'>): void + 'group_recall'(session: RawSession<'notice'>): void + 'friend_recall'(session: RawSession<'notice'>): void + 'notify'(session: RawSession<'notice'>): void + 'request/friend'(session: RawSession<'request'>): void + 'request/group/add'(session: RawSession<'request'>): void + 'request/group/invite'(session: RawSession<'request'>): void + 'heartbeat'(session: RawSession<'meta_event'>): void + 'lifecycle'(session: RawSession<'meta_event'>): void + 'lifecycle/enable'(session: RawSession<'meta_event'>): void + 'lifecycle/disable'(session: RawSession<'meta_event'>): void + 'lifecycle/connect'(session: RawSession<'meta_event'>): void // Koishi events - 'parse' (message: string, session: Session, builtin: boolean, terminator: string): void | ExecuteArgv - 'before-attach-user' (session: Session, fields: Set): void - 'before-attach-group' (session: Session, fields: Set): void - 'attach-user' (session: Session): void | boolean | Promise - 'attach-group' (session: Session): void | boolean | Promise - 'attach' (session: Session): void | Promise - 'send' (session: Session): void | Promise - 'before-send' (session: Session): void | boolean - 'before-command' (argv: ParsedArgv): void | string | Promise - 'command' (argv: ParsedArgv): void | Promise - 'middleware' (session: Session): void - 'new-command' (cmd: Command): void - 'remove-command' (cmd: Command): void - 'before-connect' (): void | Promise - 'connect' (): void - 'before-disconnect' (): void | Promise - 'disconnect' (): void - 'dispose' (): void + 'parse'(message: string, session: Session, builtin: boolean, terminator: string): void | ExecuteArgv + 'before-attach-user'(session: Session, fields: Set): void + 'before-attach-group'(session: Session, fields: Set): void + 'attach-user'(session: Session): void | boolean | Promise + 'attach-group'(session: Session): void | boolean | Promise + 'attach'(session: Session): void | Promise + 'send'(session: Session): void | Promise + 'before-send'(session: Session): void | boolean + 'before-command'(argv: ParsedArgv): void | string | Promise + 'command'(argv: ParsedArgv): void | Promise + 'middleware'(session: Session): void + 'new-command'(cmd: Command): void + 'remove-command'(cmd: Command): void + 'before-connect'(): void | Promise + 'connect'(): void + 'before-disconnect'(): void | Promise + 'disconnect'(): void + 'dispose'(): void } export type Events = keyof EventMap diff --git a/packages/koishi-core/src/session.ts b/packages/koishi-core/src/session.ts index 17acdc01fe..78e5b07138 100644 --- a/packages/koishi-core/src/session.ts +++ b/packages/koishi-core/src/session.ts @@ -8,7 +8,7 @@ export type PostType = 'message' | 'notice' | 'request' | 'meta_event' | 'send' export type MessageType = 'private' | 'group' export type NoticeType = | 'group_upload' | 'group_admin' | 'group_increase' | 'group_decrease' - | 'group_ban' | 'friend_add' | 'group_recall' + | 'group_ban' | 'friend_add' | 'group_recall' | 'friend_recall' | 'notify' export type RequestType = 'friend' | 'group' export type MetaEventType = 'lifecycle' | 'heartbeat' @@ -23,7 +23,9 @@ export interface MetaTypeMap { export interface SubTypeMap { message: 'friend' | 'group' | 'other' | 'normal' | 'anonymous' | 'notice' - notice: 'set' | 'unset' | 'approve' | 'invite' | 'leave' | 'kick' | 'kick_me' | 'ban' | 'lift_ban' + notice: + | 'set' | 'unset' | 'approve' | 'invite' | 'leave' | 'kick' | 'kick_me' + | 'ban' | 'lift_ban' | 'poke' | 'lucky_king' | 'honor' request: 'add' | 'invite' // eslint-disable-next-line camelcase meta_event: 'enable' | 'disable' | 'connect' @@ -57,8 +59,10 @@ export interface Meta

{ // notice event operatorId?: number + targetId?: number duration?: number file?: FileInfo + honorType?: 'talkative' | 'performer' | 'emotion' // request event comment?: string @@ -85,11 +89,13 @@ export class Session void)[] = [] + private _queued: Promise + private _hooks: (() => void)[] constructor(app: App, session: Partial) { defineProperty(this, '$app', app) + defineProperty(this, '_queued', Promise.resolve()) + defineProperty(this, '_hooks', []) Object.assign(this, session) } diff --git a/packages/koishi-test-utils/package.json b/packages/koishi-test-utils/package.json index 3f902cb013..26fa25ab42 100644 --- a/packages/koishi-test-utils/package.json +++ b/packages/koishi-test-utils/package.json @@ -40,7 +40,7 @@ "dependencies": { "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "koishi-core": "^2.2.2", + "koishi-core": "^2.3.0", "koishi-utils": "^3.1.5" }, "devDependencies": { diff --git a/packages/koishi/ecosystem.json b/packages/koishi/ecosystem.json index 57a6cd433b..640a1a8075 100644 --- a/packages/koishi/ecosystem.json +++ b/packages/koishi/ecosystem.json @@ -1,14 +1,18 @@ { "koishi-adapter-cqhttp": { - "version": "1.0.3", + "version": "1.0.4", "description": "CQHTTP adapter for Koishi" }, + "koishi-adapter-tomon": { + "version": "0.1.0", + "description": "Tomon adapter for Koishi" + }, "koishi-plugin-chess": { "version": "2.0.0-beta.10", "description": "Chess Plugin for Koishi" }, "koishi-plugin-common": { - "version": "3.0.0", + "version": "3.0.1", "description": "Common plugins for Koishi" }, "koishi-plugin-eval": { @@ -20,7 +24,7 @@ "description": "Execute JavaScript in Koishi" }, "koishi-plugin-github": { - "version": "2.0.3", + "version": "2.1.0", "description": "GitHub webhook plugin for Koishi" }, "koishi-plugin-image-search": { @@ -55,10 +59,10 @@ "description": "Show Status of Koishi" }, "koishi-plugin-teach": { - "version": "1.0.4", + "version": "1.1.0", "description": "Teach plugin for Koishi" }, "koishi-plugin-tools": { - "version": "1.0.0" + "version": "1.0.1" } } diff --git a/packages/koishi/package.json b/packages/koishi/package.json index 2635fe2185..bcad87c227 100644 --- a/packages/koishi/package.json +++ b/packages/koishi/package.json @@ -1,7 +1,7 @@ { "name": "koishi", "description": "A QQ bot framework based on CQHTTP", - "version": "2.2.2", + "version": "2.3.0", "main": "dist/index.js", "typings": "dist/index.d.ts", "engines": { @@ -40,9 +40,9 @@ "dependencies": { "cac": "^6.6.1", "kleur": "^4.1.1", - "koishi-adapter-cqhttp": "^1.0.3", - "koishi-core": "^2.2.2", - "koishi-plugin-common": "^3.0.0", + "koishi-adapter-cqhttp": "^1.0.4", + "koishi-core": "^2.3.0", + "koishi-plugin-common": "^3.0.1", "prompts": "^2.3.2" } } diff --git a/packages/koishi/src/init.ts b/packages/koishi/src/init.ts index 9ada23aaa1..8f02658ab4 100644 --- a/packages/koishi/src/init.ts +++ b/packages/koishi/src/init.ts @@ -3,6 +3,8 @@ import { yellow, red, green } from 'kleur' import { resolve, extname, dirname } from 'path' import { AppConfig } from './worker' import { CAC } from 'cac' +import {} from 'koishi-adapter-cqhttp' +import {} from 'koishi-adapter-tomon' import prompts, { Choice, PrevCaller, PromptObject } from 'prompts' import * as mysql from 'koishi-plugin-mysql/dist/database' import * as mongo from 'koishi-plugin-mongo/dist/database' @@ -14,21 +16,24 @@ function conditional(type: T, key: string, ...va } } -const serverQuestions: PromptObject[] = [{ +const serverQuestions: PromptObject[] = [{ name: 'type', type: 'select', message: 'Server Type', choices: [ - { title: 'HTTP', value: 'cqhttp:http' }, - { title: 'WebSocket', value: 'cqhttp:ws' }, - { title: 'WebSocket Reverse', value: 'cqhttp:ws-reverse' }, + { title: 'QQ (OneBot, HTTP)', value: 'cqhttp:http' }, + { title: 'QQ (OneBot, WebSocket)', value: 'cqhttp:ws' }, + { title: 'QQ (OneBot, WebSocket Reverse)', value: 'cqhttp:ws-reverse' }, + { title: 'Tomon', value: 'tomon' }, ], }, { name: 'port', - type: conditional('number', 'type', 'cqhttp:http', 'cqhttp:ws-reverse'), + type: 'number', message: 'Koishi Port', initial: 8080, -}, { +}] + +const cqhttpQuestions: PromptObject[] = [{ name: 'path', type: conditional('text', 'type', 'cqhttp:http', 'cqhttp:ws-reverse'), message: 'Koishi Path', @@ -55,7 +60,22 @@ const serverQuestions: PromptObject[] = [{ name: 'token', type: 'text', message: 'Token for CQHTTP Server', -}, { +}] + +const tomonQuestions: PromptObject[] = [{ + name: 'token', + type: 'text', + message: 'Token for Tomon', +}] + +const adapterMap = { + 'cqhttp:http': cqhttpQuestions, + 'cqhttp:ws': cqhttpQuestions, + 'cqhttp:ws-reverse': cqhttpQuestions, + tomon: tomonQuestions, +} + +const databaseQuestions: PromptObject<'database'>[] = [{ name: 'database', type: 'select', message: 'Database Type', @@ -118,7 +138,7 @@ const mongoQuestions: PromptObject[] = [{ initial: 'koishi', }] -const dbQuestionMap = { +const databaseMap = { mysql: mysqlQuestions, mongo: mongoQuestions, } @@ -143,20 +163,21 @@ const ecosystem: Record = require('../ecosystem') const builtinPackages = ['koishi-plugin-common'] async function createConfig() { - const data = await question(serverQuestions) - const { database } = data - const config = { ...data, database: undefined, plugins: [] } as AppConfig + const config: AppConfig = { plugins: [] } + Object.assign(config, await question(serverQuestions)) + Object.assign(config, await question(adapterMap[config.type])) // database + const { database } = await question(databaseQuestions) if (database) { - config.plugins.push([database, await question(dbQuestionMap[database])]) + config.plugins.push([database, await question(databaseMap[database])]) } // official plugins const choices: Choice[] = Object.entries(ecosystem).map(([title, meta]) => { if (!title.startsWith('koishi-plugin-')) return const value = title.slice(14) - if (value in dbQuestionMap) return + if (value in databaseMap) return const { description } = meta const selected = builtinPackages.includes(title) return { title, value, description, selected } @@ -195,7 +216,7 @@ async function updateMeta(config: AppConfig) { } if (!modified) return await fs.writeFile(path, JSON.stringify(meta, null, 2)) - console.log(`${success} package.json was updated`) + console.log(`${success} package.json was updated, type "npm install" to install new dependencies`) } type Serializable = string | number | Serializable[] | { [key: string]: Serializable } diff --git a/packages/koishi/src/worker.ts b/packages/koishi/src/worker.ts index fe56ad8f7d..05699bfdd4 100644 --- a/packages/koishi/src/worker.ts +++ b/packages/koishi/src/worker.ts @@ -3,7 +3,6 @@ import { resolve, dirname } from 'path' import { Logger, noop } from 'koishi-utils' import { performance } from 'perf_hooks' import { yellow } from 'kleur' -import 'koishi-adapter-cqhttp' const logger = new Logger('app') const { version } = require('../package') @@ -56,11 +55,11 @@ if (!config) { const cacheMap: Record = {} -function loadEcosystem(name: string) { +function loadEcosystem(type: string, name: string) { const cache = cacheMap[name] if (cache) return cache - const prefix = 'koishi-plugin-' + const prefix = `koishi-${type}-` const modules: string[] = [] if (name.startsWith('.')) { modules.push(resolve(configDir, name)) @@ -74,7 +73,7 @@ function loadEcosystem(name: string) { logger.debug('resolving %c', path) try { const result = require(path) - logger.info('apply plugin %c', result.name || name) + logger.info('apply %s %c', type, result.name || name) return cacheMap[name] = result } catch (error) { if (isErrorModule(error)) { @@ -82,22 +81,7 @@ function loadEcosystem(name: string) { } } } - throw new Error(`cannot resolve plugin ${name}`) -} - -function loadPlugins(ctx: Context, plugins: PluginConfig) { - for (const item of plugins) { - let plugin: Plugin, options: any - if (Array.isArray(item)) { - plugin = typeof item[0] === 'string' ? loadEcosystem(item[0]) : item[0] - options = item[1] - } else if (typeof item === 'string') { - plugin = loadEcosystem(item) - } else { - plugin = item - } - ctx.plugin(plugin, options) - } + throw new Error(`cannot resolve ${type} ${name}`) } Object.assign(Logger.levels, config.logFilter) @@ -139,8 +123,26 @@ app.command('exit', '停止机器人运行', { authority: 4 }) process.exit(514) }) +// load adapter +try { + const [name] = config.type.split('.', 1) + loadEcosystem('adapter', name) +} catch {} + +// load plugins if (Array.isArray(config.plugins)) { - loadPlugins(app, config.plugins) + for (const item of config.plugins) { + let plugin: Plugin, options: any + if (Array.isArray(item)) { + plugin = typeof item[0] === 'string' ? loadEcosystem('plugin', item[0]) : item[0] + options = item[1] + } else if (typeof item === 'string') { + plugin = loadEcosystem('plugin', item) + } else { + plugin = item + } + app.plugin(plugin, options) + } } process.on('unhandledRejection', (error) => { diff --git a/packages/plugin-chess/package.json b/packages/plugin-chess/package.json index 1beb19af50..7e5f427fe5 100644 --- a/packages/plugin-chess/package.json +++ b/packages/plugin-chess/package.json @@ -33,7 +33,7 @@ "game" ], "peerDependencies": { - "koishi-core": "^2.2.2", + "koishi-core": "^2.3.0", "koishi-plugin-puppeteer": "^1.0.0" }, "dependencies": { diff --git a/packages/plugin-common/package.json b/packages/plugin-common/package.json index 44f67f710d..c861cd4655 100644 --- a/packages/plugin-common/package.json +++ b/packages/plugin-common/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-common", "description": "Common plugins for Koishi", - "version": "3.0.0", + "version": "3.0.1", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -31,7 +31,7 @@ "plugin" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "devDependencies": { "koishi-test-utils": "^5.0.1" diff --git a/packages/plugin-common/src/debug.ts b/packages/plugin-common/src/debug.ts index a017a03f35..07026c35a1 100644 --- a/packages/plugin-common/src/debug.ts +++ b/packages/plugin-common/src/debug.ts @@ -1,4 +1,4 @@ -import { Context, Session } from 'koishi-core' +import { Context, RawSession, Session } from 'koishi-core' import { Logger, CQCode, Time } from 'koishi-utils' import {} from 'koishi-adapter-cqhttp' @@ -7,6 +7,8 @@ export interface DebugOptions { showGroupId?: boolean refreshUserName?: number refreshGroupName?: number + includeUsers?: number[] + includeGroups?: number[] } const cqTypes = { @@ -25,7 +27,15 @@ const cqTypes = { } export function apply(ctx: Context, config: DebugOptions = {}) { - const { refreshUserName = Time.hour, refreshGroupName = Time.hour, showUserId, showGroupId } = config + const { + refreshUserName = Time.hour, + refreshGroupName = Time.hour, + includeUsers = [], + includeGroups = [], + showUserId, + showGroupId, + } = config + const logger = new Logger('message', true) Logger.levels.message = 3 @@ -90,10 +100,18 @@ export function apply(ctx: Context, config: DebugOptions = {}) { Logger.lastTime = Date.now() }) - ctx.on('message', async (session) => { + async function onMessage(session: RawSession<'message'>) { const groupName = await getGroupName(session) const senderName = getSenderName(session) const message = await formatMessage(session) logger.debug(`[${groupName}] ${senderName}: ${message}`) - }) + } + + if (includeUsers) { + ctx.private(...includeUsers).on('message', onMessage) + } + + if (includeGroups) { + ctx.group(...includeGroups).on('message', onMessage) + } } diff --git a/packages/plugin-common/src/handler.ts b/packages/plugin-common/src/handler.ts index a0c4616a03..348fe9a10b 100644 --- a/packages/plugin-common/src/handler.ts +++ b/packages/plugin-common/src/handler.ts @@ -22,7 +22,6 @@ export interface HandlerOptions { onFriend?: RequestHandler onGroupAdd?: RequestHandler onGroupInvite?: RequestHandler - blackList?: string[] respondents?: Respondent[] throttle?: ThrottleConfig | ThrottleConfig[] welcome?: WelcomeMessage @@ -50,14 +49,7 @@ export default function apply(ctx: App, options: HandlerOptions = {}) { return result !== undefined && session.$bot.setGroupAddRequest(session.flag, session.subType, result) }) - const { blackList = [], respondents = [], welcome = defaultMessage } = options - - blackList.length && ctx.prependMiddleware((session, next) => { - for (const word of blackList) { - if (session.message.includes(word)) return - } - return next() - }) + const { respondents = [], welcome = defaultMessage } = options respondents.length && ctx.middleware((session, next) => { const message = simplify(session.message) diff --git a/packages/plugin-common/src/index.ts b/packages/plugin-common/src/index.ts index 8f043a7102..afb5330851 100644 --- a/packages/plugin-common/src/index.ts +++ b/packages/plugin-common/src/index.ts @@ -20,6 +20,9 @@ export function apply(ctx: Context, config: Config = {}) { ctx.plugin(sender, config) ctx.plugin(require('./admin')) - ctx.plugin(require('./debug'), config.debug) ctx.plugin(require('./info')) + + if (config.debug) { + ctx.plugin(require('./debug'), config.debug) + } } diff --git a/packages/plugin-common/src/sender.ts b/packages/plugin-common/src/sender.ts index 6705b87cf7..6680c45d54 100644 --- a/packages/plugin-common/src/sender.ts +++ b/packages/plugin-common/src/sender.ts @@ -46,7 +46,7 @@ export default function apply(ctx: Context, config: SenderConfig = {}) { const interactions: Record = {} - config.operator && ctx.command('feedback', '发送反馈信息给作者') + config.operator && ctx.command('feedback ', '发送反馈信息给作者') .userFields(['name', 'id']) .action(async ({ session }, text) => { if (!text) return '请输入要发送的文本。' diff --git a/packages/plugin-common/tests/handler.spec.ts b/packages/plugin-common/tests/handler.spec.ts index 06f21c291c..8c2e278785 100644 --- a/packages/plugin-common/tests/handler.spec.ts +++ b/packages/plugin-common/tests/handler.spec.ts @@ -3,14 +3,27 @@ import { fn } from 'jest-mock' import { Meta } from 'koishi-core' import { App } from 'koishi-test-utils' import { sleep } from 'koishi-utils' +import {} from 'koishi-adapter-cqhttp' import * as common from 'koishi-plugin-common' const app = new App({ mockDatabase: true }) -const options: common.Config = {} + +const options: common.Config = { + respondents: [{ + match: '挖坑一时爽', + reply: '填坑火葬场', + }, { + match: /^(.+)一时爽$/, + reply: (_, action) => `一直${action}一直爽`, + }], +} + +const session = app.session(123) app.plugin(common, options) before(async () => { + await app.database.getUser(123, 3) await app.database.getGroup(123, app.selfId) }) @@ -125,6 +138,12 @@ describe('Common Handlers', () => { expect(setGroupAddRequest.mock.calls).to.have.shape([['flag', 'invite', true]]) }) + it('respondent', async () => { + await session.shouldReply('挖坑一时爽', '填坑火葬场') + await session.shouldReply('填坑一时爽', '一直填坑一直爽') + await session.shouldNotReply('填坑一直爽') + }) + it('welcome', async () => { sendGroupMsg.mockClear() await receiveGroupIncrease(321, 456) diff --git a/packages/plugin-common/tests/respondent.spec.ts b/packages/plugin-common/tests/respondent.spec.ts deleted file mode 100644 index 0696e8f908..0000000000 --- a/packages/plugin-common/tests/respondent.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MockedApp } from 'koishi-test-utils' -import { respondent } from '../src' - -const app = new MockedApp() -const session = app.session(123) - -// make coverage happy -app.plugin(respondent) -app.plugin(respondent, [{ - match: '挖坑一时爽', - reply: '填坑火葬场', -}, { - match: /^(.+)一时爽$/, - reply: (_, action) => `一直${action}一直爽`, -}]) - -it('basic support', async () => { - await session.shouldReply('挖坑一时爽', '填坑火葬场') - await session.shouldReply('填坑一时爽', '一直填坑一直爽') - await session.shouldNotReply('填坑一直爽') -}) diff --git a/packages/plugin-eval-addons/package.json b/packages/plugin-eval-addons/package.json index b53e5a2ffd..6bd7ecfb91 100644 --- a/packages/plugin-eval-addons/package.json +++ b/packages/plugin-eval-addons/package.json @@ -36,7 +36,7 @@ "code" ], "peerDependencies": { - "koishi-core": "^2.2.2", + "koishi-core": "^2.3.0", "koishi-plugin-eval": "^2.0.1" }, "dependencies": { diff --git a/packages/plugin-eval/package.json b/packages/plugin-eval/package.json index d1964ba7ce..41848fd413 100644 --- a/packages/plugin-eval/package.json +++ b/packages/plugin-eval/package.json @@ -37,7 +37,7 @@ "code" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "devDependencies": { "koishi-test-utils": "^5.0.1" diff --git a/packages/plugin-github/package.json b/packages/plugin-github/package.json index 2167e9317d..666370816d 100644 --- a/packages/plugin-github/package.json +++ b/packages/plugin-github/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-github", "description": "GitHub webhook plugin for Koishi", - "version": "2.0.3", + "version": "2.1.0", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -36,7 +36,7 @@ "koishi-test-utils": "^5.0.1" }, "peerDependencies": { - "koishi-core": "^2.2.2", + "koishi-core": "^2.3.0", "koishi-plugin-puppeteer": "^1.0.0" }, "dependencies": { diff --git a/packages/plugin-github/src/events.ts b/packages/plugin-github/src/events.ts index 1d28126cd0..b385788a07 100644 --- a/packages/plugin-github/src/events.ts +++ b/packages/plugin-github/src/events.ts @@ -93,7 +93,8 @@ export const defaultEvents: EventConfig = { }, } -export interface ReplyPayloads { +export interface EventData { + message?: string link?: string react?: string reply?: [url: string, params?: Record] @@ -105,7 +106,7 @@ export interface ReplyPayloads { } type Payload = GetWebhookPayloadTypeFromEvent['payload'] -type EventHandler = (payload: Payload) => [message: string, replies?: ReplyPayloads] +type EventHandler = (payload: Payload) => EventData export function addListeners(on: (event: T, handler: EventHandler) => void) { function formatMarkdown(source: string) { @@ -114,12 +115,12 @@ export function addListeners(on: (event: T, handler: E .replace(/\n\s*\n/g, '\n') } - interface CommantReplyPayloads extends ReplyPayloads { + interface CommentReplyPayloads extends EventData { padding?: number[] } type CommentEvent = 'commit_comment' | 'issue_comment' | 'pull_request_review_comment' - type CommantHandler = (payload: Payload) => [target: string, replies: CommantReplyPayloads] + type CommantHandler = (payload: Payload) => [target: string, replies: CommentReplyPayloads] function onComment(event: E, handler: CommantHandler) { on(event as CommentEvent, (payload) => { @@ -128,12 +129,13 @@ export function addListeners(on: (event: T, handler: E const [target, replies] = handler(payload) if (payload.action === 'deleted') { - return [`[GitHub] ${user.login} deleted a comment on ${target}`] + return { message: `${user.login} deleted a comment on ${target}` } } const index = html_url.indexOf('#') const operation = payload.action === 'created' ? 'commented' : 'edited a comment' - return [`[GitHub] ${user.login} ${operation} on ${target}\n${formatMarkdown(body)}`, { + return { + message: `${user.login} ${operation} on ${target}\n${formatMarkdown(body)}`, link: html_url, react: url + `/reactions`, shot: { @@ -142,7 +144,7 @@ export function addListeners(on: (event: T, handler: E padding: replies.padding, }, ...replies, - }] + } }) } @@ -157,7 +159,9 @@ export function addListeners(on: (event: T, handler: E on('fork', ({ repository, sender, forkee }) => { const { full_name, forks_count } = repository - return [`[GitHub] ${sender.login} forked ${full_name} to ${forkee.full_name} (total ${forks_count} forks)`] + return { + message: `${sender.login} forked ${full_name} to ${forkee.full_name} (total ${forks_count} forks)`, + } }) onComment('issue_comment', ({ issue, repository }) => { @@ -175,15 +179,16 @@ export function addListeners(on: (event: T, handler: E const { user, url, html_url, comments_url, title, body, number } = issue if (user.type === 'Bot') return - return [[ - `[GitHub] ${user.login} opened an issue ${full_name}#${number}`, - `Title: ${title}`, - formatMarkdown(body), - ].join('\n'), { + return { + message: [ + `${user.login} opened an issue ${full_name}#${number}`, + `Title: ${title}`, + formatMarkdown(body), + ].join('\n'), link: html_url, react: url + `/reactions`, reply: [comments_url], - }] + } }) on('issues.closed', ({ repository, issue }) => { @@ -191,11 +196,12 @@ export function addListeners(on: (event: T, handler: E const { user, url, html_url, comments_url, title, number } = issue if (user.type === 'Bot') return - return [`[GitHub] ${user.login} closed issue ${full_name}#${number}\n${title}`, { + return { + message: `${user.login} closed issue ${full_name}#${number}\n${title}`, link: html_url, react: url + `/reactions`, reply: [comments_url], - }] + } }) onComment('pull_request_review_comment', ({ repository, comment, pull_request }) => { @@ -214,10 +220,14 @@ export function addListeners(on: (event: T, handler: E const { user, html_url, body } = review if (user.type === 'Bot') return - return [[ - `[GitHub] ${user.login} reviewed pull request ${full_name}#${number}`, - formatMarkdown(body), - ].join('\n'), { link: html_url, reply: [comments_url] }] + return { + message: [ + `${user.login} reviewed pull request ${full_name}#${number}`, + formatMarkdown(body), + ].join('\n'), + link: html_url, + reply: [comments_url], + } }) on('pull_request.closed', ({ repository, pull_request, sender }) => { @@ -225,11 +235,12 @@ export function addListeners(on: (event: T, handler: E const { html_url, issue_url, comments_url, title, number, merged } = pull_request const type = merged ? 'merged' : 'closed' - return [`[GitHub] ${sender.login} ${type} pull request ${full_name}#${number}\n${title}`, { + return { + message: `${sender.login} ${type} pull request ${full_name}#${number}\n${title}`, link: html_url, react: issue_url + '/reactions', reply: [comments_url], - }] + } }) on('pull_request.opened', ({ repository, pull_request }) => { @@ -240,15 +251,16 @@ export function addListeners(on: (event: T, handler: E const prefix = new RegExp(`^${owner.login}:`) const baseLabel = base.label.replace(prefix, '') const headLabel = head.label.replace(prefix, '') - return [[ - `[GitHub] ${user.login} opened a pull request ${full_name}#${number} (${baseLabel} <- ${headLabel})`, - `Title: ${title}`, - formatMarkdown(body), - ].join('\n'), { + return { + message: [ + `${user.login} opened a pull request ${full_name}#${number} (${baseLabel} <- ${headLabel})`, + `Title: ${title}`, + formatMarkdown(body), + ].join('\n'), link: html_url, react: issue_url + '/reactions', reply: [comments_url], - }] + } }) on('push', ({ compare, pusher, commits, repository, ref, after }) => { @@ -259,17 +271,24 @@ export function addListeners(on: (event: T, handler: E // use short form for tag releases if (ref.startsWith('refs/tags')) { - return [`[GitHub] ${pusher.name} published tag ${full_name}@${ref.slice(10)}`] + return { + message: `${pusher.name} published tag ${full_name}@${ref.slice(10)}`, + } } - return [[ - `[GitHub] ${pusher.name} pushed to ${full_name}:${ref.replace(/^refs\/heads\//, '')}`, - ...commits.map(c => `[${c.id.slice(0, 6)}] ${formatMarkdown(c.message)}`), - ].join('\n'), { link: compare }] + return { + message: [ + `${pusher.name} pushed to ${full_name}:${ref.replace(/^refs\/heads\//, '')}`, + ...commits.map(c => `[${c.id.slice(0, 6)}] ${formatMarkdown(c.message)}`), + ].join('\n'), + link: compare, + } }) on('star.created', ({ repository, sender }) => { const { full_name, stargazers_count } = repository - return [`[GitHub] ${sender.login} starred ${full_name} (total ${stargazers_count} stargazers)`] + return { + message: `${sender.login} starred ${full_name} (total ${stargazers_count} stargazers)`, + } }) } diff --git a/packages/plugin-github/src/index.ts b/packages/plugin-github/src/index.ts index f1a8397898..68e5974c6e 100644 --- a/packages/plugin-github/src/index.ts +++ b/packages/plugin-github/src/index.ts @@ -4,7 +4,7 @@ import { Context, Session } from 'koishi-core' import { camelize, CQCode, defineProperty, Logger, Time } from 'koishi-utils' import { encode } from 'querystring' -import { addListeners, defaultEvents, ReplyPayloads } from './events' +import { addListeners, defaultEvents, EventData } from './events' import { Config, GitHub } from './server' import {} from 'koishi-plugin-puppeteer' @@ -17,12 +17,13 @@ declare module 'koishi-core/dist/app' { } type ReplyHandlers = { - [K in keyof ReplyPayloads]: (payload: ReplyPayloads[K], session: Session, message: string) => Promise + [K in keyof EventData]: (payload: EventData[K], session: Session, message: string) => Promise } const defaultOptions: Config = { secret: '', - prefix: '.', + replyPrefix: '.', + messagePrefix: '[GitHub] ', webhook: '/github/webhook', authorize: '/github/authorize', replyTimeout: Time.hour, @@ -35,7 +36,7 @@ export const name = 'github' export function apply(ctx: Context, config: Config = {}) { config = { ...defaultOptions, ...config } const { app, database, router } = ctx - const { appId, prefix, redirect, webhook } = config + const { appId, replyPrefix, redirect, webhook } = config const github = new GitHub(config) defineProperty(app, 'github', github) @@ -55,7 +56,9 @@ export function apply(ctx: Context, config: Config = {}) { return ctx.status = 200 }) - ctx.command('github ', '授权 GitHub 功能') + ctx.command('github', 'GitHub 相关功能') + + ctx.command('github.authorize ', 'GitHub 授权') .action(async ({ session }, user) => { if (!user) return '请输入用户名。' const url = 'https://github.com/login/oauth/authorize?' + encode({ @@ -68,6 +71,16 @@ export function apply(ctx: Context, config: Config = {}) { return '请点击下面的链接继续操作:\n' + url }) + ctx.command('github.recent', '查看最近的通知') + .action(async () => { + const output = Object.entries(history).slice(0, 10).map(([messageId, payload]) => { + const [brief] = payload.message.split('\n', 1) + return `${messageId}. ${brief}` + }) + if (!output.length) return '最近没有 GitHub 通知。' + return output.join('\n') + }) + const reactions = ['+1', '-1', 'laugh', 'confused', 'heart', 'hooray', 'rocket', 'eyes'] function formatReply(source: string) { @@ -114,7 +127,7 @@ export function apply(ctx: Context, config: Config = {}) { }, } - const interactions: Record = {} + const history: Record = {} router.post(webhook, (ctx, next) => { // workaround @octokit/webhooks for koa @@ -124,7 +137,7 @@ export function apply(ctx: Context, config: Config = {}) { }) ctx.on('before-attach-user', (session, fields) => { - if (interactions[session.$reply]) { + if (history[int32ToHex6(session.$reply)]) { fields.add('ghAccessToken') fields.add('ghRefreshToken') } @@ -132,13 +145,13 @@ export function apply(ctx: Context, config: Config = {}) { ctx.middleware((session, next) => { const body = session.$parsed - const payloads = interactions[session.$reply] + const payloads = history[int32ToHex6(session.$reply)] if (!body || !payloads) return next() let name: string, message: string - if (body.startsWith(prefix)) { - name = body.split(' ', 1)[0].slice(prefix.length) - message = body.slice(prefix.length + name.length).trim() + if (body.startsWith(replyPrefix)) { + name = body.split(' ', 1)[0].slice(replyPrefix.length) + message = body.slice(replyPrefix.length + name.length).trim() } else { name = reactions.includes(body) ? 'react' : 'reply' message = body @@ -173,19 +186,24 @@ export function apply(ctx: Context, config: Config = {}) { if (!result) return // step 4: broadcast message - const [message, replies] = result - const messageIds = await ctx.broadcast(groupIds, message) - if (!replies) return + const messageIds = await ctx.broadcast(groupIds, config.messagePrefix + result.message) + const hexIds = messageIds.map(int32ToHex6) // step 5: save message ids for interactions - for (const id of messageIds) { - interactions[id] = replies + for (const id of hexIds) { + history[id] = result } + setTimeout(() => { - for (const id of messageIds) { - delete interactions[id] + for (const id of hexIds) { + delete history[id] } }, config.replyTimeout) }) }) } + +function int32ToHex6(source: number) { + if (source < 0) source -= 1 << 31 + return source.toString(16).padStart(8, '0').slice(2) +} diff --git a/packages/plugin-github/src/server.ts b/packages/plugin-github/src/server.ts index 975faabc32..235ddc6c9d 100644 --- a/packages/plugin-github/src/server.ts +++ b/packages/plugin-github/src/server.ts @@ -22,7 +22,8 @@ export interface Config { secret?: string webhook?: string authorize?: string - prefix?: string + replyPrefix?: string + messagePrefix?: string appId?: string appSecret?: string redirect?: string @@ -86,7 +87,7 @@ export class GitHub extends Webhooks { await session.$send(message) const name = await session.$prompt(this.config.promptTimeout) if (!name) return session.$send('输入超时。') - return session.$execute({ command: 'github', args: [name] }) + return session.$execute({ command: 'github.authorize', args: [name] }) } async post(options: PostOptions) { diff --git a/packages/plugin-github/tests/index.spec.ts b/packages/plugin-github/tests/index.spec.ts index 779c184480..f5eab1571c 100644 --- a/packages/plugin-github/tests/index.spec.ts +++ b/packages/plugin-github/tests/index.spec.ts @@ -74,13 +74,17 @@ describe('GitHub Plugin', () => { await expect(app.server.post('/github/webhook', {})).to.eventually.have.property('code', 400) }) - it('github command', async () => { - await session1.shouldReply('github', '请输入用户名。') - await session1.shouldReply('github satori', /^请点击下面的链接继续操作:/) + it('github.authorize', async () => { + await session1.shouldReply('github.authorize', '请输入用户名。') + await session1.shouldReply('github.authorize satori', /^请点击下面的链接继续操作:/) + }) + + it('github.recent', async () => { + await session1.shouldReply('github.recent', '最近没有 GitHub 通知。') }) }) - let counter = 10000 + let counter = 0x100000 const idMap: Record = {} describe('Webhook Events', () => { @@ -172,5 +176,9 @@ describe('GitHub Plugin', () => { expect(unauthorized.mock.calls).to.have.length(1) expect(notFound.mock.calls).to.have.length(1) }) + + it('github.recent', async () => { + await session1.shouldReply('github.recent', /^100001\./) + }) }) }) diff --git a/packages/plugin-image-search/package.json b/packages/plugin-image-search/package.json index 582ce7e6b3..395e0e0180 100644 --- a/packages/plugin-image-search/package.json +++ b/packages/plugin-image-search/package.json @@ -37,7 +37,7 @@ "pixiv" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "axios": "^0.20.0", diff --git a/packages/plugin-mongo/package.json b/packages/plugin-mongo/package.json index aa9eb0cc18..07a5f90ee2 100644 --- a/packages/plugin-mongo/package.json +++ b/packages/plugin-mongo/package.json @@ -39,7 +39,7 @@ "@types/mongodb": "^3.5.27" }, "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "mongodb": "^3.6.1" diff --git a/packages/plugin-monitor/package.json b/packages/plugin-monitor/package.json index c522a44f7c..3954777438 100644 --- a/packages/plugin-monitor/package.json +++ b/packages/plugin-monitor/package.json @@ -21,7 +21,7 @@ }, "homepage": "https://github.com/koishijs/koishi#readme", "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "koishi-utils": "^3.1.5" diff --git a/packages/plugin-mysql/package.json b/packages/plugin-mysql/package.json index 7e494ccbc2..fce4786b5b 100644 --- a/packages/plugin-mysql/package.json +++ b/packages/plugin-mysql/package.json @@ -36,7 +36,7 @@ "@types/mysql": "^2.15.15" }, "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "koishi-utils": "^3.1.5", diff --git a/packages/plugin-puppeteer/package.json b/packages/plugin-puppeteer/package.json index a0ca26470b..7c95df2c54 100644 --- a/packages/plugin-puppeteer/package.json +++ b/packages/plugin-puppeteer/package.json @@ -39,7 +39,7 @@ "koishi-test-utils": "^5.0.1" }, "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "chrome-finder": "^1.0.7", diff --git a/packages/plugin-rss/package.json b/packages/plugin-rss/package.json index 1dc783369c..6da2d96c59 100644 --- a/packages/plugin-rss/package.json +++ b/packages/plugin-rss/package.json @@ -36,7 +36,7 @@ "rss" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "devDependencies": { "koishi-test-utils": "^5.0.1" diff --git a/packages/plugin-schedule/package.json b/packages/plugin-schedule/package.json index 675c8b373b..09d40cace7 100644 --- a/packages/plugin-schedule/package.json +++ b/packages/plugin-schedule/package.json @@ -39,7 +39,7 @@ "koishi-test-utils": "^5.0.1" }, "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "koishi-utils": "^3.1.5" diff --git a/packages/plugin-status/package.json b/packages/plugin-status/package.json index 8323b356ac..8130c7eefc 100644 --- a/packages/plugin-status/package.json +++ b/packages/plugin-status/package.json @@ -32,7 +32,7 @@ "status" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "devDependencies": { "@types/cross-spawn": "^6.0.2", diff --git a/packages/plugin-teach/package.json b/packages/plugin-teach/package.json index 5a40edbf7b..8b3491cded 100644 --- a/packages/plugin-teach/package.json +++ b/packages/plugin-teach/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-teach", "description": "Teach plugin for Koishi", - "version": "1.0.4", + "version": "1.1.0", "main": "dist/index.js", "typings": "dist/index.d.ts", "engines": { @@ -38,7 +38,7 @@ "conversation" ], "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "devDependencies": { "koishi-plugin-mongo": "^1.0.3", diff --git a/packages/plugin-teach/src/receiver.ts b/packages/plugin-teach/src/receiver.ts index 74a63511f0..64f588c73f 100644 --- a/packages/plugin-teach/src/receiver.ts +++ b/packages/plugin-teach/src/receiver.ts @@ -52,7 +52,6 @@ declare module './utils' { } } -// TODO change name export interface SessionState { userId: number groupId: number @@ -163,7 +162,7 @@ export class MessageBuffer { } } -export async function triggerDialogue(ctx: Context, session: Session, config: Dialogue.Config, next: NextFunction = noop) { +export async function triggerDialogue(ctx: Context, session: Session, next: NextFunction = noop) { const state = ctx.getSessionState(session) state.next = next state.test = {} @@ -269,7 +268,11 @@ export default function (ctx: Context, config: Dialogue.Config) { } ctx.group().middleware(async (session, next) => { - return triggerDialogue(ctx, session, config, next) + return session.$execute({ + command: 'dialogue', + args: [session.message], + next, + }) }) ctx.on('dialogue/receive', ({ session, test }) => { @@ -295,11 +298,11 @@ export default function (ctx: Context, config: Dialogue.Config) { } }) - ctx.group().command('teach/dialogue ', '触发教学对话') + ctx.group().command('dialogue ', '触发教学对话') .action(async ({ session, next }, message = '') => { if (session._redirected > maxRedirections) return next() session.message = message - return triggerDialogue(ctx, session, config, next) + return triggerDialogue(ctx, session, next) }) } diff --git a/packages/plugin-tools/package.json b/packages/plugin-tools/package.json index c424a03edb..bebeef81ed 100644 --- a/packages/plugin-tools/package.json +++ b/packages/plugin-tools/package.json @@ -1,6 +1,6 @@ { "name": "koishi-plugin-tools", - "version": "1.0.0", + "version": "1.0.1", "main": "dist/index.js", "typings": "dist/index.d.ts", "author": "Shigma <1700011071@pku.edu.cn>", @@ -25,7 +25,7 @@ "@types/qrcode": "^1.3.5" }, "peerDependencies": { - "koishi-core": "^2.2.2" + "koishi-core": "^2.3.0" }, "dependencies": { "axios": "^0.20.0", diff --git a/packages/plugin-tools/src/alpha.ts b/packages/plugin-tools/src/alpha.ts index 3ce5911cdb..6ab51cb6fd 100644 --- a/packages/plugin-tools/src/alpha.ts +++ b/packages/plugin-tools/src/alpha.ts @@ -32,7 +32,7 @@ export function apply(ctx: Context, config: AlphaOptions) { if (queryresult._attributes.success !== 'true') { return 'failed' } - const output = [`Question from ${session.sender.card || session.sender.nickname}: ${input}`] + const output = [`Question from ${session.$username}: ${input}`] queryresult.pod.forEach((el) => { if (Array.isArray(el.subpod)) { output.push(el._attributes.title + ': ', ...el.subpod.map(extractData).filter(t => t)) diff --git a/tsconfig.json b/tsconfig.json index 5bbe1c23f1..99e422d9a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ { "path": "./packages/koishi-core" }, { "path": "./packages/koishi-test-utils" }, { "path": "./packages/adapter-cqhttp" }, + { "path": "./packages/adapter-tomon" }, { "path": "./packages/plugin-mysql" }, { "path": "./packages/plugin-mongo" },