@zhin.js/adapter-icqq 8.0.2 → 8.0.5

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/icqq-inbox.js CHANGED
@@ -27,7 +27,7 @@ export function buildIcqqInboxRequestRow(payload, base) {
27
27
  const isGroup = requestType === 'group' || groupId != null;
28
28
  return {
29
29
  adapter: base.adapter,
30
- endpoint_id: base.endpointId,
30
+ endpoint_id: base.endpointKey,
31
31
  platform_request_id: platformRequestId,
32
32
  type: isGroup ? 'group' : (requestType ?? 'friend'),
33
33
  scene_type: isGroup ? 'group' : null,
@@ -63,7 +63,7 @@ export function buildIcqqInboxNoticeRow(payload, base) {
63
63
  const targetId = userId != null && String(userId) !== String(actorId ?? '') ? userId : undefined;
64
64
  return {
65
65
  adapter: base.adapter,
66
- endpoint_id: base.endpointId,
66
+ endpoint_id: base.endpointKey,
67
67
  platform_notice_id: platformNoticeId,
68
68
  type: noticeType,
69
69
  scene_type: groupId != null ? 'group' : null,
@@ -92,7 +92,7 @@ export function buildIcqqSystemRequestRow(message, kind, base) {
92
92
  return null;
93
93
  return {
94
94
  adapter: base.adapter,
95
- endpoint_id: base.endpointId,
95
+ endpoint_id: base.endpointKey,
96
96
  platform_request_id: platformRequestId,
97
97
  type: kind,
98
98
  scene_type: kind === 'group' ? 'group' : null,
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Actions, formatInboundContent, formatInboundTarget, formatOutboundBody, parseSendTarget, resolveIcqqConfig, type IcqqAdapterConfig, type IcqqInboundMessage, type IcqqWireSegment, type IpcEvent, type IpcMessage, type IpcRequest, type IpcResponse, type ParsedIcqqSendTarget, type ResolvedIcqqConfig, } from './protocol.js';
1
+ export { Actions, formatInboundContent, formatOutboundBody, icqqInboundConversation, icqqOutboundTarget, resolveIcqqConfig, type IcqqAdapterConfig, type IcqqInboundMessage, type IcqqWireSegment, type IpcEvent, type IpcMessage, type IpcRequest, type IpcResponse, type ParsedIcqqSendTarget, type ResolvedIcqqConfig, } from './protocol.js';
2
2
  export { IcqqIpcEndpoint, type CreateIcqqIpc, type IcqqEndpointOptions, type IcqqInboxHooks, type IcqqIpcTransport, } from './endpoint.js';
3
3
  export * from './types.js';
4
4
  export { getIcqqAgentDeps, registerIcqqAgentEndpoint, setIcqqAgentDeps, type IcqqAgentDeps, type IcqqAgentEndpoint, } from './icqq-agent-deps.js';
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Actions, formatInboundContent, formatInboundTarget, formatOutboundBody, parseSendTarget, resolveIcqqConfig, } from './protocol.js';
1
+ export { Actions, formatInboundContent, formatOutboundBody, icqqInboundConversation, icqqOutboundTarget, resolveIcqqConfig, } from './protocol.js';
2
2
  export { IcqqIpcEndpoint, } from './endpoint.js';
3
3
  export * from './types.js';
4
4
  export { getIcqqAgentDeps, registerIcqqAgentEndpoint, setIcqqAgentDeps, } from './icqq-agent-deps.js';
@@ -61,7 +61,7 @@ export declare class IpcClient {
61
61
  */
62
62
  request(action: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<IpcResponse>;
63
63
  /**
64
- * @deprecated 兼容旧调用方式:服务端已自动推送事件,type/id 过滤在客户端完成。
64
+ * 订阅 daemon 推送事件:服务端自动推送全部事件,type/id 过滤在客户端完成。
65
65
  * @returns 订阅句柄,包含 unsubscribe() 方法
66
66
  */
67
67
  subscribe(_action: string, params: Record<string, unknown>, onEvent: (event: IpcEvent) => void): {
package/lib/ipc-client.js CHANGED
@@ -310,7 +310,7 @@ export class IpcClient {
310
310
  });
311
311
  }
312
312
  /**
313
- * @deprecated 兼容旧调用方式:服务端已自动推送事件,type/id 过滤在客户端完成。
313
+ * 订阅 daemon 推送事件:服务端自动推送全部事件,type/id 过滤在客户端完成。
314
314
  * @returns 订阅句柄,包含 unsubscribe() 方法
315
315
  */
316
316
  subscribe(_action, params, onEvent) {
package/lib/protocol.d.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  *
12
12
  * 登录相关:**推送**走 IpcEvent(`system.login.*`)。
13
13
  */
14
+ import type { ConversationRef } from '@zhin.js/im-contract';
14
15
  import type { MessageSegment } from "zhin.js";
15
16
  /** CLI → Daemon 请求 */
16
17
  export type IpcRequest = {
@@ -198,7 +199,7 @@ export declare const Actions: {
198
199
  };
199
200
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
200
201
  export interface IcqqAdapterConfig {
201
- readonly name?: string;
202
+ readonly id?: string;
202
203
  readonly autoReconnect?: boolean;
203
204
  readonly outboundMedia?: 'file' | 'base64';
204
205
  readonly rpc?: {
@@ -209,7 +210,7 @@ export interface IcqqAdapterConfig {
209
210
  /** Transitional: legacy root `endpoints[]` with `context: icqq`. */
210
211
  readonly endpoints?: ReadonlyArray<{
211
212
  readonly context?: string;
212
- readonly name?: string;
213
+ readonly id?: string;
213
214
  readonly autoReconnect?: boolean;
214
215
  readonly outboundMedia?: 'file' | 'base64';
215
216
  readonly rpc?: {
@@ -221,7 +222,7 @@ export interface IcqqAdapterConfig {
221
222
  }
222
223
  export interface ResolvedIcqqConfig {
223
224
  readonly context: 'icqq';
224
- readonly name: string;
225
+ readonly id: string;
225
226
  readonly autoReconnect: boolean;
226
227
  readonly outboundMedia?: 'file' | 'base64';
227
228
  readonly rpc?: {
@@ -236,14 +237,17 @@ export interface IcqqWireSegment {
236
237
  }
237
238
  export interface IcqqInboundMessage {
238
239
  readonly id: string;
239
- readonly target: string;
240
+ readonly conversation: ConversationRef;
240
241
  readonly content: string;
241
242
  /**
242
243
  * 结构化段视图(canonical Segment,经 toCanonicalSegments 归一)。
243
244
  * 与 content(CQ 原文纯文本视图)同源,随 gateway.receive 上送。
244
245
  */
245
246
  readonly segments?: readonly MessageSegment[];
246
- readonly sender: string;
247
+ readonly sender: {
248
+ readonly id: string;
249
+ readonly name?: string;
250
+ };
247
251
  readonly channelType: 'private' | 'group' | 'channel';
248
252
  readonly metadata?: Record<string, unknown>;
249
253
  }
@@ -263,13 +267,20 @@ export type ParsedIcqqSendTarget = {
263
267
  readonly channelId: string;
264
268
  };
265
269
  export declare function resolveIcqqConfig(config?: IcqqAdapterConfig): ResolvedIcqqConfig;
266
- /** Gateway reply target: `private:uid` / `group:gid` / `temp:gid:uid` / `channel:guild:channel`. */
267
- export declare function formatInboundTarget(input: {
270
+ /**
271
+ * 入站归一化 → ConversationRef:群临时会话(temp)映射为群容器内的 private
272
+ * 会话(parent kind 'group');频道消息的所属 guild 进 `parent`(kind 'channel')。
273
+ */
274
+ export declare function icqqInboundConversation(endpointKey: string, input: {
268
275
  readonly channelType: 'private' | 'group' | 'channel';
269
276
  readonly channelId: string;
270
277
  readonly channelParentGroupId?: string;
271
278
  readonly guildId?: string;
272
- }): string;
273
- export declare function parseSendTarget(target: string): ParsedIcqqSendTarget;
279
+ }): ConversationRef;
280
+ /**
281
+ * 出站:从 ConversationRef 派生 IPC action 路由。
282
+ * 群容器(parent kind 'group')内的 private 会话即 ICQQ 群临时会话(temp)。
283
+ */
284
+ export declare function icqqOutboundTarget(conversation: ConversationRef): ParsedIcqqSendTarget;
274
285
  export declare function formatOutboundBody(payload: unknown): string;
275
286
  export declare function formatInboundContent(rawMessage: string): string;
package/lib/protocol.js CHANGED
@@ -188,9 +188,9 @@ export const Actions = {
188
188
  };
189
189
  export function resolveIcqqConfig(config = {}) {
190
190
  const entry = config.endpoints?.find((item) => item.context === 'icqq');
191
- const name = pickCredential(config.name, entry?.name, process.env.ICQQ_ACCOUNT);
192
- if (!/^\d+$/.test(name)) {
193
- throw new TypeError('ICQQ adapter requires numeric name (QQ uin) via plugins.<key>.name or ICQQ_ACCOUNT');
191
+ const id = pickCredential(config.id, entry?.id, process.env.ICQQ_ACCOUNT);
192
+ if (!/^\d+$/.test(id)) {
193
+ throw new TypeError('ICQQ adapter requires numeric id (QQ uin) via plugins.<key>.id or ICQQ_ACCOUNT');
194
194
  }
195
195
  const autoReconnect = config.autoReconnect ?? entry?.autoReconnect ?? true;
196
196
  const outboundMedia = config.outboundMedia ?? entry?.outboundMedia;
@@ -200,53 +200,59 @@ export function resolveIcqqConfig(config = {}) {
200
200
  : undefined;
201
201
  return {
202
202
  context: 'icqq',
203
- name,
203
+ id,
204
204
  autoReconnect,
205
205
  ...(outboundMedia ? { outboundMedia } : {}),
206
206
  ...(rpc ? { rpc } : {}),
207
207
  };
208
208
  }
209
- /** Gateway reply target: `private:uid` / `group:gid` / `temp:gid:uid` / `channel:guild:channel`. */
210
- export function formatInboundTarget(input) {
209
+ /**
210
+ * 入站归一化 → ConversationRef:群临时会话(temp)映射为群容器内的 private
211
+ * 会话(parent kind 'group');频道消息的所属 guild 进 `parent`(kind 'channel')。
212
+ */
213
+ export function icqqInboundConversation(endpointKey, input) {
214
+ const endpoint = { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey };
211
215
  if (input.channelType === 'private' && input.channelParentGroupId) {
212
- return `temp:${input.channelParentGroupId}:${input.channelId}`;
216
+ return {
217
+ endpoint,
218
+ kind: 'private',
219
+ id: input.channelId,
220
+ parent: { kind: 'group', id: input.channelParentGroupId },
221
+ };
213
222
  }
214
223
  if (input.channelType === 'channel' && input.guildId) {
215
- return `channel:${input.guildId}:${input.channelId}`;
224
+ return {
225
+ endpoint,
226
+ kind: 'channel',
227
+ id: input.channelId,
228
+ parent: { kind: 'channel', id: input.guildId },
229
+ };
216
230
  }
217
- return `${input.channelType}:${input.channelId}`;
231
+ return { endpoint, kind: input.channelType, id: input.channelId };
218
232
  }
219
- export function parseSendTarget(target) {
220
- const trimmed = target.trim();
221
- if (trimmed.startsWith('temp:')) {
222
- const rest = trimmed.slice(5);
223
- const [groupId, userId] = rest.split(':');
224
- if (!groupId || !userId)
225
- throw new TypeError(`Invalid icqq temp target: ${target}`);
226
- return { kind: 'temp', groupId: Number(groupId), userId: Number(userId) };
227
- }
228
- if (trimmed.startsWith('channel:')) {
229
- const rest = trimmed.slice(8);
230
- const idx = rest.indexOf(':');
231
- if (idx <= 0)
232
- throw new TypeError(`Invalid icqq channel target: ${target}`);
233
+ /**
234
+ * 出站:从 ConversationRef 派生 IPC action 路由。
235
+ * 群容器(parent kind 'group')内的 private 会话即 ICQQ 群临时会话(temp)。
236
+ */
237
+ export function icqqOutboundTarget(conversation) {
238
+ if (conversation.kind === 'private' && conversation.parent?.kind === 'group') {
233
239
  return {
234
- kind: 'channel',
235
- guildId: rest.slice(0, idx),
236
- channelId: rest.slice(idx + 1),
240
+ kind: 'temp',
241
+ groupId: Number(conversation.parent.id),
242
+ userId: Number(conversation.id),
237
243
  };
238
244
  }
239
- if (trimmed.startsWith('private:')) {
240
- return { kind: 'private', userId: Number(trimmed.slice(8)) };
245
+ if (conversation.kind === 'private') {
246
+ return { kind: 'private', userId: Number(conversation.id) };
241
247
  }
242
- if (trimmed.startsWith('group:')) {
243
- return { kind: 'group', groupId: Number(trimmed.slice(6)) };
248
+ if (conversation.kind === 'group') {
249
+ return { kind: 'group', groupId: Number(conversation.id) };
244
250
  }
245
- // Bare numeric id → private (common reply path)
246
- if (/^\d+$/.test(trimmed)) {
247
- return { kind: 'private', userId: Number(trimmed) };
251
+ const guildId = conversation.parent?.kind === 'channel' ? conversation.parent.id : undefined;
252
+ if (!guildId) {
253
+ throw new TypeError(`Invalid icqq channel conversation (missing guild parent): ${conversation.id}`);
248
254
  }
249
- throw new TypeError(`Invalid icqq send target: ${target}`);
255
+ return { kind: 'channel', guildId, channelId: conversation.id };
250
256
  }
251
257
  export function formatOutboundBody(payload) {
252
258
  if (typeof payload === 'string') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-icqq",
3
- "version": "8.0.2",
3
+ "version": "8.0.5",
4
4
  "description": "Zhin.js ICQQ adapter for Plugin Runtime (IPC daemon client)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -34,19 +34,20 @@
34
34
  "directory": "plugins/adapters/icqq"
35
35
  },
36
36
  "dependencies": {
37
- "@zhin.js/adapter": "1.1.4",
38
- "@zhin.js/command": "1.0.6",
39
- "@zhin.js/core": "1.5.1",
40
- "@zhin.js/logger": "1.0.75",
41
- "@zhin.js/plugin-runtime": "1.1.2"
37
+ "@zhin.js/adapter": "1.1.7",
38
+ "@zhin.js/command": "1.0.9",
39
+ "@zhin.js/core": "1.5.4",
40
+ "@zhin.js/im-contract": "1.0.3",
41
+ "@zhin.js/logger": "1.0.76",
42
+ "@zhin.js/plugin-runtime": "1.1.5"
42
43
  },
43
44
  "peerDependencies": {
44
45
  "zod": "^4.0.0",
45
- "@zhin.js/adapter": "1.1.4",
46
- "@zhin.js/agent": "1.1.2",
47
- "@zhin.js/core": "1.5.1",
48
- "@zhin.js/plugin-runtime": "1.1.2",
49
- "zhin.js": "6.0.1"
46
+ "@zhin.js/adapter": "1.1.7",
47
+ "@zhin.js/agent": "1.1.5",
48
+ "@zhin.js/core": "1.5.4",
49
+ "@zhin.js/plugin-runtime": "1.1.5",
50
+ "zhin.js": "6.0.4"
50
51
  },
51
52
  "peerDependenciesMeta": {
52
53
  "zhin.js": {
@@ -64,8 +65,8 @@
64
65
  "typescript": "^6.0.3",
65
66
  "vitest": "^4.1.10",
66
67
  "zod": "^4.4.3",
67
- "@zhin.js/agent": "1.1.2",
68
- "zhin.js": "6.0.1"
68
+ "@zhin.js/agent": "1.1.5",
69
+ "zhin.js": "6.0.4"
69
70
  },
70
71
  "files": [
71
72
  "adapters",
package/schema.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "string",
9
9
  "number"
10
10
  ],
11
- "description": "Endpoint Owner QQ uin (for /approve bash and master role)"
11
+ "description": "框架 master QQ uin(/approve、AI/工具权限);endpoints[i].master 可逐项覆盖"
12
12
  },
13
13
  "trusted": {
14
14
  "type": "array",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "description": "Trusted QQ uin"
21
21
  },
22
- "description": "Trusted QQ uin list"
22
+ "description": "框架 trusted QQ uin 列表(弱于 master)"
23
23
  },
24
24
  "autoReconnect": {
25
25
  "type": "boolean",
@@ -35,21 +35,17 @@
35
35
  },
36
36
  "endpoints": {
37
37
  "type": "array",
38
- "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(name 必填,其余覆盖顶层)",
38
+ "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
39
39
  "items": {
40
40
  "type": "object",
41
41
  "additionalProperties": true,
42
42
  "properties": {
43
- "name": {
44
- "type": "string",
45
- "description": "QQ uin (must match icqq login account)"
46
- },
47
43
  "master": {
48
44
  "type": [
49
45
  "string",
50
46
  "number"
51
47
  ],
52
- "description": "Endpoint Owner QQ uin (for /approve bash and master role)"
48
+ "description": "本 endpoint 的框架 master QQ uin;覆盖顶层 master"
53
49
  },
54
50
  "trusted": {
55
51
  "type": "array",
@@ -60,7 +56,7 @@
60
56
  ],
61
57
  "description": "Trusted QQ uin"
62
58
  },
63
- "description": "Trusted QQ uin list"
59
+ "description": "本 endpoint 的 trusted 列表"
64
60
  },
65
61
  "rpc": {
66
62
  "type": "object",
@@ -84,10 +80,14 @@
84
80
  "port",
85
81
  "token"
86
82
  ]
83
+ },
84
+ "id": {
85
+ "type": "string",
86
+ "description": "QQ uin (must match icqq login account)"
87
87
  }
88
88
  },
89
89
  "required": [
90
- "name"
90
+ "id"
91
91
  ]
92
92
  }
93
93
  },
@@ -101,4 +101,4 @@
101
101
  "master",
102
102
  "endpoints"
103
103
  ]
104
- }
104
+ }