@zhin.js/core 1.0.57 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/lib/adapter.d.ts +1 -26
  2. package/lib/adapter.d.ts.map +1 -1
  3. package/lib/adapter.js +20 -117
  4. package/lib/adapter.js.map +1 -1
  5. package/lib/ai/index.d.ts +2 -0
  6. package/lib/ai/index.d.ts.map +1 -1
  7. package/lib/ai/index.js +1 -0
  8. package/lib/ai/index.js.map +1 -1
  9. package/lib/built/adapter-process.d.ts +0 -4
  10. package/lib/built/adapter-process.d.ts.map +1 -1
  11. package/lib/built/adapter-process.js +0 -95
  12. package/lib/built/adapter-process.js.map +1 -1
  13. package/lib/built/agent-preset.d.ts +2 -0
  14. package/lib/built/agent-preset.d.ts.map +1 -1
  15. package/lib/built/agent-preset.js +4 -0
  16. package/lib/built/agent-preset.js.map +1 -1
  17. package/lib/built/command.d.ts +4 -0
  18. package/lib/built/command.d.ts.map +1 -1
  19. package/lib/built/command.js +6 -0
  20. package/lib/built/command.js.map +1 -1
  21. package/lib/built/component.d.ts.map +1 -1
  22. package/lib/built/component.js +1 -0
  23. package/lib/built/component.js.map +1 -1
  24. package/lib/built/dispatcher.d.ts.map +1 -1
  25. package/lib/built/dispatcher.js +0 -13
  26. package/lib/built/dispatcher.js.map +1 -1
  27. package/lib/built/message-filter.d.ts +2 -0
  28. package/lib/built/message-filter.d.ts.map +1 -1
  29. package/lib/built/message-filter.js +5 -0
  30. package/lib/built/message-filter.js.map +1 -1
  31. package/lib/built/skill.d.ts +11 -0
  32. package/lib/built/skill.d.ts.map +1 -1
  33. package/lib/built/skill.js +14 -0
  34. package/lib/built/skill.js.map +1 -1
  35. package/lib/built/tool.d.ts +11 -44
  36. package/lib/built/tool.d.ts.map +1 -1
  37. package/lib/built/tool.js +14 -353
  38. package/lib/built/tool.js.map +1 -1
  39. package/lib/plugin.d.ts +1 -25
  40. package/lib/plugin.d.ts.map +1 -1
  41. package/lib/plugin.js +1 -77
  42. package/lib/plugin.js.map +1 -1
  43. package/lib/types.d.ts +0 -25
  44. package/lib/types.d.ts.map +1 -1
  45. package/package.json +10 -7
  46. package/CHANGELOG.md +0 -538
  47. package/REFACTORING_COMPLETE.md +0 -178
  48. package/REFACTORING_STATUS.md +0 -263
  49. package/src/adapter.ts +0 -275
  50. package/src/ai/index.ts +0 -52
  51. package/src/ai/providers/anthropic.ts +0 -379
  52. package/src/ai/providers/base.ts +0 -175
  53. package/src/ai/providers/index.ts +0 -13
  54. package/src/ai/providers/ollama.ts +0 -302
  55. package/src/ai/providers/openai.ts +0 -174
  56. package/src/ai/types.ts +0 -348
  57. package/src/bot.ts +0 -37
  58. package/src/built/adapter-process.ts +0 -177
  59. package/src/built/agent-preset.ts +0 -136
  60. package/src/built/ai-trigger.ts +0 -259
  61. package/src/built/command.ts +0 -108
  62. package/src/built/common-adapter-tools.ts +0 -242
  63. package/src/built/component.ts +0 -130
  64. package/src/built/config.ts +0 -335
  65. package/src/built/cron.ts +0 -156
  66. package/src/built/database.ts +0 -134
  67. package/src/built/dispatcher.ts +0 -496
  68. package/src/built/login-assist.ts +0 -131
  69. package/src/built/message-filter.ts +0 -390
  70. package/src/built/permission.ts +0 -151
  71. package/src/built/schema-feature.ts +0 -190
  72. package/src/built/skill.ts +0 -221
  73. package/src/built/tool.ts +0 -948
  74. package/src/command.ts +0 -87
  75. package/src/component.ts +0 -565
  76. package/src/cron.ts +0 -4
  77. package/src/errors.ts +0 -46
  78. package/src/feature.ts +0 -7
  79. package/src/index.ts +0 -53
  80. package/src/jsx-dev-runtime.ts +0 -2
  81. package/src/jsx-runtime.ts +0 -12
  82. package/src/jsx.ts +0 -135
  83. package/src/message.ts +0 -48
  84. package/src/models/system-log.ts +0 -20
  85. package/src/models/user.ts +0 -15
  86. package/src/notice.ts +0 -98
  87. package/src/plugin.ts +0 -896
  88. package/src/prompt.ts +0 -293
  89. package/src/request.ts +0 -95
  90. package/src/scheduler/index.ts +0 -19
  91. package/src/scheduler/scheduler.ts +0 -372
  92. package/src/scheduler/types.ts +0 -74
  93. package/src/tool-zod.ts +0 -115
  94. package/src/types-generator.ts +0 -78
  95. package/src/types.ts +0 -505
  96. package/src/utils.ts +0 -227
  97. package/tests/adapter.test.ts +0 -638
  98. package/tests/ai/ai-trigger.test.ts +0 -368
  99. package/tests/ai/providers.integration.test.ts +0 -227
  100. package/tests/ai/setup.ts +0 -308
  101. package/tests/ai/tool.test.ts +0 -800
  102. package/tests/bot.test.ts +0 -151
  103. package/tests/command.test.ts +0 -737
  104. package/tests/component-new.test.ts +0 -361
  105. package/tests/config.test.ts +0 -372
  106. package/tests/cron.test.ts +0 -82
  107. package/tests/dispatcher.test.ts +0 -293
  108. package/tests/errors.test.ts +0 -21
  109. package/tests/expression-evaluation.test.ts +0 -258
  110. package/tests/features-builtin.test.ts +0 -191
  111. package/tests/jsx-runtime.test.ts +0 -45
  112. package/tests/jsx.test.ts +0 -319
  113. package/tests/message-filter.test.ts +0 -566
  114. package/tests/message.test.ts +0 -402
  115. package/tests/notice.test.ts +0 -198
  116. package/tests/plugin.test.ts +0 -779
  117. package/tests/prompt.test.ts +0 -78
  118. package/tests/redos-protection.test.ts +0 -198
  119. package/tests/request.test.ts +0 -221
  120. package/tests/schema.test.ts +0 -248
  121. package/tests/skill-feature.test.ts +0 -179
  122. package/tests/test-utils.ts +0 -59
  123. package/tests/tool-feature.test.ts +0 -254
  124. package/tests/types.test.ts +0 -162
  125. package/tests/utils.test.ts +0 -135
  126. package/tsconfig.json +0 -24
@@ -1,402 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { Message, MessageBase, MessageChannel, MessageType } from '../src/message'
3
- import { MessageSegment, MessageSender } from '../src/types'
4
-
5
- describe('Message系统测试', () => {
6
- describe('Message类型定义测试', () => {
7
- it('应该正确定义MessageChannel接口', () => {
8
- const channel: MessageChannel = {
9
- id: 'test-channel-123',
10
- type: 'private'
11
- }
12
-
13
- expect(channel.id).toBe('test-channel-123')
14
- expect(channel.type).toBe('private')
15
- })
16
-
17
- it('应该支持所有MessageType类型', () => {
18
- const privateType: MessageType = 'private'
19
- const groupType: MessageType = 'group'
20
- const channelType: MessageType = 'channel'
21
-
22
- expect(privateType).toBe('private')
23
- expect(groupType).toBe('group')
24
- expect(channelType).toBe('channel')
25
- })
26
-
27
- it('应该正确定义MessageBase接口', () => {
28
- const mockReply = vi.fn().mockResolvedValue(undefined)
29
- const sender: MessageSender = {
30
- id: 'user-123',
31
- name: 'Test User',
32
- avatar: 'https://example.com/avatar.png'
33
- }
34
-
35
- const messageBase: MessageBase = {
36
- $id: 'msg-123',
37
- $adapter: 'test-adapter',
38
- $bot: 'test-bot',
39
- $content: [
40
- { type: 'text', data: { text: 'Hello World' } }
41
- ],
42
- $sender: sender,
43
- $reply: mockReply,
44
- $channel: { id: 'channel-123', type: 'private' },
45
- $timestamp: Date.now(),
46
- $raw: 'Hello World'
47
- }
48
-
49
- expect(messageBase.$id).toBe('msg-123')
50
- expect(messageBase.$adapter).toBe('test-adapter')
51
- expect(messageBase.$bot).toBe('test-bot')
52
- expect(messageBase.$content).toHaveLength(1)
53
- expect(messageBase.$content[0].type).toBe('text')
54
- expect(messageBase.$sender.id).toBe('user-123')
55
- expect(typeof messageBase.$reply).toBe('function')
56
- expect(messageBase.$channel.id).toBe('channel-123')
57
- expect(messageBase.$timestamp).toBeTypeOf('number')
58
- expect(messageBase.$raw).toBe('Hello World')
59
- })
60
- })
61
-
62
- describe('Message工厂函数测试', () => {
63
- it('应该使用Message.from创建消息对象', () => {
64
- const mockReply = vi.fn().mockResolvedValue(undefined)
65
- const customData = {
66
- platform: 'discord',
67
- serverId: 'server-123',
68
- messageId: 'discord-msg-456'
69
- }
70
-
71
- const messageBase: MessageBase = {
72
- $id: 'msg-123',
73
- $adapter: 'discord',
74
- $bot: 'discord-bot',
75
- $content: [
76
- { type: 'text', data: { text: 'Hello from Discord' } }
77
- ],
78
- $sender: {
79
- id: 'user-456',
80
- name: 'Discord User'
81
- },
82
- $reply: mockReply,
83
- $channel: { id: 'discord-channel', type: 'channel' },
84
- $timestamp: Date.now(),
85
- $raw: 'Hello from Discord'
86
- }
87
-
88
- const message = Message.from(customData, messageBase)
89
-
90
- // 验证合并结果
91
- expect(message.$id).toBe('msg-123')
92
- expect(message.$adapter).toBe('discord')
93
- expect(message.platform).toBe('discord')
94
- expect(message.serverId).toBe('server-123')
95
- expect(message.messageId).toBe('discord-msg-456')
96
- expect(typeof message.$reply).toBe('function')
97
- })
98
-
99
- it('应该保持原始数据的属性', () => {
100
- const mockReply = vi.fn()
101
- const originalData = {
102
- customField: 'custom-value',
103
- nested: {
104
- prop: 'nested-value'
105
- }
106
- }
107
-
108
- const messageBase: MessageBase = {
109
- $id: 'msg-456',
110
- $adapter: 'test',
111
- $bot: 'test-bot',
112
- $content: [],
113
- $sender: { id: 'user', name: 'User' },
114
- $reply: mockReply,
115
- $channel: { id: 'channel', type: 'private' },
116
- $timestamp: Date.now(),
117
- $raw: 'test'
118
- }
119
-
120
- const message = Message.from(originalData, messageBase)
121
-
122
- expect(message.customField).toBe('custom-value')
123
- expect(message.nested.prop).toBe('nested-value')
124
- expect(message.$id).toBe('msg-456')
125
- })
126
-
127
- it('应该正确处理泛型类型', () => {
128
- interface DiscordMessage {
129
- guildId?: string
130
- channelId: string
131
- authorId: string
132
- }
133
-
134
- const discordData: DiscordMessage = {
135
- guildId: 'guild-123',
136
- channelId: 'channel-456',
137
- authorId: 'author-789'
138
- }
139
-
140
- const messageBase: MessageBase = {
141
- $id: 'msg-789',
142
- $adapter: 'discord',
143
- $bot: 'discord-bot',
144
- $content: [
145
- { type: 'text', data: { text: 'Discord message' } }
146
- ],
147
- $sender: { id: 'author-789', name: 'Discord Author' },
148
- $reply: vi.fn(),
149
- $channel: { id: 'channel-456', type: 'channel' },
150
- $timestamp: Date.now(),
151
- $raw: 'Discord message'
152
- }
153
-
154
- const message: Message<DiscordMessage> = Message.from(discordData, messageBase)
155
-
156
- // TypeScript类型检查 + 运行时验证
157
- expect(message.guildId).toBe('guild-123')
158
- expect(message.channelId).toBe('channel-456')
159
- expect(message.authorId).toBe('author-789')
160
- expect(message.$adapter).toBe('discord')
161
- })
162
- })
163
-
164
- describe('消息内容处理测试', () => {
165
- it('应该正确处理文本消息', () => {
166
- const textSegment: MessageSegment = {
167
- type: 'text',
168
- data: { text: '这是一条文本消息' }
169
- }
170
-
171
- const messageBase: MessageBase = {
172
- $id: 'text-msg',
173
- $adapter: 'test',
174
- $bot: 'test-bot',
175
- $content: [textSegment],
176
- $sender: { id: 'user', name: 'User' },
177
- $reply: vi.fn(),
178
- $channel: { id: 'channel', type: 'private' },
179
- $timestamp: Date.now(),
180
- $raw: '这是一条文本消息'
181
- }
182
-
183
- expect(messageBase.$content[0].type).toBe('text')
184
- expect(messageBase.$content[0].data.text).toBe('这是一条文本消息')
185
- })
186
-
187
- it('应该正确处理多媒体消息', () => {
188
- const multiSegments: MessageSegment[] = [
189
- { type: 'text', data: { text: '看看这张图片:' } },
190
- { type: 'image', data: { url: 'https://example.com/image.png' } },
191
- { type: 'text', data: { text: '很漂亮吧!' } }
192
- ]
193
-
194
- const messageBase: MessageBase = {
195
- $id: 'multi-msg',
196
- $adapter: 'test',
197
- $bot: 'test-bot',
198
- $content: multiSegments,
199
- $sender: { id: 'user', name: 'User' },
200
- $reply: vi.fn(),
201
- $channel: { id: 'channel', type: 'group' },
202
- $timestamp: Date.now(),
203
- $raw: '看看这张图片:[图片]很漂亮吧!'
204
- }
205
-
206
- expect(messageBase.$content).toHaveLength(3)
207
- expect(messageBase.$content[0].type).toBe('text')
208
- expect(messageBase.$content[1].type).toBe('image')
209
- expect(messageBase.$content[2].type).toBe('text')
210
- expect(messageBase.$content[1].data.url).toBe('https://example.com/image.png')
211
- })
212
-
213
- it('应该正确处理特殊消息类型', () => {
214
- const specialSegments: MessageSegment[] = [
215
- { type: 'at', data: { user_id: 'user-123', name: '@张三' } },
216
- { type: 'emoji', data: { id: 'emoji-456', name: '😀' } },
217
- { type: 'file', data: { url: 'https://example.com/file.pdf', name: 'document.pdf' } }
218
- ]
219
-
220
- const messageBase: MessageBase = {
221
- $id: 'special-msg',
222
- $adapter: 'test',
223
- $bot: 'test-bot',
224
- $content: specialSegments,
225
- $sender: { id: 'user', name: 'User' },
226
- $reply: vi.fn(),
227
- $channel: { id: 'channel', type: 'group' },
228
- $timestamp: Date.now(),
229
- $raw: '@张三 😀 [文件: document.pdf]'
230
- }
231
-
232
- expect(messageBase.$content[0].type).toBe('at')
233
- expect(messageBase.$content[0].data.user_id).toBe('user-123')
234
- expect(messageBase.$content[1].type).toBe('emoji')
235
- expect(messageBase.$content[1].data.name).toBe('😀')
236
- expect(messageBase.$content[2].type).toBe('file')
237
- expect(messageBase.$content[2].data.name).toBe('document.pdf')
238
- })
239
- })
240
-
241
- describe('消息回复功能测试', () => {
242
- it('应该正确处理基本回复', async () => {
243
- const mockReply = vi.fn().mockResolvedValue(undefined)
244
-
245
- const message: Message = {
246
- $id: 'reply-test',
247
- $adapter: 'test',
248
- $bot: 'test-bot',
249
- $content: [{ type: 'text', data: { text: 'hello' } }],
250
- $sender: { id: 'user', name: 'User' },
251
- $reply: mockReply,
252
- $channel: { id: 'channel', type: 'private' },
253
- $timestamp: Date.now(),
254
- $raw: 'hello'
255
- }
256
-
257
- await message.$reply('Hello back!')
258
-
259
- expect(mockReply).toHaveBeenCalledWith('Hello back!')
260
- })
261
-
262
- it('应该正确处理带引用的回复', async () => {
263
- const mockReply = vi.fn().mockResolvedValue(undefined)
264
-
265
- const message: Message = {
266
- $id: 'quote-test',
267
- $adapter: 'test',
268
- $bot: 'test-bot',
269
- $content: [{ type: 'text', data: { text: 'original message' } }],
270
- $sender: { id: 'user', name: 'User' },
271
- $reply: mockReply,
272
- $channel: { id: 'channel', type: 'group' },
273
- $timestamp: Date.now(),
274
- $raw: 'original message'
275
- }
276
-
277
- await message.$reply('Quoted reply', true)
278
- await message.$reply('Custom quote', 'custom-quote-id')
279
-
280
- expect(mockReply).toHaveBeenCalledWith('Quoted reply', true)
281
- expect(mockReply).toHaveBeenCalledWith('Custom quote', 'custom-quote-id')
282
- })
283
-
284
- it('应该正确处理回复失败', async () => {
285
- const mockReply = vi.fn().mockRejectedValue(new Error('回复失败'))
286
-
287
- const message: Message = {
288
- $id: 'fail-test',
289
- $adapter: 'test',
290
- $bot: 'test-bot',
291
- $content: [{ type: 'text', data: { text: 'test' } }],
292
- $sender: { id: 'user', name: 'User' },
293
- $reply: mockReply,
294
- $channel: { id: 'channel', type: 'private' },
295
- $timestamp: Date.now(),
296
- $raw: 'test'
297
- }
298
-
299
- await expect(message.$reply('This will fail')).rejects.toThrow('回复失败')
300
- })
301
- })
302
-
303
- describe('发送者信息测试', () => {
304
- it('应该正确处理基本发送者信息', () => {
305
- const sender: MessageSender = {
306
- id: 'sender-123',
307
- name: '发送者'
308
- }
309
-
310
- const message: Message = {
311
- $id: 'sender-test',
312
- $adapter: 'test',
313
- $bot: 'test-bot',
314
- $content: [],
315
- $sender: sender,
316
- $reply: vi.fn(),
317
- $channel: { id: 'channel', type: 'private' },
318
- $timestamp: Date.now(),
319
- $raw: ''
320
- }
321
-
322
- expect(message.$sender.id).toBe('sender-123')
323
- expect(message.$sender.name).toBe('发送者')
324
- expect(message.$sender.avatar).toBeUndefined()
325
- })
326
-
327
- it('应该正确处理完整发送者信息', () => {
328
- const sender: MessageSender = {
329
- id: 'sender-456',
330
- name: '完整发送者',
331
- avatar: 'https://example.com/avatar.jpg',
332
- nickname: '昵称',
333
- roles: ['admin', 'moderator']
334
- }
335
-
336
- const message: Message = {
337
- $id: 'full-sender-test',
338
- $adapter: 'test',
339
- $bot: 'test-bot',
340
- $content: [],
341
- $sender: sender,
342
- $reply: vi.fn(),
343
- $channel: { id: 'channel', type: 'group' },
344
- $timestamp: Date.now(),
345
- $raw: ''
346
- }
347
-
348
- expect(message.$sender.avatar).toBe('https://example.com/avatar.jpg')
349
- expect(message.$sender.nickname).toBe('昵称')
350
- expect(message.$sender.roles).toEqual(['admin', 'moderator'])
351
- })
352
- })
353
-
354
- describe('消息时间戳测试', () => {
355
- it('应该正确处理时间戳', () => {
356
- const timestamp = Date.now()
357
-
358
- const message: Message = {
359
- $id: 'timestamp-test',
360
- $adapter: 'test',
361
- $bot: 'test-bot',
362
- $content: [],
363
- $sender: { id: 'user', name: 'User' },
364
- $reply: vi.fn(),
365
- $channel: { id: 'channel', type: 'private' },
366
- $timestamp: timestamp,
367
- $raw: ''
368
- }
369
-
370
- expect(message.$timestamp).toBe(timestamp)
371
- expect(typeof message.$timestamp).toBe('number')
372
- expect(message.$timestamp).toBeGreaterThan(0)
373
- })
374
- })
375
-
376
- describe('原始消息内容测试', () => {
377
- it('应该保留原始消息内容', () => {
378
- const rawContent = 'This is the raw message content with emojis 😀 and @mentions'
379
-
380
- const message: Message = {
381
- $id: 'raw-test',
382
- $adapter: 'test',
383
- $bot: 'test-bot',
384
- $content: [
385
- { type: 'text', data: { text: 'This is the raw message content with emojis ' } },
386
- { type: 'emoji', data: { name: '😀' } },
387
- { type: 'text', data: { text: ' and ' } },
388
- { type: 'at', data: { user_id: 'user123', name: '@mentions' } }
389
- ],
390
- $sender: { id: 'user', name: 'User' },
391
- $reply: vi.fn(),
392
- $channel: { id: 'channel', type: 'group' },
393
- $timestamp: Date.now(),
394
- $raw: rawContent
395
- }
396
-
397
- expect(message.$raw).toBe(rawContent)
398
- expect(message.$raw).toContain('😀')
399
- expect(message.$raw).toContain('@mentions')
400
- })
401
- })
402
- })
@@ -1,198 +0,0 @@
1
- /**
2
- * Notice 抽象层测试
3
- */
4
- import { Notice, NoticeBase, NoticeType } from '../src/notice.js';
5
-
6
- describe('Notice', () => {
7
- // ============================================================================
8
- // Notice.from()
9
- // ============================================================================
10
- describe('Notice.from()', () => {
11
- it('应合并原始数据与基础结构', () => {
12
- const raw = { original_field: 'test', group_id: 12345 };
13
- const base: NoticeBase = {
14
- $id: 'n_001',
15
- $adapter: 'onebot11' as any,
16
- $bot: 'bot1',
17
- $type: 'group_member_increase',
18
- $channel: { id: '12345', type: 'group' },
19
- $timestamp: 1000,
20
- };
21
- const notice = Notice.from(raw, base);
22
-
23
- expect(notice.$id).toBe('n_001');
24
- expect(notice.$adapter).toBe('onebot11');
25
- expect(notice.$bot).toBe('bot1');
26
- expect(notice.$type).toBe('group_member_increase');
27
- expect(notice.$channel.id).toBe('12345');
28
- expect(notice.$channel.type).toBe('group');
29
- expect(notice.$timestamp).toBe(1000);
30
- // 原始字段保留
31
- expect(notice.original_field).toBe('test');
32
- expect(notice.group_id).toBe(12345);
33
- });
34
-
35
- it('应保留可选字段 $operator 和 $target', () => {
36
- const raw = {};
37
- const base: NoticeBase = {
38
- $id: 'n_002',
39
- $adapter: 'icqq' as any,
40
- $bot: 'bot2',
41
- $type: 'group_member_decrease',
42
- $subType: 'kick',
43
- $channel: { id: '67890', type: 'group' },
44
- $operator: { id: '111', name: '管理员' },
45
- $target: { id: '222', name: '被踢者' },
46
- $timestamp: 2000,
47
- };
48
- const notice = Notice.from(raw, base);
49
-
50
- expect(notice.$subType).toBe('kick');
51
- expect(notice.$operator).toEqual({ id: '111', name: '管理员' });
52
- expect(notice.$target).toEqual({ id: '222', name: '被踢者' });
53
- });
54
-
55
- it('$operator 和 $target 应可以为 undefined', () => {
56
- const notice = Notice.from({}, {
57
- $id: 'n_003',
58
- $adapter: 'onebot11' as any,
59
- $bot: 'bot1',
60
- $type: 'friend_add',
61
- $channel: { id: '100', type: 'private' },
62
- $timestamp: 3000,
63
- });
64
-
65
- expect(notice.$operator).toBeUndefined();
66
- expect(notice.$target).toBeUndefined();
67
- expect(notice.$subType).toBeUndefined();
68
- });
69
- });
70
-
71
- // ============================================================================
72
- // NoticeType
73
- // ============================================================================
74
- describe('NoticeType', () => {
75
- it('应接受所有预定义类型', () => {
76
- const types: NoticeType[] = [
77
- 'group_member_increase',
78
- 'group_member_decrease',
79
- 'group_admin_change',
80
- 'group_ban',
81
- 'group_recall',
82
- 'friend_recall',
83
- 'friend_add',
84
- 'group_poke',
85
- 'friend_poke',
86
- 'group_transfer',
87
- ];
88
- expect(types).toHaveLength(10);
89
- });
90
-
91
- it('应接受自定义扩展类型', () => {
92
- const customType: NoticeType = 'custom_adapter_event';
93
- expect(customType).toBe('custom_adapter_event');
94
- });
95
- });
96
-
97
- // ============================================================================
98
- // NoticeChannel
99
- // ============================================================================
100
- describe('NoticeChannel', () => {
101
- it('应支持 group 类型', () => {
102
- const notice = Notice.from({}, {
103
- $id: '1',
104
- $adapter: 'onebot11' as any,
105
- $bot: 'b',
106
- $type: 'group_member_increase',
107
- $channel: { id: '123', type: 'group' },
108
- $timestamp: 0,
109
- });
110
- expect(notice.$channel.type).toBe('group');
111
- });
112
-
113
- it('应支持 private 类型', () => {
114
- const notice = Notice.from({}, {
115
- $id: '2',
116
- $adapter: 'onebot11' as any,
117
- $bot: 'b',
118
- $type: 'friend_add',
119
- $channel: { id: '456', type: 'private' },
120
- $timestamp: 0,
121
- });
122
- expect(notice.$channel.type).toBe('private');
123
- });
124
-
125
- it('应支持 channel 类型', () => {
126
- const notice = Notice.from({}, {
127
- $id: '3',
128
- $adapter: 'kook' as any,
129
- $bot: 'b',
130
- $type: 'group_member_increase',
131
- $channel: { id: '789', type: 'channel' },
132
- $timestamp: 0,
133
- });
134
- expect(notice.$channel.type).toBe('channel');
135
- });
136
- });
137
-
138
- // ============================================================================
139
- // 典型场景
140
- // ============================================================================
141
- describe('典型场景', () => {
142
- it('群成员入群通知', () => {
143
- const raw = { group_id: 12345, user_id: 67890, operator_id: 11111 };
144
- const notice = Notice.from(raw, {
145
- $id: 'inc_001',
146
- $adapter: 'onebot11' as any,
147
- $bot: 'mybot',
148
- $type: 'group_member_increase',
149
- $subType: 'approve',
150
- $channel: { id: '12345', type: 'group' },
151
- $operator: { id: '11111', name: '管理员' },
152
- $target: { id: '67890', name: '新成员' },
153
- $timestamp: Date.now(),
154
- });
155
-
156
- expect(notice.$type).toBe('group_member_increase');
157
- expect(notice.$subType).toBe('approve');
158
- expect(notice.group_id).toBe(12345);
159
- expect(notice.user_id).toBe(67890);
160
- });
161
-
162
- it('群消息撤回通知', () => {
163
- const raw = { group_id: 100, user_id: 200, operator_id: 300, message_id: 'msg_42' };
164
- const notice = Notice.from(raw, {
165
- $id: 'recall_001',
166
- $adapter: 'icqq' as any,
167
- $bot: 'bot1',
168
- $type: 'group_recall',
169
- $subType: 'recall',
170
- $channel: { id: '100', type: 'group' },
171
- $operator: { id: '300', name: '撤回者' },
172
- $target: { id: '200', name: '消息发送者' },
173
- $timestamp: Date.now(),
174
- });
175
-
176
- expect(notice.$type).toBe('group_recall');
177
- expect(notice.message_id).toBe('msg_42');
178
- });
179
-
180
- it('好友戳一戳通知', () => {
181
- const raw = { user_id: 100, operator_id: 100, target_id: 200, action: '戳了戳' };
182
- const notice = Notice.from(raw, {
183
- $id: 'poke_001',
184
- $adapter: 'icqq' as any,
185
- $bot: 'bot1',
186
- $type: 'friend_poke',
187
- $subType: 'poke',
188
- $channel: { id: '100', type: 'private' },
189
- $operator: { id: '100', name: '操作者' },
190
- $target: { id: '200', name: '被戳者' },
191
- $timestamp: Date.now(),
192
- });
193
-
194
- expect(notice.$type).toBe('friend_poke');
195
- expect(notice.action).toBe('戳了戳');
196
- });
197
- });
198
- });