@zhin.js/adapter-icqq 4.0.0 → 4.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/CHANGELOG.md +15 -0
- package/README.md +30 -30
- package/client/ICQQManagement.tsx +15 -15
- package/client/LoginAssistPanel.tsx +2 -2
- package/dist/index.js +1 -2
- package/lib/adapter.d.ts +14 -13
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +31 -30
- package/lib/adapter.js.map +1 -1
- package/lib/{bot.d.ts → endpoint.d.ts} +9 -9
- package/lib/endpoint.d.ts.map +1 -0
- package/lib/{bot.js → endpoint.js} +30 -41
- package/lib/endpoint.js.map +1 -0
- package/lib/icqq-side-events.d.ts +2 -2
- package/lib/icqq-side-events.d.ts.map +1 -1
- package/lib/icqq-side-events.js +4 -4
- package/lib/icqq-side-events.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/ipc-client.js +2 -2
- package/lib/ipc-client.js.map +1 -1
- package/lib/outbound-media.d.ts +2 -2
- package/lib/outbound-media.d.ts.map +1 -1
- package/lib/outbound-media.js.map +1 -1
- package/lib/routes.js +14 -14
- package/lib/routes.js.map +1 -1
- package/lib/tools/index.d.ts.map +1 -1
- package/lib/tools/index.js +80 -75
- package/lib/tools/index.js.map +1 -1
- package/lib/types.d.ts +2 -2
- package/lib/types.d.ts.map +1 -1
- package/lib/typing-indicator-example.d.ts +10 -10
- package/lib/typing-indicator-example.d.ts.map +1 -1
- package/lib/typing-indicator-example.js +24 -24
- package/lib/typing-indicator-example.js.map +1 -1
- package/lib/typing-indicator.d.ts +10 -10
- package/lib/typing-indicator.d.ts.map +1 -1
- package/lib/typing-indicator.js +37 -37
- package/lib/typing-indicator.js.map +1 -1
- package/package.json +15 -11
- package/skills/icqq/PERMITS.md +22 -0
- package/src/adapter.ts +33 -31
- package/src/{bot.ts → endpoint.ts} +30 -40
- package/src/icqq-side-events.ts +4 -4
- package/src/index.ts +1 -1
- package/src/ipc-client.ts +2 -2
- package/src/outbound-media.ts +2 -2
- package/src/routes.ts +14 -14
- package/src/tools/index.ts +68 -63
- package/src/types.ts +2 -2
- package/src/typing-indicator-example.ts +25 -25
- package/src/typing-indicator.ts +40 -40
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ICQQ Bot:通过 @icqqjs/cli 守护进程 IPC 通信,实现 zhin
|
|
2
|
+
* ICQQ Bot:通过 @icqqjs/cli 守护进程 IPC 通信,实现 zhin Endpoint 接口
|
|
3
3
|
*
|
|
4
4
|
* 不再直接依赖 @icqqjs/icqq 协议库。
|
|
5
|
-
* 登录由 `icqq login` 完成,本
|
|
5
|
+
* 登录由 `icqq login` 完成,本 Endpoint 只负责连接守护进程并收发消息。
|
|
6
6
|
*/
|
|
7
|
-
import { formatCompact,
|
|
7
|
+
import { formatCompact, Endpoint, Message, segment, SendContent, SendOptions, type QuotedMessagePayload } from 'zhin.js';
|
|
8
8
|
import type {
|
|
9
|
-
|
|
9
|
+
IcqqEndpointConfig,
|
|
10
10
|
IcqqSenderInfo,
|
|
11
11
|
IpcFriendInfo,
|
|
12
12
|
IpcGroupInfo,
|
|
@@ -53,9 +53,9 @@ import { enableTypingIndicator, type ICQQTypingIndicatorManager } from "./typing
|
|
|
53
53
|
import { parseIcqqGetMsgResponse } from "./get-msg.js";
|
|
54
54
|
import { enrichQuotedPayloadWithForward, isForwardPlaceholderPayload } from "./forward-msg.js";
|
|
55
55
|
|
|
56
|
-
export class
|
|
56
|
+
export class IcqqEndpoint implements Endpoint<IcqqEndpointConfig, IcqqIpcMessageEvent> {
|
|
57
57
|
$connected = false;
|
|
58
|
-
$config:
|
|
58
|
+
$config: IcqqEndpointConfig;
|
|
59
59
|
ipc!: IpcClient;
|
|
60
60
|
|
|
61
61
|
/** 缓存的好友列表 */
|
|
@@ -86,7 +86,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
86
86
|
|
|
87
87
|
constructor(
|
|
88
88
|
public adapter: IcqqAdapter,
|
|
89
|
-
config:
|
|
89
|
+
config: IcqqEndpointConfig,
|
|
90
90
|
) {
|
|
91
91
|
this.$config = config;
|
|
92
92
|
}
|
|
@@ -127,7 +127,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
127
127
|
// 如果配置中明确设置为 false,则不启用
|
|
128
128
|
if (typingConfig?.enabled === false) {
|
|
129
129
|
this.logger.debug(formatCompact({
|
|
130
|
-
|
|
130
|
+
endpoint: this.$id,
|
|
131
131
|
typingIndicator: 'disabled_by_config',
|
|
132
132
|
}));
|
|
133
133
|
return;
|
|
@@ -137,13 +137,13 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
137
137
|
try {
|
|
138
138
|
this.$typingIndicator = enableTypingIndicator(this, typingConfig);
|
|
139
139
|
this.logger.debug(formatCompact({
|
|
140
|
-
|
|
140
|
+
endpoint: this.$id,
|
|
141
141
|
typingIndicator: 'enabled',
|
|
142
142
|
emoji: typingConfig?.defaultEmoji || '⏳',
|
|
143
143
|
}));
|
|
144
144
|
} catch (error) {
|
|
145
145
|
this.logger.warn(formatCompact({
|
|
146
|
-
|
|
146
|
+
endpoint: this.$id,
|
|
147
147
|
typingIndicator: 'failed',
|
|
148
148
|
error: error instanceof Error ? error.message : String(error),
|
|
149
149
|
}));
|
|
@@ -209,7 +209,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
209
209
|
this.$connected = false;
|
|
210
210
|
this.logger.warn(formatCompact( {
|
|
211
211
|
op: "disconnect",
|
|
212
|
-
|
|
212
|
+
endpoint: this.$id,
|
|
213
213
|
ok: false,
|
|
214
214
|
delay_ms: delayMs,
|
|
215
215
|
attempt: attempt + 1,
|
|
@@ -222,17 +222,17 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
222
222
|
await this.rebindIpcSession();
|
|
223
223
|
this.logger.info(formatCompact( {
|
|
224
224
|
op: "reconnect",
|
|
225
|
-
|
|
225
|
+
endpoint: this.$id,
|
|
226
226
|
friends: this.friends.size,
|
|
227
227
|
groups: this.groups.size,
|
|
228
228
|
}));
|
|
229
229
|
break;
|
|
230
|
-
} catch (e:
|
|
230
|
+
} catch (e: unknown) {
|
|
231
231
|
this.logger.warn(formatCompact( {
|
|
232
232
|
op: "reconnect",
|
|
233
|
-
|
|
233
|
+
endpoint: this.$id,
|
|
234
234
|
ok: false,
|
|
235
|
-
error: e
|
|
235
|
+
error: e instanceof Error ? e.message : String(e),
|
|
236
236
|
}));
|
|
237
237
|
}
|
|
238
238
|
}
|
|
@@ -282,7 +282,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
282
282
|
this.inboundDeduper.clear();
|
|
283
283
|
this.ipc?.close();
|
|
284
284
|
this.$connected = false;
|
|
285
|
-
this.logger.info(formatCompact( { op: "disconnect",
|
|
285
|
+
this.logger.info(formatCompact( { op: "disconnect", endpoint: this.$id }));
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
// ── 消息处理 ───────────────────────────────────────────────────────
|
|
@@ -394,7 +394,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
394
394
|
formatCompact({
|
|
395
395
|
notice: notice.$type,
|
|
396
396
|
channel: `${notice.$channel.type}(${notice.$channel.id})`,
|
|
397
|
-
|
|
397
|
+
endpoint: this.$id,
|
|
398
398
|
sub_type: notice.$subType,
|
|
399
399
|
}),
|
|
400
400
|
);
|
|
@@ -414,7 +414,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
414
414
|
formatCompact({
|
|
415
415
|
request: request.$type,
|
|
416
416
|
channel: `${request.$channel.type}(${request.$channel.id})`,
|
|
417
|
-
|
|
417
|
+
endpoint: this.$id,
|
|
418
418
|
from: request.$sender.id,
|
|
419
419
|
}),
|
|
420
420
|
);
|
|
@@ -489,16 +489,6 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
489
489
|
senderInfo.permissions = ["admin"];
|
|
490
490
|
}
|
|
491
491
|
}
|
|
492
|
-
if (normalized.senderRole && normalized.senderRole !== "member") {
|
|
493
|
-
senderInfo.role = normalized.senderRole;
|
|
494
|
-
if (normalized.senderRole === "owner") {
|
|
495
|
-
senderInfo.isOwner = true;
|
|
496
|
-
senderInfo.permissions = ["owner"];
|
|
497
|
-
} else if (normalized.senderRole === "admin") {
|
|
498
|
-
senderInfo.isAdmin = true;
|
|
499
|
-
senderInfo.permissions = ["admin"];
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
492
|
|
|
503
493
|
const quoteId =
|
|
504
494
|
Message.quoteIdFromContent(normalized.content) ??
|
|
@@ -508,7 +498,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
508
498
|
const result = Message.from(raw, {
|
|
509
499
|
$id: normalized.messageId,
|
|
510
500
|
$adapter: "icqq" as const,
|
|
511
|
-
$
|
|
501
|
+
$endpoint: this.$config.name,
|
|
512
502
|
$sender: senderInfo,
|
|
513
503
|
$channel: {
|
|
514
504
|
id: normalized.channelId,
|
|
@@ -522,7 +512,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
522
512
|
if (normalized.idSource === "synthetic") {
|
|
523
513
|
this.logger.warn(formatCompact( {
|
|
524
514
|
op: "recall",
|
|
525
|
-
|
|
515
|
+
endpoint: this.$id,
|
|
526
516
|
ok: false,
|
|
527
517
|
error: "no message_id in push",
|
|
528
518
|
}));
|
|
@@ -544,7 +534,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
544
534
|
return await this.adapter.sendMessage({
|
|
545
535
|
...result.$channel,
|
|
546
536
|
context: "icqq",
|
|
547
|
-
|
|
537
|
+
endpoint: this.$config.name,
|
|
548
538
|
content,
|
|
549
539
|
});
|
|
550
540
|
},
|
|
@@ -640,7 +630,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
640
630
|
if (!resp.ok) {
|
|
641
631
|
this.logger.warn(formatCompact( {
|
|
642
632
|
op: "recall",
|
|
643
|
-
|
|
633
|
+
endpoint: this.$id,
|
|
644
634
|
ok: false,
|
|
645
635
|
error: resp.error,
|
|
646
636
|
}));
|
|
@@ -717,7 +707,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
717
707
|
}
|
|
718
708
|
|
|
719
709
|
// 从映射中查找
|
|
720
|
-
const id =
|
|
710
|
+
const id = IcqqEndpoint.EMOJI_MAP[emoji];
|
|
721
711
|
if (id) {
|
|
722
712
|
return id;
|
|
723
713
|
}
|
|
@@ -745,7 +735,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
745
735
|
if (!resp.ok) {
|
|
746
736
|
this.logger.warn(formatCompact({
|
|
747
737
|
op: "add_reaction",
|
|
748
|
-
|
|
738
|
+
endpoint: this.$id,
|
|
749
739
|
message_id: messageId,
|
|
750
740
|
emoji,
|
|
751
741
|
id: emojiId,
|
|
@@ -757,7 +747,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
757
747
|
|
|
758
748
|
this.logger.debug(formatCompact({
|
|
759
749
|
op: "add_reaction",
|
|
760
|
-
|
|
750
|
+
endpoint: this.$id,
|
|
761
751
|
message_id: messageId,
|
|
762
752
|
emoji,
|
|
763
753
|
id: emojiId,
|
|
@@ -769,7 +759,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
769
759
|
} catch (error) {
|
|
770
760
|
this.logger.warn(formatCompact({
|
|
771
761
|
op: "add_reaction",
|
|
772
|
-
|
|
762
|
+
endpoint: this.$id,
|
|
773
763
|
message_id: messageId,
|
|
774
764
|
emoji,
|
|
775
765
|
ok: false,
|
|
@@ -801,7 +791,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
801
791
|
if (!resp.ok) {
|
|
802
792
|
this.logger.warn(formatCompact({
|
|
803
793
|
op: "remove_reaction",
|
|
804
|
-
|
|
794
|
+
endpoint: this.$id,
|
|
805
795
|
message_id: messageId,
|
|
806
796
|
reaction_id: reactionId,
|
|
807
797
|
id: emojiId,
|
|
@@ -811,7 +801,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
811
801
|
} else {
|
|
812
802
|
this.logger.debug(formatCompact({
|
|
813
803
|
op: "remove_reaction",
|
|
814
|
-
|
|
804
|
+
endpoint: this.$id,
|
|
815
805
|
message_id: messageId,
|
|
816
806
|
reaction_id: reactionId,
|
|
817
807
|
id: emojiId,
|
|
@@ -821,7 +811,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
821
811
|
} catch (error) {
|
|
822
812
|
this.logger.warn(formatCompact({
|
|
823
813
|
op: "remove_reaction",
|
|
824
|
-
|
|
814
|
+
endpoint: this.$id,
|
|
825
815
|
message_id: messageId,
|
|
826
816
|
reaction_id: reactionId,
|
|
827
817
|
ok: false,
|
|
@@ -832,7 +822,7 @@ export class IcqqBot implements Bot<IcqqBotConfig, IcqqIpcMessageEvent> {
|
|
|
832
822
|
}
|
|
833
823
|
|
|
834
824
|
/** @deprecated 使用 `./cq-message.js` 导出 */
|
|
835
|
-
export namespace
|
|
825
|
+
export namespace IcqqEndpoint {
|
|
836
826
|
export const parseCqMessage = parseCqMessageImpl;
|
|
837
827
|
export const buildIcqqIpcMessage = buildIcqqIpcMessageImpl;
|
|
838
828
|
export const toCqString = toCqStringImpl;
|
package/src/icqq-side-events.ts
CHANGED
|
@@ -116,7 +116,7 @@ function senderFromId(id: unknown, name?: string) {
|
|
|
116
116
|
|
|
117
117
|
export function formatIcqqNotice(
|
|
118
118
|
event: IcqqIpcRawEvent,
|
|
119
|
-
|
|
119
|
+
endpointName: string,
|
|
120
120
|
): ReturnType<typeof Notice.from<IcqqIpcRawEvent>> {
|
|
121
121
|
const $type = resolveNoticeZhinType(event);
|
|
122
122
|
const isGroup = event.group_id != null;
|
|
@@ -128,7 +128,7 @@ export function formatIcqqNotice(
|
|
|
128
128
|
return Notice.from(event, {
|
|
129
129
|
$id: resolveSideEventDedupeKey(event, "notice"),
|
|
130
130
|
$adapter: "icqq",
|
|
131
|
-
$
|
|
131
|
+
$endpoint: endpointName,
|
|
132
132
|
$type,
|
|
133
133
|
$subType: event.sub_type,
|
|
134
134
|
$channel: {
|
|
@@ -152,7 +152,7 @@ function resolveRequestZhinType(event: IcqqIpcRawEvent): RequestType {
|
|
|
152
152
|
|
|
153
153
|
export function formatIcqqRequest(
|
|
154
154
|
event: IcqqIpcRawEvent,
|
|
155
|
-
|
|
155
|
+
endpointName: string,
|
|
156
156
|
ipc: IpcClient,
|
|
157
157
|
): ReturnType<typeof Request.from<IcqqIpcRawEvent>> {
|
|
158
158
|
const $type = resolveRequestZhinType(event);
|
|
@@ -169,7 +169,7 @@ export function formatIcqqRequest(
|
|
|
169
169
|
return Request.from(event, {
|
|
170
170
|
$id: String(flag),
|
|
171
171
|
$adapter: "icqq",
|
|
172
|
-
$
|
|
172
|
+
$endpoint: endpointName,
|
|
173
173
|
$type,
|
|
174
174
|
$subType: event.sub_type,
|
|
175
175
|
$channel: {
|
package/src/index.ts
CHANGED
package/src/ipc-client.ts
CHANGED
|
@@ -162,7 +162,7 @@ export class IpcClient {
|
|
|
162
162
|
sock.on("error", (err) =>
|
|
163
163
|
reject(
|
|
164
164
|
new Error(
|
|
165
|
-
`无法连接 icqq 守护进程 (${getSocketPath(uin)}): ${err.message}。请先执行: icqq login`,
|
|
165
|
+
`无法连接 icqq 守护进程 (${getSocketPath(uin)}): ${err instanceof Error ? err.message : String(err)}。请先执行: icqq login`,
|
|
166
166
|
),
|
|
167
167
|
),
|
|
168
168
|
);
|
|
@@ -204,7 +204,7 @@ export class IpcClient {
|
|
|
204
204
|
sock.on("connect", () => resolve(new IpcClient(sock, true)));
|
|
205
205
|
sock.on("error", (err) =>
|
|
206
206
|
reject(
|
|
207
|
-
new Error(`无法连接 icqq RPC 服务 (${host}:${port}): ${err.message}`),
|
|
207
|
+
new Error(`无法连接 icqq RPC 服务 (${host}:${port}): ${err instanceof Error ? err.message : String(err)}`),
|
|
208
208
|
),
|
|
209
209
|
);
|
|
210
210
|
});
|
package/src/outbound-media.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import * as crypto from "node:crypto";
|
|
5
5
|
import type { MessageSegment, SendContent } from "zhin.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { IcqqEndpointConfig } from "./types.js";
|
|
7
7
|
|
|
8
8
|
export type IcqqOutboundMediaMode = "file" | "base64";
|
|
9
9
|
|
|
@@ -38,7 +38,7 @@ function spoolBase64ToFile(
|
|
|
38
38
|
* base64=保留 segment.base64,CQ 编码为 [image:base64://...] 经 IPC 交给守护进程解码(异机 RPC 默认)。
|
|
39
39
|
*/
|
|
40
40
|
export function resolveIcqqOutboundMediaMode(
|
|
41
|
-
config: Pick<
|
|
41
|
+
config: Pick<IcqqEndpointConfig, "rpc" | "outboundMedia">,
|
|
42
42
|
): IcqqOutboundMediaMode {
|
|
43
43
|
if (config.outboundMedia === "base64" || config.outboundMedia === "file") {
|
|
44
44
|
return config.outboundMedia;
|
package/src/routes.ts
CHANGED
|
@@ -11,29 +11,29 @@ export function registerRoutes(
|
|
|
11
11
|
icqq: IcqqAdapter,
|
|
12
12
|
_root: Plugin,
|
|
13
13
|
) {
|
|
14
|
-
router.get("/api/icqq/
|
|
14
|
+
router.get("/api/icqq/endpoints", async (ctx) => {
|
|
15
15
|
try {
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
ctx.body = { success: true, data: [], message: "暂无
|
|
16
|
+
const endpoints = Array.from(icqq.endpoints.values());
|
|
17
|
+
if (endpoints.length === 0) {
|
|
18
|
+
ctx.body = { success: true, data: [], message: "暂无ICQQEndpoint 实例" };
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const result = await Promise.all(
|
|
22
|
-
|
|
22
|
+
endpoints.map(async (endpoint) => {
|
|
23
23
|
try {
|
|
24
24
|
const base: Record<string, unknown> = {
|
|
25
|
-
name:
|
|
26
|
-
connected:
|
|
27
|
-
groupCount:
|
|
28
|
-
friendCount:
|
|
29
|
-
status:
|
|
25
|
+
name: endpoint.$config.name,
|
|
26
|
+
connected: endpoint.$connected || false,
|
|
27
|
+
groupCount: endpoint.groups.size,
|
|
28
|
+
friendCount: endpoint.friends.size,
|
|
29
|
+
status: endpoint.$connected ? "online" : "offline",
|
|
30
30
|
lastActivity: new Date().toISOString(),
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
// 尝试从守护进程获取详细状态
|
|
34
|
-
if (
|
|
34
|
+
if (endpoint.$connected && endpoint.ipc && !endpoint.ipc.closed) {
|
|
35
35
|
try {
|
|
36
|
-
const statusResp = await
|
|
36
|
+
const statusResp = await endpoint.ipc.request(
|
|
37
37
|
Actions.GET_STATUS,
|
|
38
38
|
{},
|
|
39
39
|
5000,
|
|
@@ -51,7 +51,7 @@ export function registerRoutes(
|
|
|
51
51
|
return base;
|
|
52
52
|
} catch {
|
|
53
53
|
return {
|
|
54
|
-
name:
|
|
54
|
+
name: endpoint.$config.name,
|
|
55
55
|
connected: false,
|
|
56
56
|
groupCount: 0,
|
|
57
57
|
friendCount: 0,
|
|
@@ -71,7 +71,7 @@ export function registerRoutes(
|
|
|
71
71
|
ctx.body = {
|
|
72
72
|
success: false,
|
|
73
73
|
error: "ICQQ_API_ERROR",
|
|
74
|
-
message: "
|
|
74
|
+
message: "获取 Endpoint 数据失败",
|
|
75
75
|
details:
|
|
76
76
|
process.env.NODE_ENV === "development"
|
|
77
77
|
? (error as Error).message
|