@zhin.js/adapter-icqq 8.0.13 → 9.0.0
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 +58 -0
- package/README.md +8 -4
- package/adapters/icqq.js +3 -55
- package/adapters/icqq.ts +12 -62
- package/lib/cq-message.d.ts +5 -13
- package/lib/cq-message.js +6 -72
- package/lib/endpoint.d.ts +9 -10
- package/lib/endpoint.js +429 -141
- package/lib/forward-msg.d.ts +3 -22
- package/lib/forward-msg.js +38 -307
- package/lib/icqq-inbound.d.ts +29 -3
- package/lib/icqq-inbound.js +95 -12
- package/lib/icqq-login-assist.d.ts +27 -0
- package/lib/icqq-login-assist.js +109 -0
- package/lib/index.d.ts +1 -1
- package/lib/outbound-media.d.ts +6 -2
- package/lib/outbound-media.js +15 -8
- package/lib/protocol.d.ts +10 -1
- package/lib/protocol.js +82 -20
- package/package.json +13 -13
- package/src/cq-message.ts +7 -74
- package/src/endpoint.ts +463 -153
- package/src/forward-msg.ts +35 -342
- package/src/icqq-inbound.ts +112 -13
- package/src/icqq-login-assist.ts +132 -0
- package/src/index.ts +0 -1
- package/src/outbound-media.ts +20 -5
- package/src/protocol.ts +82 -22
- package/tools/announce.js +1 -1
- package/tools/announce.ts +1 -1
- package/tools/essence.js +1 -1
- package/tools/essence.ts +1 -1
- package/tools/friend_list.js +5 -4
- package/tools/friend_list.ts +7 -5
- package/tools/group_list.js +6 -5
- package/tools/group_list.ts +8 -6
- package/tools/group_member_info.js +27 -0
- package/tools/group_member_info.ts +30 -0
- package/tools/set_mute.js +1 -1
- package/tools/set_mute.ts +1 -1
- package/tools/set_title.js +1 -1
- package/tools/set_title.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# @zhin.js/adapter-icqq
|
|
2
2
|
|
|
3
|
+
## 9.0.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [f2c532f]
|
|
8
|
+
- Updated dependencies [3dbf990]
|
|
9
|
+
- @zhin.js/adapter@1.2.0
|
|
10
|
+
- @zhin.js/core@1.5.13
|
|
11
|
+
- @zhin.js/agent@1.1.15
|
|
12
|
+
- zhin.js@6.0.13
|
|
13
|
+
|
|
14
|
+
## 8.0.14
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 5969c5b: Remove legacy compound-string message targets and Endpoint control probing. Endpoint control and outbound Host operations now carry structured `MessageRef` identities. Endpoint send has one exact result contract (a platform message id), which IM Runtime projects into `DeliveryReceipt.message`; arbitrary result guessing is removed.
|
|
19
|
+
- 5969c5b: Drop ICQQ unified_inbox dual-write for request/notice; Console request.list prefers EndpointManagement.listRequests, and approval stays on $approve / management.
|
|
20
|
+
- 5969c5b: Wire ICQQ login challenges (QR / slider / SMS / auth) through LoginAssist so pending tasks survive Console refresh; add login.list/submit/cancel RPC and TTY stdin consumer.
|
|
21
|
+
- 7cd8b34: Send canonical outbound segments as native ICQQ `Sendable` elements instead of literal CQ-like text. Resolve inbound voice and video URLs while the endpoint client is active, preserve file metadata and opaque platform references, and reject unsupported mixed standalone media messages instead of silently dropping segments.
|
|
22
|
+
- 5969c5b: Add SideEventGateway so adapters forward notice/request/system into HandlerIndex. HandlerContext now exposes only generation-safe capabilities and prompt ports; live Endpoint escape hatches are removed.
|
|
23
|
+
- 2f786bd: Replace text-only IM context and metadata-based quote handling with canonical
|
|
24
|
+
conversation events, scoped reference resolution, explicit Endpoint content
|
|
25
|
+
ports, and typed multimedia outcomes. Conversation notices are projected as
|
|
26
|
+
untrusted context data rather than model-authority system instructions.
|
|
27
|
+
The process-global passive-group buffer is removed: prior inbound conversation messages
|
|
28
|
+
are now consumed from the same event store and cursor, with the current Turn
|
|
29
|
+
message excluded from its own context projection.
|
|
30
|
+
The unused `ConversationMemory` topic-memory runtime, its timers, legacy tables,
|
|
31
|
+
and topic-window configuration are removed; `ContextRepository` is the only
|
|
32
|
+
Agent conversation-history authority.
|
|
33
|
+
- Updated dependencies [5969c5b]
|
|
34
|
+
- Updated dependencies [d336a3f]
|
|
35
|
+
- Updated dependencies [0c82a7e]
|
|
36
|
+
- Updated dependencies [b9217e4]
|
|
37
|
+
- Updated dependencies [5969c5b]
|
|
38
|
+
- Updated dependencies [5969c5b]
|
|
39
|
+
- Updated dependencies [974772e]
|
|
40
|
+
- Updated dependencies [5969c5b]
|
|
41
|
+
- Updated dependencies [5969c5b]
|
|
42
|
+
- Updated dependencies [2f786bd]
|
|
43
|
+
- Updated dependencies [63d89f9]
|
|
44
|
+
- Updated dependencies [71c7cdd]
|
|
45
|
+
- Updated dependencies [3cca0ea]
|
|
46
|
+
- Updated dependencies [1312ca0]
|
|
47
|
+
- Updated dependencies [985fa22]
|
|
48
|
+
- Updated dependencies [04b861d]
|
|
49
|
+
- Updated dependencies [a23d544]
|
|
50
|
+
- Updated dependencies [8cddabf]
|
|
51
|
+
- Updated dependencies [dbe5081]
|
|
52
|
+
- @zhin.js/im-contract@1.0.4
|
|
53
|
+
- @zhin.js/core@1.5.12
|
|
54
|
+
- @zhin.js/adapter@1.1.11
|
|
55
|
+
- @zhin.js/agent@1.1.14
|
|
56
|
+
- @zhin.js/command@1.0.15
|
|
57
|
+
- zhin.js@6.0.12
|
|
58
|
+
- @zhin.js/permission@1.0.3
|
|
59
|
+
- @zhin.js/tool@1.0.12
|
|
60
|
+
|
|
3
61
|
## 8.0.13
|
|
4
62
|
|
|
5
63
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@ ICQQ Plugin Runtime 适配器 — 进程内直接使用 [@icqqjs/icqq](https://g
|
|
|
5
5
|
## 功能特性
|
|
6
6
|
|
|
7
7
|
- 群聊 / 私聊 / 群临时会话 / QQ 频道消息
|
|
8
|
-
- 入站:`messageGatewayToken
|
|
9
|
-
-
|
|
8
|
+
- 入站:`messageGatewayToken`,文本与图片 / 语音 / 视频 / 文件统一归一为 canonical `Segment` + `MediaRef`
|
|
9
|
+
- 出站:canonical Segment 直接投影为 ICQQ 原生 `Sendable`,再由 `sendGroupMsg` / `sendPrivateMsg` / …发送
|
|
10
10
|
- 群聊 reaction:`control.addReaction` / `removeReaction`(协议 ACK 失败不阻塞后续发送)
|
|
11
11
|
- Agent 工具:包根 `tools/`(`@zhin.js/tool` Feature;模型侧名为 `icqq__send_user_like` 等)
|
|
12
12
|
- Console Endpoint 管理:`src/endpoint.ts` 显式实现 `EndpointManagement`(好友/群/群成员列表、请求审批、删好友、踢人、禁言、设管理)
|
|
@@ -76,9 +76,13 @@ plugins:
|
|
|
76
76
|
|
|
77
77
|
- 不再经过 `@icqqjs/cli` IPC 守护进程;登录态与协议栈都在本进程。
|
|
78
78
|
- `autoReconnect`:Client 断线后按配置自动重连(`stop()` 为主动断开,不触发重连)。
|
|
79
|
-
- `outboundMedia: file | base64`:`file`
|
|
79
|
+
- `outboundMedia: file | base64`:`file` 在发送期间把 segment base64 物化为临时文件并于发送结束清理;`base64` 使用 ICQQ 原生支持的 `base64://` file 参数。
|
|
80
|
+
- ICQQ 的语音、视频、文件是独立消息元素;它们与其他段混发时适配器会明确拒绝,避免协议栈静默丢段。
|
|
81
|
+
- 入站语音 / 视频在 Endpoint 持有原生 Client 时解析可下载 URL;解析失败则保留真实平台引用,不伪造或丢弃媒体。
|
|
80
82
|
- **Console 社交/群管 RPC 已接线**:endpoint 把好友/群/群成员列表、请求审批和群管操作归一化为冻结的 `EndpointManagement`。Host 只消费该语义端口。
|
|
81
|
-
-
|
|
83
|
+
- 好友/入群请求与通知:经 `sideEventGatewayToken` 分发到 `handlers`(`notice.receive` / `request.receive`);审批走 `Request.$approve` / `EndpointManagement.approveRequest`。Console `request.list` 优先读 `management.listRequests()`(`getSystemMsg`),不再写入 `unified_inbox_request/notice`。
|
|
84
|
+
- `system.*`(登录扫码等)分发到 `system.receive`。
|
|
85
|
+
- **登录辅助**:`system.login.qrcode|slider|device|auth` 经 `loginAssistToken`(`LoginAssist`)挂起待办;刷新后可用 Console `login.list` / `login.submit` 或终端 stdin 继续(对齐 icqq 官方 stdin 流程)。`system.online` / `login.error` 会清理该 endpoint 待办。
|
|
82
86
|
|
|
83
87
|
## License
|
|
84
88
|
|
package/adapters/icqq.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
* Convention entry: discover `adapters/icqq.ts` → defineAdapter.
|
|
4
4
|
*/
|
|
5
5
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
-
import { messageGatewayToken } from '@zhin.js/core/runtime';
|
|
7
|
-
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
8
|
-
import { databaseHostToken, INBOX_TABLE_NOTICE, INBOX_TABLE_REQUEST, runtimeEventPublisherToken, } from 'zhin.js';
|
|
6
|
+
import { loginAssistToken, messageGatewayToken, sideEventGatewayToken, } from '@zhin.js/core/runtime';
|
|
9
7
|
import { IcqqEndpoint } from "../lib/endpoint.js";
|
|
10
8
|
import { icqqRuntimeStateToken } from "../lib/icqq-runtime-state.js";
|
|
11
9
|
import { resolveIcqqConfig, } from "../lib/protocol.js";
|
|
12
10
|
export { IcqqEndpoint } from "../lib/endpoint.js";
|
|
13
|
-
const logger = getLogger('icqq');
|
|
14
11
|
export default defineAdapter({
|
|
15
12
|
capabilities: ['inbound', 'outbound'],
|
|
16
13
|
operations: ['recall', 'reaction'],
|
|
@@ -25,61 +22,12 @@ export default defineAdapter({
|
|
|
25
22
|
id: config.id,
|
|
26
23
|
mode: 'direct',
|
|
27
24
|
});
|
|
28
|
-
const inbox = resolveInboxHooks(context);
|
|
29
25
|
return new IcqqEndpoint({
|
|
30
26
|
id: context.id,
|
|
31
27
|
gateway: context.use(messageGatewayToken),
|
|
28
|
+
sideEvents: context.use(sideEventGatewayToken),
|
|
29
|
+
loginAssist: context.use(loginAssistToken),
|
|
32
30
|
config,
|
|
33
|
-
...(inbox ? { inbox } : {}),
|
|
34
31
|
});
|
|
35
32
|
},
|
|
36
33
|
});
|
|
37
|
-
/** 资源可选(轻量 Root 无 DatabaseHost / console hub):缺失时降级为不写收件箱。 */
|
|
38
|
-
function tryUse(context, token) {
|
|
39
|
-
try {
|
|
40
|
-
return context.use(token);
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* 收件箱钩子:写 unified_inbox_request/notice(按 platform_*_id 去重,
|
|
48
|
-
* 推送事件与 GET_SYSTEM_MSG 首拉可能重复同一请求),并经 console hub 广播。
|
|
49
|
-
*/
|
|
50
|
-
function resolveInboxHooks(context) {
|
|
51
|
-
const host = tryUse(context, databaseHostToken);
|
|
52
|
-
const publisher = tryUse(context, runtimeEventPublisherToken);
|
|
53
|
-
if (!host && !publisher)
|
|
54
|
-
return undefined;
|
|
55
|
-
const insertDeduped = async (table, idField, row) => {
|
|
56
|
-
const model = host?.models.get(table);
|
|
57
|
-
if (!model)
|
|
58
|
-
return;
|
|
59
|
-
try {
|
|
60
|
-
const existing = await model.select().where({
|
|
61
|
-
adapter: row.adapter,
|
|
62
|
-
endpoint_id: row.endpoint_id,
|
|
63
|
-
[idField]: row[idField],
|
|
64
|
-
});
|
|
65
|
-
if (Array.isArray(existing) && existing.length > 0)
|
|
66
|
-
return;
|
|
67
|
-
await model.insert(row);
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
logger.warn(formatCompact({
|
|
71
|
-
op: 'inbox_insert',
|
|
72
|
-
table,
|
|
73
|
-
error: error instanceof Error ? error.message : String(error),
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
const publish = publisher;
|
|
78
|
-
return {
|
|
79
|
-
recordRequest: (row) => insertDeduped(INBOX_TABLE_REQUEST, 'platform_request_id', row),
|
|
80
|
-
recordNotice: (row) => insertDeduped(INBOX_TABLE_NOTICE, 'platform_notice_id', row),
|
|
81
|
-
...(publish
|
|
82
|
-
? { publish: (type, data) => publish.publish(type, data) }
|
|
83
|
-
: {}),
|
|
84
|
-
};
|
|
85
|
-
}
|
package/adapters/icqq.ts
CHANGED
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
* Convention entry: discover `adapters/icqq.ts` → defineAdapter.
|
|
3
3
|
*/
|
|
4
4
|
import { defineAdapter, type AdapterContext } from 'zhin.js/adapter';
|
|
5
|
-
import { messageGatewayToken } from '@zhin.js/core/runtime';
|
|
6
|
-
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
7
5
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from 'zhin.js';
|
|
14
|
-
import { IcqqEndpoint, type IcqqInboxHooks } from '../src/endpoint.js';
|
|
6
|
+
loginAssistToken,
|
|
7
|
+
messageGatewayToken,
|
|
8
|
+
sideEventGatewayToken,
|
|
9
|
+
} from '@zhin.js/core/runtime';
|
|
10
|
+
import { IcqqEndpoint } from '../src/endpoint.js';
|
|
15
11
|
import { icqqRuntimeStateToken } from '../src/icqq-runtime-state.js';
|
|
16
12
|
import {
|
|
17
13
|
resolveIcqqConfig,
|
|
@@ -21,7 +17,11 @@ import {
|
|
|
21
17
|
export { IcqqEndpoint } from '../src/endpoint.js';
|
|
22
18
|
export type { IcqqEndpointOptions } from '../src/endpoint.js';
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
declare module '@zhin.js/core' {
|
|
21
|
+
interface AdapterEndpoints {
|
|
22
|
+
icqq: import('../src/endpoint.js').IcqqEndpoint;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
25
|
|
|
26
26
|
export default defineAdapter<IcqqAdapterConfig>({
|
|
27
27
|
capabilities: ['inbound', 'outbound'],
|
|
@@ -37,62 +37,12 @@ export default defineAdapter<IcqqAdapterConfig>({
|
|
|
37
37
|
id: config.id,
|
|
38
38
|
mode: 'direct',
|
|
39
39
|
});
|
|
40
|
-
const inbox = resolveInboxHooks(context);
|
|
41
40
|
return new IcqqEndpoint({
|
|
42
41
|
id: context.id,
|
|
43
42
|
gateway: context.use(messageGatewayToken),
|
|
43
|
+
sideEvents: context.use(sideEventGatewayToken),
|
|
44
|
+
loginAssist: context.use(loginAssistToken),
|
|
44
45
|
config,
|
|
45
|
-
...(inbox ? { inbox } : {}),
|
|
46
46
|
});
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
|
-
|
|
50
|
-
/** 资源可选(轻量 Root 无 DatabaseHost / console hub):缺失时降级为不写收件箱。 */
|
|
51
|
-
function tryUse<T>(context: AdapterContext<IcqqAdapterConfig>, token: Token<T>): T | undefined {
|
|
52
|
-
try {
|
|
53
|
-
return context.use(token);
|
|
54
|
-
} catch {
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 收件箱钩子:写 unified_inbox_request/notice(按 platform_*_id 去重,
|
|
61
|
-
* 推送事件与 GET_SYSTEM_MSG 首拉可能重复同一请求),并经 console hub 广播。
|
|
62
|
-
*/
|
|
63
|
-
function resolveInboxHooks(context: AdapterContext<IcqqAdapterConfig>): IcqqInboxHooks | undefined {
|
|
64
|
-
const host = tryUse(context, databaseHostToken);
|
|
65
|
-
const publisher = tryUse(context, runtimeEventPublisherToken);
|
|
66
|
-
if (!host && !publisher) return undefined;
|
|
67
|
-
const insertDeduped = async (
|
|
68
|
-
table: string,
|
|
69
|
-
idField: 'platform_request_id' | 'platform_notice_id',
|
|
70
|
-
row: Record<string, unknown>,
|
|
71
|
-
): Promise<void> => {
|
|
72
|
-
const model = host?.models.get(table);
|
|
73
|
-
if (!model) return;
|
|
74
|
-
try {
|
|
75
|
-
const existing = await model.select().where({
|
|
76
|
-
adapter: row.adapter,
|
|
77
|
-
endpoint_id: row.endpoint_id,
|
|
78
|
-
[idField]: row[idField],
|
|
79
|
-
});
|
|
80
|
-
if (Array.isArray(existing) && existing.length > 0) return;
|
|
81
|
-
await model.insert(row);
|
|
82
|
-
} catch (error) {
|
|
83
|
-
logger.warn(formatCompact({
|
|
84
|
-
op: 'inbox_insert',
|
|
85
|
-
table,
|
|
86
|
-
error: error instanceof Error ? error.message : String(error),
|
|
87
|
-
}));
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
const publish = publisher;
|
|
91
|
-
return {
|
|
92
|
-
recordRequest: (row) => insertDeduped(INBOX_TABLE_REQUEST, 'platform_request_id', row),
|
|
93
|
-
recordNotice: (row) => insertDeduped(INBOX_TABLE_NOTICE, 'platform_notice_id', row),
|
|
94
|
-
...(publish
|
|
95
|
-
? { publish: (type: string, data: unknown): void => publish.publish(type, data) }
|
|
96
|
-
: {}),
|
|
97
|
-
};
|
|
98
|
-
}
|
package/lib/cq-message.d.ts
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CQ 码与 MessageSegment 互转。
|
|
3
|
-
* 出站:@icqqjs/cli 要求 message 为非空字符串;引用段编码为 [reply:id](需 cli parse-message 支持 reply,见 scripts/patch-icqq-cli-reply.mjs)。
|
|
4
|
-
* 媒体段双向均为 canonical MediaRef(`data.media`),无 legacy url/file/base64 字段。
|
|
5
|
-
*/
|
|
1
|
+
/** ICQQ 历史文本视图 → canonical MessageSegment。出站只使用原生 Sendable。 */
|
|
6
2
|
import { type MediaRef } from "@zhin.js/core";
|
|
7
|
-
import { MessageSegment
|
|
3
|
+
import type { MessageSegment } from "zhin.js";
|
|
8
4
|
/**
|
|
9
5
|
* CQ 媒体参数 / 入站元素媒体值 → canonical MediaRef:
|
|
10
6
|
* `base64://` → base64;http(s) → url;本机路径 → path;其余视为平台不透明引用(file)。
|
|
11
7
|
*/
|
|
12
8
|
export declare function icqqMediaRefFromString(value: string): MediaRef;
|
|
13
9
|
/**
|
|
14
|
-
* canonical MediaRef(`data.media`,唯一媒体来源)→
|
|
15
|
-
* base64
|
|
16
|
-
* 无 canonical 媒体引用时 warn 并返回 undefined(调用方丢弃该段)。
|
|
10
|
+
* canonical MediaRef(`data.media`,唯一媒体来源)→ ICQQ native
|
|
11
|
+
* element 的 file 参数。base64 使用 ICQQ 原生支持的 `base64://` 前缀。
|
|
17
12
|
*/
|
|
18
|
-
export declare function
|
|
13
|
+
export declare function resolveIcqqMediaFile(data: Record<string, unknown> | undefined): string | undefined;
|
|
19
14
|
export declare function parseCqMessage(raw: string): MessageSegment[];
|
|
20
|
-
/** 构建 icqq send_*_msg 的 message 字符串(非空) */
|
|
21
|
-
export declare function buildIcqqMessage(content: SendContent): string;
|
|
22
|
-
export declare function toCqString(content: SendContent): string;
|
package/lib/cq-message.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CQ 码与 MessageSegment 互转。
|
|
3
|
-
* 出站:@icqqjs/cli 要求 message 为非空字符串;引用段编码为 [reply:id](需 cli parse-message 支持 reply,见 scripts/patch-icqq-cli-reply.mjs)。
|
|
4
|
-
* 媒体段双向均为 canonical MediaRef(`data.media`),无 legacy url/file/base64 字段。
|
|
5
|
-
*/
|
|
1
|
+
/** ICQQ 历史文本视图 → canonical MessageSegment。出站只使用原生 Sendable。 */
|
|
6
2
|
import { isMediaRef } from "@zhin.js/core";
|
|
7
|
-
import { formatCompact, getLogger } from "@zhin.js/logger";
|
|
8
|
-
import { segment } from "zhin.js";
|
|
9
|
-
const logger = getLogger("icqq");
|
|
10
3
|
const MAX_CQ_PARSE_LEN = 256_000;
|
|
11
4
|
/**
|
|
12
5
|
* CQ 媒体参数 / 入站元素媒体值 → canonical MediaRef:
|
|
@@ -25,20 +18,13 @@ export function icqqMediaRefFromString(value) {
|
|
|
25
18
|
return { kind: "file", value };
|
|
26
19
|
}
|
|
27
20
|
/**
|
|
28
|
-
* canonical MediaRef(`data.media`,唯一媒体来源)→
|
|
29
|
-
* base64
|
|
30
|
-
* 无 canonical 媒体引用时 warn 并返回 undefined(调用方丢弃该段)。
|
|
21
|
+
* canonical MediaRef(`data.media`,唯一媒体来源)→ ICQQ native
|
|
22
|
+
* element 的 file 参数。base64 使用 ICQQ 原生支持的 `base64://` 前缀。
|
|
31
23
|
*/
|
|
32
|
-
export function
|
|
24
|
+
export function resolveIcqqMediaFile(data) {
|
|
33
25
|
const media = data?.media;
|
|
34
|
-
if (!isMediaRef(media))
|
|
35
|
-
logger.warn(formatCompact({
|
|
36
|
-
op: "icqq_outbound_media_dropped",
|
|
37
|
-
type,
|
|
38
|
-
reason: "missing_media_ref",
|
|
39
|
-
}));
|
|
26
|
+
if (!isMediaRef(media))
|
|
40
27
|
return undefined;
|
|
41
|
-
}
|
|
42
28
|
if (media.kind === "base64") {
|
|
43
29
|
return media.value.startsWith("base64://") ? media.value : `base64://${media.value}`;
|
|
44
30
|
}
|
|
@@ -68,7 +54,7 @@ function pushCqSegment(segments, type, arg) {
|
|
|
68
54
|
break;
|
|
69
55
|
case "record":
|
|
70
56
|
case "audio":
|
|
71
|
-
segments.push({ type: "
|
|
57
|
+
segments.push({ type: "audio", data: { media: icqqMediaRefFromString(arg) } });
|
|
72
58
|
break;
|
|
73
59
|
case "video":
|
|
74
60
|
segments.push({ type: "video", data: { media: icqqMediaRefFromString(arg) } });
|
|
@@ -118,55 +104,3 @@ export function parseCqMessage(raw) {
|
|
|
118
104
|
}
|
|
119
105
|
return segments.length ? segments : [{ type: "text", data: { text: raw } }];
|
|
120
106
|
}
|
|
121
|
-
/** 构建 icqq send_*_msg 的 message 字符串(非空) */
|
|
122
|
-
export function buildIcqqMessage(content) {
|
|
123
|
-
let message = toCqString(content).trim();
|
|
124
|
-
if (!message)
|
|
125
|
-
message = "\u200b";
|
|
126
|
-
return message;
|
|
127
|
-
}
|
|
128
|
-
export function toCqString(content) {
|
|
129
|
-
if (!Array.isArray(content))
|
|
130
|
-
content = [content];
|
|
131
|
-
return content
|
|
132
|
-
.map((seg) => {
|
|
133
|
-
if (typeof seg === "string")
|
|
134
|
-
return seg;
|
|
135
|
-
const { type, data } = seg;
|
|
136
|
-
switch (type) {
|
|
137
|
-
case "text":
|
|
138
|
-
return data.text ?? "";
|
|
139
|
-
case "face":
|
|
140
|
-
return `[face:${data.id}]`;
|
|
141
|
-
case "image": {
|
|
142
|
-
const arg = resolveCqMediaArg("image", data);
|
|
143
|
-
return arg ? `[image:${arg}]` : "";
|
|
144
|
-
}
|
|
145
|
-
case "at":
|
|
146
|
-
case "mention": {
|
|
147
|
-
const target = data.target ?? data.qq ?? data.id ?? data.user_id;
|
|
148
|
-
return `[at:${target}]`;
|
|
149
|
-
}
|
|
150
|
-
case "dice":
|
|
151
|
-
return "[dice]";
|
|
152
|
-
case "rps":
|
|
153
|
-
return "[rps]";
|
|
154
|
-
case "record":
|
|
155
|
-
case "audio": {
|
|
156
|
-
const arg = resolveCqMediaArg("record", data);
|
|
157
|
-
return arg ? `[record:${arg}]` : "";
|
|
158
|
-
}
|
|
159
|
-
case "video": {
|
|
160
|
-
const arg = resolveCqMediaArg("video", data);
|
|
161
|
-
return arg ? `[video:${arg}]` : "";
|
|
162
|
-
}
|
|
163
|
-
case "reply":
|
|
164
|
-
return `[reply:${data.message_id ?? data.id}]`;
|
|
165
|
-
case "json":
|
|
166
|
-
return `[json:${data.text ?? ''}]`;
|
|
167
|
-
default:
|
|
168
|
-
return segment.toString(seg);
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
.join("");
|
|
172
|
-
}
|
package/lib/endpoint.d.ts
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
import { Client } from '@icqqjs/icqq';
|
|
2
2
|
import type { EndpointControl, EndpointInstance, EndpointManagement, EndpointSendRequest } from 'zhin.js/adapter';
|
|
3
|
-
import type {
|
|
3
|
+
import type { EndpointContentPort } from '@zhin.js/adapter';
|
|
4
|
+
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
5
|
+
import { type LoginAssist } from '@zhin.js/core';
|
|
4
6
|
import type { CapabilityId } from 'zhin.js';
|
|
5
7
|
import { type IcqqInboundMessage, type ResolvedIcqqConfig } from './protocol.js';
|
|
6
|
-
export interface IcqqInboxHooks {
|
|
7
|
-
recordRequest(row: Record<string, unknown>): void | Promise<void>;
|
|
8
|
-
recordNotice(row: Record<string, unknown>): void | Promise<void>;
|
|
9
|
-
publish?(type: string, data: unknown): void;
|
|
10
|
-
}
|
|
11
8
|
export interface IcqqEndpointOptions {
|
|
12
9
|
readonly id: CapabilityId;
|
|
13
10
|
readonly gateway: MessageGateway;
|
|
14
11
|
readonly config: ResolvedIcqqConfig;
|
|
15
|
-
readonly
|
|
12
|
+
readonly sideEvents: SideEventGateway;
|
|
13
|
+
readonly loginAssist: LoginAssist;
|
|
16
14
|
}
|
|
17
15
|
export declare class IcqqEndpoint extends Client implements EndpointInstance {
|
|
18
16
|
#private;
|
|
19
17
|
readonly endpointName: string;
|
|
18
|
+
readonly content: EndpointContentPort;
|
|
20
19
|
readonly management: EndpointManagement;
|
|
21
20
|
readonly control: EndpointControl;
|
|
22
21
|
constructor(options: IcqqEndpointOptions);
|
|
23
|
-
start(): Promise<void>;
|
|
22
|
+
start(signal: AbortSignal): Promise<void>;
|
|
24
23
|
open(): void;
|
|
25
|
-
close(): void
|
|
24
|
+
close(): Promise<void>;
|
|
26
25
|
stop(): Promise<void>;
|
|
27
26
|
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
28
|
-
admit(msg: IcqqInboundMessage): void;
|
|
27
|
+
admit(msg: IcqqInboundMessage, admittedBeforeRetire?: boolean): void;
|
|
29
28
|
}
|