@zhin.js/core 1.0.45 → 1.0.47

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 (42) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/lib/adapter.d.ts +13 -13
  3. package/lib/adapter.d.ts.map +1 -1
  4. package/lib/adapter.js +18 -63
  5. package/lib/adapter.js.map +1 -1
  6. package/lib/bot.d.ts +8 -2
  7. package/lib/bot.d.ts.map +1 -1
  8. package/lib/built/common-adapter-tools.d.ts +10 -14
  9. package/lib/built/common-adapter-tools.d.ts.map +1 -1
  10. package/lib/built/common-adapter-tools.js +47 -21
  11. package/lib/built/common-adapter-tools.js.map +1 -1
  12. package/lib/built/message-filter.d.ts +175 -0
  13. package/lib/built/message-filter.d.ts.map +1 -0
  14. package/lib/built/message-filter.js +236 -0
  15. package/lib/built/message-filter.js.map +1 -0
  16. package/lib/index.d.ts +3 -0
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +3 -0
  19. package/lib/index.js.map +1 -1
  20. package/lib/notice.d.ts +81 -0
  21. package/lib/notice.d.ts.map +1 -0
  22. package/lib/notice.js +11 -0
  23. package/lib/notice.js.map +1 -0
  24. package/lib/plugin.d.ts +6 -0
  25. package/lib/plugin.d.ts.map +1 -1
  26. package/lib/plugin.js.map +1 -1
  27. package/lib/request.d.ts +85 -0
  28. package/lib/request.d.ts.map +1 -0
  29. package/lib/request.js +11 -0
  30. package/lib/request.js.map +1 -0
  31. package/package.json +6 -6
  32. package/src/adapter.ts +28 -81
  33. package/src/bot.ts +8 -2
  34. package/src/built/common-adapter-tools.ts +54 -25
  35. package/src/built/message-filter.ts +390 -0
  36. package/src/index.ts +3 -0
  37. package/src/notice.ts +98 -0
  38. package/src/plugin.ts +8 -0
  39. package/src/request.ts +95 -0
  40. package/tests/message-filter.test.ts +566 -0
  41. package/tests/notice.test.ts +198 -0
  42. package/tests/request.test.ts +221 -0
@@ -0,0 +1,198 @@
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
+ });
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Request 抽象层测试
3
+ */
4
+ import { Request, RequestBase, RequestType } from '../src/request.js';
5
+
6
+ describe('Request', () => {
7
+ // ============================================================================
8
+ // Request.from()
9
+ // ============================================================================
10
+ describe('Request.from()', () => {
11
+ it('应合并原始数据与基础结构', () => {
12
+ const raw = { flag: 'abc123', extra_data: 42 };
13
+ const base: RequestBase = {
14
+ $id: 'req_001',
15
+ $adapter: 'onebot11' as any,
16
+ $bot: 'bot1',
17
+ $type: 'friend_add',
18
+ $channel: { id: '100', type: 'private' },
19
+ $sender: { id: '200', name: '请求者' },
20
+ $comment: '请加我好友',
21
+ $timestamp: 1000,
22
+ $approve: async () => {},
23
+ $reject: async () => {},
24
+ };
25
+ const request = Request.from(raw, base);
26
+
27
+ expect(request.$id).toBe('req_001');
28
+ expect(request.$adapter).toBe('onebot11');
29
+ expect(request.$bot).toBe('bot1');
30
+ expect(request.$type).toBe('friend_add');
31
+ expect(request.$channel.type).toBe('private');
32
+ expect(request.$sender).toEqual({ id: '200', name: '请求者' });
33
+ expect(request.$comment).toBe('请加我好友');
34
+ expect(request.$timestamp).toBe(1000);
35
+ // 原始字段保留
36
+ expect(request.flag).toBe('abc123');
37
+ expect(request.extra_data).toBe(42);
38
+ });
39
+
40
+ it('$comment 和 $subType 应可以为 undefined', () => {
41
+ const request = Request.from({}, {
42
+ $id: 'req_002',
43
+ $adapter: 'icqq' as any,
44
+ $bot: 'bot1',
45
+ $type: 'group_add',
46
+ $channel: { id: '300', type: 'group' },
47
+ $sender: { id: '400', name: '申请者' },
48
+ $timestamp: 2000,
49
+ $approve: async () => {},
50
+ $reject: async () => {},
51
+ });
52
+
53
+ expect(request.$comment).toBeUndefined();
54
+ expect(request.$subType).toBeUndefined();
55
+ });
56
+ });
57
+
58
+ // ============================================================================
59
+ // $approve / $reject
60
+ // ============================================================================
61
+ describe('$approve() 和 $reject()', () => {
62
+ it('调用 $approve 应执行同意逻辑', async () => {
63
+ let approved = false;
64
+ let approveRemark: string | undefined;
65
+ const request = Request.from({}, {
66
+ $id: 'req_approve',
67
+ $adapter: 'onebot11' as any,
68
+ $bot: 'bot1',
69
+ $type: 'friend_add',
70
+ $channel: { id: '100', type: 'private' },
71
+ $sender: { id: '200', name: '用户' },
72
+ $timestamp: 0,
73
+ $approve: async (remark?: string) => {
74
+ approved = true;
75
+ approveRemark = remark;
76
+ },
77
+ $reject: async () => {},
78
+ });
79
+
80
+ await request.$approve('备注名');
81
+ expect(approved).toBe(true);
82
+ expect(approveRemark).toBe('备注名');
83
+ });
84
+
85
+ it('调用 $reject 应执行拒绝逻辑', async () => {
86
+ let rejected = false;
87
+ let rejectReason: string | undefined;
88
+ const request = Request.from({}, {
89
+ $id: 'req_reject',
90
+ $adapter: 'onebot11' as any,
91
+ $bot: 'bot1',
92
+ $type: 'group_invite',
93
+ $channel: { id: '300', type: 'group' },
94
+ $sender: { id: '400', name: '邀请者' },
95
+ $timestamp: 0,
96
+ $approve: async () => {},
97
+ $reject: async (reason?: string) => {
98
+ rejected = true;
99
+ rejectReason = reason;
100
+ },
101
+ });
102
+
103
+ await request.$reject('不接受邀请');
104
+ expect(rejected).toBe(true);
105
+ expect(rejectReason).toBe('不接受邀请');
106
+ });
107
+
108
+ it('$approve 无参数调用应不报错', async () => {
109
+ let called = false;
110
+ const request = Request.from({}, {
111
+ $id: 'req_noarg',
112
+ $adapter: 'onebot11' as any,
113
+ $bot: 'bot1',
114
+ $type: 'friend_add',
115
+ $channel: { id: '1', type: 'private' },
116
+ $sender: { id: '2', name: 'user' },
117
+ $timestamp: 0,
118
+ $approve: async () => { called = true; },
119
+ $reject: async () => {},
120
+ });
121
+
122
+ await request.$approve();
123
+ expect(called).toBe(true);
124
+ });
125
+ });
126
+
127
+ // ============================================================================
128
+ // RequestType
129
+ // ============================================================================
130
+ describe('RequestType', () => {
131
+ it('应接受所有预定义类型', () => {
132
+ const types: RequestType[] = ['friend_add', 'group_add', 'group_invite'];
133
+ expect(types).toHaveLength(3);
134
+ });
135
+
136
+ it('应接受自定义扩展类型', () => {
137
+ const customType: RequestType = 'custom_request_type';
138
+ expect(customType).toBe('custom_request_type');
139
+ });
140
+ });
141
+
142
+ // ============================================================================
143
+ // 典型场景
144
+ // ============================================================================
145
+ describe('典型场景', () => {
146
+ it('好友添加请求', async () => {
147
+ let approvedFlag: string | undefined;
148
+ const raw = { flag: 'friend_flag_001', user_id: 12345 };
149
+ const request = Request.from(raw, {
150
+ $id: 'friend_flag_001',
151
+ $adapter: 'onebot11' as any,
152
+ $bot: 'mybot',
153
+ $type: 'friend_add',
154
+ $subType: 'add',
155
+ $channel: { id: '12345', type: 'private' },
156
+ $sender: { id: '12345', name: '新朋友' },
157
+ $comment: '你好,加个好友吧',
158
+ $timestamp: Date.now(),
159
+ $approve: async (remark?: string) => {
160
+ approvedFlag = raw.flag;
161
+ },
162
+ $reject: async () => {},
163
+ });
164
+
165
+ expect(request.$type).toBe('friend_add');
166
+ expect(request.$comment).toBe('你好,加个好友吧');
167
+ expect(request.flag).toBe('friend_flag_001');
168
+ expect(request.user_id).toBe(12345);
169
+
170
+ await request.$approve();
171
+ expect(approvedFlag).toBe('friend_flag_001');
172
+ });
173
+
174
+ it('入群申请', async () => {
175
+ let rejected = false;
176
+ const raw = { flag: 'group_flag_001', user_id: 111, group_id: 222, comment: '想加群' };
177
+ const request = Request.from(raw, {
178
+ $id: 'group_flag_001',
179
+ $adapter: 'icqq' as any,
180
+ $bot: 'bot2',
181
+ $type: 'group_add',
182
+ $subType: 'add',
183
+ $channel: { id: '222', type: 'group' },
184
+ $sender: { id: '111', name: '申请者' },
185
+ $comment: '想加群',
186
+ $timestamp: Date.now(),
187
+ $approve: async () => {},
188
+ $reject: async (reason?: string) => { rejected = true; },
189
+ });
190
+
191
+ expect(request.$type).toBe('group_add');
192
+ expect(request.group_id).toBe(222);
193
+
194
+ await request.$reject('暂不接受');
195
+ expect(rejected).toBe(true);
196
+ });
197
+
198
+ it('群邀请', async () => {
199
+ let approved = false;
200
+ const raw = { flag: 'invite_001', user_id: 333, group_id: 444, group_name: '测试群' };
201
+ const request = Request.from(raw, {
202
+ $id: 'invite_001',
203
+ $adapter: 'onebot11' as any,
204
+ $bot: 'bot1',
205
+ $type: 'group_invite',
206
+ $subType: 'invite',
207
+ $channel: { id: '444', type: 'group' },
208
+ $sender: { id: '333', name: '邀请者' },
209
+ $timestamp: Date.now(),
210
+ $approve: async () => { approved = true; },
211
+ $reject: async () => {},
212
+ });
213
+
214
+ expect(request.$type).toBe('group_invite');
215
+ expect(request.group_name).toBe('测试群');
216
+
217
+ await request.$approve();
218
+ expect(approved).toBe(true);
219
+ });
220
+ });
221
+ });