@zhin.js/adapter-qq 7.0.14 → 8.0.1

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.
package/lib/endpoint.js CHANGED
@@ -1,24 +1,32 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ /**
3
+ * QQ endpoints — lifecycle, outbound, admit, agent tool surface.
4
+ */
5
+ import { createRecallEndpointControl, } from 'zhin.js/adapter';
1
6
  import { formatCompact, getAdapterLogger, truncatePreview } from '@zhin.js/logger';
2
7
  import { formatOutbound } from './outbound.js';
3
- import { registerQqAgentEndpoint } from './qq-agent-deps.js';
4
8
  import { formatInboundContent, parseCompoundMessageId, qqInboundConversation, qqOutboundKind, resolveOutboundMessageId, senderDisplayName, } from './protocol.js';
5
9
  import { defaultCreateHttpBot, registerQqWebhookRoutes, } from './webhook.js';
6
10
  import { bindQqBotInboundEvents, defaultCreateBot, normalizeQqMessage, } from './ws.js';
7
11
  import { bindQqBotSideEvents, receiveQqSideEvent, } from './side-event-dispatch.js';
8
- export class QqWebsocketEndpoint {
12
+ export class QqWebsocketEndpoint extends Endpoint {
9
13
  #logger;
10
14
  #options;
11
15
  #createBot;
12
16
  #bot = null;
13
17
  #open = false;
14
18
  #started = false;
15
- #unregisterAgent;
16
- management = createQqEndpointManagement(this);
19
+ management = createQqEndpointManagement(() => this.#requireBot());
20
+ control = createRecallEndpointControl((id) => this.recallMessage(id));
17
21
  constructor(options) {
22
+ super();
18
23
  this.#logger = getAdapterLogger('qq', options.config.id);
19
24
  this.#options = options;
20
25
  this.#createBot = options.createBot ?? defaultCreateBot;
21
26
  }
27
+ get client() {
28
+ return this.#requireBot();
29
+ }
22
30
  /** Live endpoint 名(Console/AdapterIndex 展示用,如 bot appid 别名)。 */
23
31
  get name() {
24
32
  return this.#options.config.id;
@@ -28,7 +36,6 @@ export class QqWebsocketEndpoint {
28
36
  return;
29
37
  this.#started = true;
30
38
  try {
31
- this.#unregisterAgent = registerQqAgentEndpoint(this.#options.config.id, this);
32
39
  this.#bot = this.#createBot(this.#options.config);
33
40
  this.#bindBot(this.#bot);
34
41
  await this.#bot.start();
@@ -49,8 +56,6 @@ export class QqWebsocketEndpoint {
49
56
  }
50
57
  async stop() {
51
58
  this.#open = false;
52
- this.#unregisterAgent?.();
53
- this.#unregisterAgent = undefined;
54
59
  if (this.#bot) {
55
60
  try {
56
61
  this.#bot.removeAllListeners();
@@ -125,7 +130,7 @@ export class QqWebsocketEndpoint {
125
130
  + (msg.authorId ? ` from ${msg.authorId}` : '')
126
131
  + (msg.mentioned ? ' (mentioned)' : '')
127
132
  + ` | ${truncatePreview(content, 80)}`);
128
- void this.#options.gateway.receive({
133
+ void this.emit('message.receive', {
129
134
  conversation,
130
135
  message: { conversation, id: msg.id },
131
136
  content,
@@ -151,38 +156,25 @@ export class QqWebsocketEndpoint {
151
156
  }));
152
157
  });
153
158
  }
154
- getGuilds() {
155
- return this.#requireBot().getGuilds();
156
- }
157
- getChannels(guildId) {
158
- return this.#requireBot().getChannels(guildId);
159
- }
160
- getChannelInfo(channelId) {
161
- return this.#requireBot().getChannelInfo(channelId);
162
- }
163
- getGuildMember(guildId, userId) {
164
- return this.#requireBot().getGuildMember(guildId, userId);
165
- }
166
- getGuildRoles(guildId) {
167
- return this.#requireBot().getGuildRoles(guildId);
168
- }
169
- createGuildRole(guildId, name, color) {
170
- return this.#requireBot().createGuildRole(guildId, name, color);
171
- }
172
- addMemberRole(guildId, channelId, userId, roleId) {
173
- return this.#requireBot().addMemberRole(guildId, channelId, userId, roleId);
174
- }
175
- removeMemberRole(guildId, channelId, userId, roleId) {
176
- return this.#requireBot().removeMemberRole(guildId, channelId, userId, roleId);
177
- }
178
159
  #bindBot(bot) {
179
160
  bindQqBotInboundEvents(bot, (raw) => {
161
+ this.#emitPlatformEvent('message', raw);
180
162
  const msg = normalizeQqMessage(raw);
181
163
  if (msg)
182
164
  this.admit(msg);
183
165
  });
184
166
  bindQqBotSideEvents(bot, (eventName, raw) => {
185
- receiveQqSideEvent(this.#options.sideEvents, this.#options.config.id, bot, eventName, raw, this.#logger);
167
+ this.#emitPlatformEvent(eventName, raw);
168
+ receiveQqSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, bot, eventName, raw, this.#logger);
169
+ });
170
+ }
171
+ #emitPlatformEvent(name, event) {
172
+ void this.emitPlatform(name, event).catch((error) => {
173
+ this.#logger.warn(formatCompact({
174
+ op: 'qq_platform_event_failed',
175
+ event: name,
176
+ error: error instanceof Error ? error.message : String(error),
177
+ }));
186
178
  });
187
179
  }
188
180
  #requireBot() {
@@ -192,7 +184,7 @@ export class QqWebsocketEndpoint {
192
184
  }
193
185
  }
194
186
  /** Webhook / middleware inbound via httpHostToken POST (qq-official-bot Middleware receiver). */
195
- export class QqHttpEndpoint {
187
+ export class QqHttpEndpoint extends Endpoint {
196
188
  #logger;
197
189
  #options;
198
190
  #createBot;
@@ -200,13 +192,17 @@ export class QqHttpEndpoint {
200
192
  #routeReleases = [];
201
193
  #open = false;
202
194
  #started = false;
203
- #unregisterAgent;
204
- management = createQqEndpointManagement(this);
195
+ management = createQqEndpointManagement(() => this.#requireBot());
196
+ control = createRecallEndpointControl((id) => this.recallMessage(id));
205
197
  constructor(options) {
198
+ super();
206
199
  this.#logger = getAdapterLogger('qq', options.config.id);
207
200
  this.#options = options;
208
201
  this.#createBot = options.createBot ?? defaultCreateHttpBot;
209
202
  }
203
+ get client() {
204
+ return this.#requireBot();
205
+ }
210
206
  /** Live endpoint 名(Console/AdapterIndex 展示用)。 */
211
207
  get name() {
212
208
  return this.#options.config.id;
@@ -216,7 +212,6 @@ export class QqHttpEndpoint {
216
212
  return;
217
213
  this.#started = true;
218
214
  try {
219
- this.#unregisterAgent = registerQqAgentEndpoint(this.#options.config.id, this);
220
215
  this.#setupRoutes();
221
216
  this.#bot = this.#createBot(this.#options.config);
222
217
  this.#bindBot(this.#bot);
@@ -239,8 +234,6 @@ export class QqHttpEndpoint {
239
234
  this.#open = false;
240
235
  for (const release of this.#routeReleases.splice(0))
241
236
  release();
242
- this.#unregisterAgent?.();
243
- this.#unregisterAgent = undefined;
244
237
  if (this.#bot) {
245
238
  try {
246
239
  this.#bot.removeAllListeners();
@@ -314,7 +307,7 @@ export class QqHttpEndpoint {
314
307
  + (msg.authorId ? ` from ${msg.authorId}` : '')
315
308
  + (msg.mentioned ? ' (mentioned)' : '')
316
309
  + ` | ${truncatePreview(content, 80)}`);
317
- void this.#options.gateway.receive({
310
+ void this.emit('message.receive', {
318
311
  conversation,
319
312
  message: { conversation, id: msg.id },
320
313
  content,
@@ -340,30 +333,6 @@ export class QqHttpEndpoint {
340
333
  }));
341
334
  });
342
335
  }
343
- getGuilds() {
344
- return this.#requireBot().getGuilds();
345
- }
346
- getChannels(guildId) {
347
- return this.#requireBot().getChannels(guildId);
348
- }
349
- getChannelInfo(channelId) {
350
- return this.#requireBot().getChannelInfo(channelId);
351
- }
352
- getGuildMember(guildId, userId) {
353
- return this.#requireBot().getGuildMember(guildId, userId);
354
- }
355
- getGuildRoles(guildId) {
356
- return this.#requireBot().getGuildRoles(guildId);
357
- }
358
- createGuildRole(guildId, name, color) {
359
- return this.#requireBot().createGuildRole(guildId, name, color);
360
- }
361
- addMemberRole(guildId, channelId, userId, roleId) {
362
- return this.#requireBot().addMemberRole(guildId, channelId, userId, roleId);
363
- }
364
- removeMemberRole(guildId, channelId, userId, roleId) {
365
- return this.#requireBot().removeMemberRole(guildId, channelId, userId, roleId);
366
- }
367
336
  #setupRoutes() {
368
337
  this.#routeReleases.push(...registerQqWebhookRoutes(this.#options.http, {
369
338
  config: this.#options.config,
@@ -372,12 +341,23 @@ export class QqHttpEndpoint {
372
341
  }
373
342
  #bindBot(bot) {
374
343
  bindQqBotInboundEvents(bot, (raw) => {
344
+ this.#emitPlatformEvent('message', raw);
375
345
  const msg = normalizeQqMessage(raw);
376
346
  if (msg)
377
347
  this.admit(msg);
378
348
  });
379
349
  bindQqBotSideEvents(bot, (eventName, raw) => {
380
- receiveQqSideEvent(this.#options.sideEvents, this.#options.config.id, bot, eventName, raw, this.#logger);
350
+ this.#emitPlatformEvent(eventName, raw);
351
+ receiveQqSideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, bot, eventName, raw, this.#logger);
352
+ });
353
+ }
354
+ #emitPlatformEvent(name, event) {
355
+ void this.emitPlatform(name, event).catch((error) => {
356
+ this.#logger.warn(formatCompact({
357
+ op: 'qq_platform_event_failed',
358
+ event: name,
359
+ error: error instanceof Error ? error.message : String(error),
360
+ }));
381
361
  });
382
362
  }
383
363
  #requireBot() {
@@ -386,18 +366,19 @@ export class QqHttpEndpoint {
386
366
  return this.#bot;
387
367
  }
388
368
  }
389
- function createQqEndpointManagement(endpoint) {
369
+ function createQqEndpointManagement(requireClient) {
390
370
  return Object.freeze({
391
371
  async listChannels() {
392
372
  const channels = [];
393
- const guilds = await endpoint.getGuilds();
373
+ const client = requireClient();
374
+ const guilds = await client.getGuilds();
394
375
  for (const guildValue of Array.isArray(guilds) ? guilds : []) {
395
376
  const guild = asRecord(guildValue);
396
377
  const guildId = String(guild.id ?? guild.guild_id ?? guildValue ?? '');
397
378
  if (!guildId)
398
379
  continue;
399
380
  const guildName = String(guild.name ?? guild.guild_name ?? guildId);
400
- const rows = await endpoint.getChannels(guildId);
381
+ const rows = await client.getChannels(guildId);
401
382
  for (const channelValue of Array.isArray(rows) ? rows : []) {
402
383
  const channel = asRecord(channelValue);
403
384
  const id = String(channel.id ?? channel.channel_id ?? channelValue ?? '');
package/lib/index.d.ts CHANGED
@@ -4,5 +4,5 @@ export { formatOutbound, resolveMediaFile, type QqOutboundElem, type QqOutboundM
4
4
  export { QqHttpEndpoint, QqWebsocketEndpoint, type CreateQqBot, type CreateQqHttpBot, type QqBotTransport, type QqEndpointOptions, type QqHttpBotTransport, type QqHttpEndpointOptions, } from './endpoint.js';
5
5
  export { registerQqWebhookRoutes, handleQqWebhookRequest, readRequestBodyText, defaultCreateHttpBot, type QqWebhookHandler, } from './webhook.js';
6
6
  export { bindQqBotInboundEvents, defaultCreateBot, normalizeQqMessage, } from './ws.js';
7
- export { getQqAgentDeps, registerQqAgentEndpoint, setQqAgentDeps, type QqAgentDeps, type QqAgentEndpoint, } from './qq-agent-deps.js';
7
+ export { qqClient, type QqClientEventMap } from './client.js';
8
8
  export { checkQqPlatformPermit, normalizeQqGuildSenderForPermit, platformPermit, qqGuildPermitResolver, } from './platform-permit.js';
package/lib/index.js CHANGED
@@ -4,5 +4,5 @@ export { formatOutbound, resolveMediaFile, } from './outbound.js';
4
4
  export { QqHttpEndpoint, QqWebsocketEndpoint, } from './endpoint.js';
5
5
  export { registerQqWebhookRoutes, handleQqWebhookRequest, readRequestBodyText, defaultCreateHttpBot, } from './webhook.js';
6
6
  export { bindQqBotInboundEvents, defaultCreateBot, normalizeQqMessage, } from './ws.js';
7
- export { getQqAgentDeps, registerQqAgentEndpoint, setQqAgentDeps, } from './qq-agent-deps.js';
7
+ export { qqClient } from './client.js';
8
8
  export { checkQqPlatformPermit, normalizeQqGuildSenderForPermit, platformPermit, qqGuildPermitResolver, } from './platform-permit.js';
@@ -42,4 +42,4 @@ export declare function runQqEndpointRemove(_state: QqRuntimeState, id: string,
42
42
  * 通用套件生成的 QQ endpoint 命令(add 经 bindFlow 钩子走扫码绑定)。
43
43
  * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项;cancel 为 QQ 特化,单独定义。
44
44
  */
45
- export declare const qqEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
45
+ export declare const qqEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
@@ -1,4 +1,4 @@
1
- import type { SideEventGateway } from '@zhin.js/core/runtime';
1
+ import type { EndpointEventEmitter } from 'zhin.js/adapter';
2
2
  import { type getAdapterLogger } from '@zhin.js/logger';
3
3
  export interface QqSideEventCaller {
4
4
  approveGroupJoinRequest?(groupId: string, userId: string, options: {
@@ -10,4 +10,4 @@ export interface QqSideEventCaller {
10
10
  export declare function bindQqBotSideEvents(bot: {
11
11
  on(event: string, listener: (...args: unknown[]) => void): void;
12
12
  }, dispatch: (eventName: string, raw: unknown) => void): void;
13
- export declare function receiveQqSideEvent(sideEvents: SideEventGateway | undefined, endpointKey: string, caller: QqSideEventCaller, eventName: string, raw: unknown, logger: ReturnType<typeof getAdapterLogger>): void;
13
+ export declare function receiveQqSideEvent(emit: EndpointEventEmitter, endpointKey: string, caller: QqSideEventCaller, eventName: string, raw: unknown, logger: ReturnType<typeof getAdapterLogger>): void;
@@ -51,8 +51,8 @@ function toOneBotLikeRaw(eventName, raw) {
51
51
  }
52
52
  return null;
53
53
  }
54
- export function receiveQqSideEvent(sideEvents, endpointKey, caller, eventName, raw, logger) {
55
- if (!sideEvents)
54
+ export function receiveQqSideEvent(emit, endpointKey, caller, eventName, raw, logger) {
55
+ if (!emit)
56
56
  return;
57
57
  const mapped = toOneBotLikeRaw(eventName, raw);
58
58
  if (!mapped)
@@ -61,7 +61,7 @@ export function receiveQqSideEvent(sideEvents, endpointKey, caller, eventName, r
61
61
  const joinRaw = isJoinRequest && raw && typeof raw === 'object'
62
62
  ? raw
63
63
  : undefined;
64
- void receiveOneBotLikeSideEvent(sideEvents, {
64
+ void receiveOneBotLikeSideEvent(emit, {
65
65
  adapter: 'qq',
66
66
  endpointKey,
67
67
  platform: 'qq',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-qq",
3
- "version": "7.0.14",
3
+ "version": "8.0.1",
4
4
  "description": "Zhin.js QQ Official adapter for Plugin Runtime (WebSocket gateway)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -35,21 +35,22 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "qq-official-bot": "^1.2.3",
38
- "@zhin.js/adapter": "1.1.11",
39
- "@zhin.js/core": "1.5.12",
40
- "@zhin.js/host-http": "1.0.11",
38
+ "@zhin.js/adapter": "1.2.1",
39
+ "@zhin.js/core": "1.5.14",
40
+ "@zhin.js/feature-kit": "1.0.13",
41
+ "@zhin.js/host-http": "1.0.13",
41
42
  "@zhin.js/im-contract": "1.0.4",
42
- "@zhin.js/logger": "1.0.76",
43
- "@zhin.js/permission": "1.0.3"
43
+ "@zhin.js/logger": "1.0.77",
44
+ "@zhin.js/permission": "1.0.4"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "zod": "^4.0.0",
47
- "@zhin.js/adapter": "1.1.11",
48
- "@zhin.js/agent": "1.1.14",
49
- "@zhin.js/command": "1.0.15",
50
- "@zhin.js/core": "1.5.12",
51
- "@zhin.js/middleware": "1.0.12",
52
- "zhin.js": "6.0.12"
48
+ "@zhin.js/adapter": "1.2.1",
49
+ "@zhin.js/agent": "1.1.16",
50
+ "@zhin.js/command": "1.0.16",
51
+ "@zhin.js/core": "1.5.14",
52
+ "@zhin.js/middleware": "1.0.13",
53
+ "zhin.js": "6.0.14"
53
54
  },
54
55
  "peerDependenciesMeta": {
55
56
  "@zhin.js/agent": {
@@ -73,9 +74,9 @@
73
74
  "typescript": "^6.0.3",
74
75
  "vitest": "^4.1.10",
75
76
  "zod": "^4.4.3",
76
- "@zhin.js/agent": "1.1.14",
77
- "@zhin.js/host-http": "1.0.11",
78
- "zhin.js": "6.0.12"
77
+ "@zhin.js/agent": "1.1.16",
78
+ "@zhin.js/host-http": "1.0.13",
79
+ "zhin.js": "6.0.14"
79
80
  },
80
81
  "files": [
81
82
  "adapters",
package/src/client.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { defineEndpointClient } from 'zhin.js/adapter';
2
+ import type { QqInboundMessage } from './protocol.js';
3
+ import type { QqBotTransport } from './ws.js';
4
+
5
+ export type QqClientEventMap = Record<string, QqInboundMessage | unknown>;
6
+
7
+ declare module '@zhin.js/feature-kit' {
8
+ interface AdapterClientRegistry {
9
+ readonly qq: {
10
+ readonly client: QqBotTransport;
11
+ readonly events: QqClientEventMap;
12
+ };
13
+ }
14
+ }
15
+
16
+ export const qqClient = defineEndpointClient<QqBotTransport, QqClientEventMap>('qq');