@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/CHANGELOG.md +87 -0
- package/README.md +9 -9
- package/adapters/icqq.js +2 -2
- package/adapters/icqq.ts +2 -2
- package/lib/endpoint.d.ts +2 -5
- package/lib/endpoint.js +61 -89
- package/lib/icqq-agent-deps.d.ts +2 -2
- package/lib/icqq-agent-deps.js +7 -7
- package/lib/icqq-endpoint-commands.js +7 -7
- package/lib/icqq-inbox.d.ts +1 -1
- package/lib/icqq-inbox.js +3 -3
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/ipc-client.d.ts +1 -1
- package/lib/ipc-client.js +1 -1
- package/lib/protocol.d.ts +20 -9
- package/lib/protocol.js +40 -34
- package/package.json +14 -13
- package/schema.json +11 -11
- package/src/endpoint.ts +80 -94
- package/src/icqq-agent-deps.ts +8 -8
- package/src/icqq-endpoint-commands.ts +7 -7
- package/src/icqq-inbox.ts +4 -4
- package/src/index.ts +2 -2
- package/src/ipc-client.ts +1 -1
- package/src/protocol.ts +47 -38
- /package/commands/endpoint/add/{[name:string=].js → [[id]].js} +0 -0
- /package/commands/endpoint/add/{[name:string=].ts → [[id]].ts} +0 -0
- /package/commands/endpoint/remove/{[name:string].js → [id].js} +0 -0
- /package/commands/endpoint/remove/{[name:string].ts → [id].ts} +0 -0
package/src/protocol.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { pickCredential } from '@zhin.js/adapter';
|
|
16
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
16
17
|
import type { MessageSegment } from "zhin.js";
|
|
17
18
|
import { resolveCqMediaArg } from "./cq-message.js";
|
|
18
19
|
|
|
@@ -272,7 +273,7 @@ export const Actions = {
|
|
|
272
273
|
|
|
273
274
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
274
275
|
export interface IcqqAdapterConfig {
|
|
275
|
-
readonly
|
|
276
|
+
readonly id?: string;
|
|
276
277
|
readonly autoReconnect?: boolean;
|
|
277
278
|
readonly outboundMedia?: 'file' | 'base64';
|
|
278
279
|
readonly rpc?: {
|
|
@@ -283,7 +284,7 @@ export interface IcqqAdapterConfig {
|
|
|
283
284
|
/** Transitional: legacy root `endpoints[]` with `context: icqq`. */
|
|
284
285
|
readonly endpoints?: ReadonlyArray<{
|
|
285
286
|
readonly context?: string;
|
|
286
|
-
readonly
|
|
287
|
+
readonly id?: string;
|
|
287
288
|
readonly autoReconnect?: boolean;
|
|
288
289
|
readonly outboundMedia?: 'file' | 'base64';
|
|
289
290
|
readonly rpc?: {
|
|
@@ -296,7 +297,7 @@ export interface IcqqAdapterConfig {
|
|
|
296
297
|
|
|
297
298
|
export interface ResolvedIcqqConfig {
|
|
298
299
|
readonly context: 'icqq';
|
|
299
|
-
readonly
|
|
300
|
+
readonly id: string;
|
|
300
301
|
readonly autoReconnect: boolean;
|
|
301
302
|
readonly outboundMedia?: 'file' | 'base64';
|
|
302
303
|
readonly rpc?: {
|
|
@@ -313,14 +314,14 @@ export interface IcqqWireSegment {
|
|
|
313
314
|
|
|
314
315
|
export interface IcqqInboundMessage {
|
|
315
316
|
readonly id: string;
|
|
316
|
-
readonly
|
|
317
|
+
readonly conversation: ConversationRef;
|
|
317
318
|
readonly content: string;
|
|
318
319
|
/**
|
|
319
320
|
* 结构化段视图(canonical Segment,经 toCanonicalSegments 归一)。
|
|
320
321
|
* 与 content(CQ 原文纯文本视图)同源,随 gateway.receive 上送。
|
|
321
322
|
*/
|
|
322
323
|
readonly segments?: readonly MessageSegment[];
|
|
323
|
-
readonly sender: string;
|
|
324
|
+
readonly sender: { readonly id: string; readonly name?: string };
|
|
324
325
|
readonly channelType: 'private' | 'group' | 'channel';
|
|
325
326
|
readonly metadata?: Record<string, unknown>;
|
|
326
327
|
}
|
|
@@ -333,10 +334,10 @@ export type ParsedIcqqSendTarget =
|
|
|
333
334
|
|
|
334
335
|
export function resolveIcqqConfig(config: IcqqAdapterConfig = {}): ResolvedIcqqConfig {
|
|
335
336
|
const entry = config.endpoints?.find((item) => item.context === 'icqq');
|
|
336
|
-
const
|
|
337
|
-
if (!/^\d+$/.test(
|
|
337
|
+
const id = pickCredential(config.id, entry?.id, process.env.ICQQ_ACCOUNT);
|
|
338
|
+
if (!/^\d+$/.test(id)) {
|
|
338
339
|
throw new TypeError(
|
|
339
|
-
'ICQQ adapter requires numeric
|
|
340
|
+
'ICQQ adapter requires numeric id (QQ uin) via plugins.<key>.id or ICQQ_ACCOUNT',
|
|
340
341
|
);
|
|
341
342
|
}
|
|
342
343
|
const autoReconnect = config.autoReconnect ?? entry?.autoReconnect ?? true;
|
|
@@ -347,58 +348,66 @@ export function resolveIcqqConfig(config: IcqqAdapterConfig = {}): ResolvedIcqqC
|
|
|
347
348
|
: undefined;
|
|
348
349
|
return {
|
|
349
350
|
context: 'icqq',
|
|
350
|
-
|
|
351
|
+
id,
|
|
351
352
|
autoReconnect,
|
|
352
353
|
...(outboundMedia ? { outboundMedia } : {}),
|
|
353
354
|
...(rpc ? { rpc } : {}),
|
|
354
355
|
};
|
|
355
356
|
}
|
|
356
357
|
|
|
357
|
-
/**
|
|
358
|
-
|
|
358
|
+
/**
|
|
359
|
+
* 入站归一化 → ConversationRef:群临时会话(temp)映射为群容器内的 private
|
|
360
|
+
* 会话(parent kind 'group');频道消息的所属 guild 进 `parent`(kind 'channel')。
|
|
361
|
+
*/
|
|
362
|
+
export function icqqInboundConversation(endpointKey: string, input: {
|
|
359
363
|
readonly channelType: 'private' | 'group' | 'channel';
|
|
360
364
|
readonly channelId: string;
|
|
361
365
|
readonly channelParentGroupId?: string;
|
|
362
366
|
readonly guildId?: string;
|
|
363
|
-
}):
|
|
367
|
+
}): ConversationRef {
|
|
368
|
+
const endpoint = { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey };
|
|
364
369
|
if (input.channelType === 'private' && input.channelParentGroupId) {
|
|
365
|
-
return
|
|
370
|
+
return {
|
|
371
|
+
endpoint,
|
|
372
|
+
kind: 'private',
|
|
373
|
+
id: input.channelId,
|
|
374
|
+
parent: { kind: 'group', id: input.channelParentGroupId },
|
|
375
|
+
};
|
|
366
376
|
}
|
|
367
377
|
if (input.channelType === 'channel' && input.guildId) {
|
|
368
|
-
return
|
|
378
|
+
return {
|
|
379
|
+
endpoint,
|
|
380
|
+
kind: 'channel',
|
|
381
|
+
id: input.channelId,
|
|
382
|
+
parent: { kind: 'channel', id: input.guildId },
|
|
383
|
+
};
|
|
369
384
|
}
|
|
370
|
-
return
|
|
385
|
+
return { endpoint, kind: input.channelType, id: input.channelId };
|
|
371
386
|
}
|
|
372
387
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
return { kind: 'temp', groupId: Number(groupId), userId: Number(userId) };
|
|
380
|
-
}
|
|
381
|
-
if (trimmed.startsWith('channel:')) {
|
|
382
|
-
const rest = trimmed.slice(8);
|
|
383
|
-
const idx = rest.indexOf(':');
|
|
384
|
-
if (idx <= 0) throw new TypeError(`Invalid icqq channel target: ${target}`);
|
|
388
|
+
/**
|
|
389
|
+
* 出站:从 ConversationRef 派生 IPC action 路由。
|
|
390
|
+
* 群容器(parent kind 'group')内的 private 会话即 ICQQ 群临时会话(temp)。
|
|
391
|
+
*/
|
|
392
|
+
export function icqqOutboundTarget(conversation: ConversationRef): ParsedIcqqSendTarget {
|
|
393
|
+
if (conversation.kind === 'private' && conversation.parent?.kind === 'group') {
|
|
385
394
|
return {
|
|
386
|
-
kind: '
|
|
387
|
-
|
|
388
|
-
|
|
395
|
+
kind: 'temp',
|
|
396
|
+
groupId: Number(conversation.parent.id),
|
|
397
|
+
userId: Number(conversation.id),
|
|
389
398
|
};
|
|
390
399
|
}
|
|
391
|
-
if (
|
|
392
|
-
return { kind: 'private', userId: Number(
|
|
400
|
+
if (conversation.kind === 'private') {
|
|
401
|
+
return { kind: 'private', userId: Number(conversation.id) };
|
|
393
402
|
}
|
|
394
|
-
if (
|
|
395
|
-
return { kind: 'group', groupId: Number(
|
|
403
|
+
if (conversation.kind === 'group') {
|
|
404
|
+
return { kind: 'group', groupId: Number(conversation.id) };
|
|
396
405
|
}
|
|
397
|
-
|
|
398
|
-
if (
|
|
399
|
-
|
|
406
|
+
const guildId = conversation.parent?.kind === 'channel' ? conversation.parent.id : undefined;
|
|
407
|
+
if (!guildId) {
|
|
408
|
+
throw new TypeError(`Invalid icqq channel conversation (missing guild parent): ${conversation.id}`);
|
|
400
409
|
}
|
|
401
|
-
|
|
410
|
+
return { kind: 'channel', guildId, channelId: conversation.id };
|
|
402
411
|
}
|
|
403
412
|
|
|
404
413
|
export function formatOutboundBody(payload: unknown): string {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|