@izhimu/qq 0.1.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/LICENSE +21 -0
- package/README.md +388 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +19 -0
- package/dist/src/adapters/message.d.ts +8 -0
- package/dist/src/adapters/message.js +152 -0
- package/dist/src/channel.d.ts +7 -0
- package/dist/src/channel.js +312 -0
- package/dist/src/core/config.d.ts +22 -0
- package/dist/src/core/config.js +32 -0
- package/dist/src/core/connection.d.ts +65 -0
- package/dist/src/core/connection.js +328 -0
- package/dist/src/core/dispatch.d.ts +54 -0
- package/dist/src/core/dispatch.js +285 -0
- package/dist/src/core/request.d.ts +26 -0
- package/dist/src/core/request.js +115 -0
- package/dist/src/core/runtime.d.ts +16 -0
- package/dist/src/core/runtime.js +48 -0
- package/dist/src/onboarding.d.ts +10 -0
- package/dist/src/onboarding.js +98 -0
- package/dist/src/types/index.d.ts +261 -0
- package/dist/src/types/index.js +5 -0
- package/dist/src/utils/cqcode.d.ts +33 -0
- package/dist/src/utils/cqcode.js +102 -0
- package/dist/src/utils/index.d.ts +51 -0
- package/dist/src/utils/index.js +250 -0
- package/dist/src/utils/log.d.ts +6 -0
- package/dist/src/utils/log.js +23 -0
- package/dist/src/utils/markdown.d.ts +29 -0
- package/dist/src/utils/markdown.js +137 -0
- package/openclaw.plugin.json +11 -0
- package/package.json +61 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQ NapCat Plugin for OpenClaw
|
|
3
|
+
* Main plugin entry point
|
|
4
|
+
*/
|
|
5
|
+
import { buildChannelConfigSchema, DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
|
|
6
|
+
import { messageIdToString, Logger as log } from "./utils/index.js";
|
|
7
|
+
import { setContext, setContextStatus, clearContext, setConnection, getConnection, clearConnection } from "./core/runtime.js";
|
|
8
|
+
import { ConnectionManager } from "./core/connection.js";
|
|
9
|
+
import { openClawToNapCatMessage } from "./adapters/message.js";
|
|
10
|
+
import { listQQAccountIds, resolveQQAccount, QQConfigSchema, CHANNEL_ID } from "./core/config.js";
|
|
11
|
+
import { eventListener, sendMsg } from "./core/request.js";
|
|
12
|
+
import { qqOnboardingAdapter } from "./onboarding.js";
|
|
13
|
+
export const qqPlugin = {
|
|
14
|
+
id: CHANNEL_ID,
|
|
15
|
+
meta: {
|
|
16
|
+
id: CHANNEL_ID,
|
|
17
|
+
label: "QQ",
|
|
18
|
+
selectionLabel: "QQ",
|
|
19
|
+
docsPath: "/channels/qq",
|
|
20
|
+
blurb: "通过 NapCat WebSocket 连接 QQ 机器人",
|
|
21
|
+
},
|
|
22
|
+
capabilities: {
|
|
23
|
+
chatTypes: ["direct", "group"],
|
|
24
|
+
reactions: true,
|
|
25
|
+
reply: true,
|
|
26
|
+
media: true,
|
|
27
|
+
blockStreaming: true,
|
|
28
|
+
},
|
|
29
|
+
reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },
|
|
30
|
+
onboarding: qqOnboardingAdapter,
|
|
31
|
+
config: {
|
|
32
|
+
listAccountIds: (cfg) => listQQAccountIds(cfg),
|
|
33
|
+
resolveAccount: (cfg) => resolveQQAccount({ cfg }),
|
|
34
|
+
isEnabled: (account) => Boolean(account?.enabled),
|
|
35
|
+
isConfigured: (account) => Boolean(account?.wsUrl),
|
|
36
|
+
},
|
|
37
|
+
configSchema: buildChannelConfigSchema(QQConfigSchema),
|
|
38
|
+
messaging: {
|
|
39
|
+
normalizeTarget: (target) => {
|
|
40
|
+
return target.replace(/^qq:/i, "");
|
|
41
|
+
},
|
|
42
|
+
targetResolver: {
|
|
43
|
+
looksLikeId: (id) => {
|
|
44
|
+
const normalized = id.replace(/^qq:/i, "");
|
|
45
|
+
// 支持 private:xxx, group:xxx 格式
|
|
46
|
+
if (normalized.startsWith("private:") || normalized.startsWith("group:"))
|
|
47
|
+
return true;
|
|
48
|
+
// 支持纯数字QQ号或群号
|
|
49
|
+
return /^\d+$/.test(normalized);
|
|
50
|
+
},
|
|
51
|
+
hint: "private:<qqId> or group:<groupId>",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
outbound: {
|
|
55
|
+
deliveryMode: "direct",
|
|
56
|
+
sendText: async (ctx) => {
|
|
57
|
+
const { to, text, accountId, cfg, replyToId } = ctx;
|
|
58
|
+
if (!accountId) {
|
|
59
|
+
return {
|
|
60
|
+
channel: CHANNEL_ID,
|
|
61
|
+
messageId: "",
|
|
62
|
+
error: new Error("accountId is required"),
|
|
63
|
+
deliveredAt: Date.now(),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const account = resolveQQAccount({ cfg });
|
|
67
|
+
if (!account) {
|
|
68
|
+
return {
|
|
69
|
+
channel: CHANNEL_ID,
|
|
70
|
+
messageId: "",
|
|
71
|
+
error: new Error(`Account not found: ${accountId}`),
|
|
72
|
+
deliveredAt: Date.now(),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const connection = getConnection();
|
|
76
|
+
if (!connection?.isConnected()) {
|
|
77
|
+
return {
|
|
78
|
+
channel: CHANNEL_ID,
|
|
79
|
+
messageId: "",
|
|
80
|
+
error: new Error(`Not connected for account: ${accountId}`),
|
|
81
|
+
deliveredAt: Date.now(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Parse target (format: private:xxx or group:xxx)
|
|
85
|
+
const parts = to.split(":");
|
|
86
|
+
const type = parts[0];
|
|
87
|
+
const id = parts[1];
|
|
88
|
+
const chatType = type === "group" ? "group" : "direct";
|
|
89
|
+
const chatId = id || to;
|
|
90
|
+
try {
|
|
91
|
+
const messageSegments = openClawToNapCatMessage([{ type: "text", text }], replyToId ?? undefined);
|
|
92
|
+
const response = await sendMsg({
|
|
93
|
+
message_type: chatType === "direct" ? "private" : "group",
|
|
94
|
+
user_id: chatType === "direct" ? chatId : undefined,
|
|
95
|
+
group_id: chatType === "group" ? chatId : undefined,
|
|
96
|
+
message: messageSegments,
|
|
97
|
+
});
|
|
98
|
+
// Update lastOutboundAt timestamp on successful send
|
|
99
|
+
if (response.status === "ok") {
|
|
100
|
+
setContextStatus({
|
|
101
|
+
lastOutboundAt: Date.now(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (response.status === "ok" && response.data) {
|
|
105
|
+
const data = response.data;
|
|
106
|
+
return {
|
|
107
|
+
channel: CHANNEL_ID,
|
|
108
|
+
messageId: messageIdToString(data.message_id),
|
|
109
|
+
deliveredAt: Date.now(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return {
|
|
114
|
+
channel: CHANNEL_ID,
|
|
115
|
+
messageId: "",
|
|
116
|
+
error: new Error(response.msg || "Send failed"),
|
|
117
|
+
deliveredAt: Date.now(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
123
|
+
return {
|
|
124
|
+
channel: CHANNEL_ID,
|
|
125
|
+
messageId: "",
|
|
126
|
+
error: new Error(errorMessage),
|
|
127
|
+
deliveredAt: Date.now(),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
sendMedia: async (ctx) => {
|
|
132
|
+
const { to, mediaUrl, accountId, cfg, replyToId } = ctx;
|
|
133
|
+
log.debug("outbound", `sendMedia called - accountId: ${accountId}, to: ${to}, mediaUrl: ${mediaUrl ?? "null"}, replyToId: ${replyToId ?? "none"}`);
|
|
134
|
+
if (!accountId) {
|
|
135
|
+
log.warn("outbound", "sendMedia failed: accountId is required");
|
|
136
|
+
return {
|
|
137
|
+
channel: CHANNEL_ID,
|
|
138
|
+
messageId: "",
|
|
139
|
+
error: new Error("accountId is required"),
|
|
140
|
+
deliveredAt: Date.now(),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// Validate mediaUrl - check for null, undefined, empty string, or invalid URL
|
|
144
|
+
if (mediaUrl === null || mediaUrl === undefined || mediaUrl === "") {
|
|
145
|
+
log.warn("outbound", `sendMedia failed: mediaUrl is invalid (value: ${String(mediaUrl)})`);
|
|
146
|
+
return {
|
|
147
|
+
channel: CHANNEL_ID,
|
|
148
|
+
messageId: "",
|
|
149
|
+
error: new Error(`mediaUrl is required but received: ${mediaUrl === null ? "null" : mediaUrl === undefined ? "undefined" : "empty string"}`),
|
|
150
|
+
deliveredAt: Date.now(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// Check if mediaUrl looks like a valid URL or file path
|
|
154
|
+
const trimmedUrl = String(mediaUrl).trim();
|
|
155
|
+
if (trimmedUrl === "" || trimmedUrl.length < 3) {
|
|
156
|
+
log.warn("outbound", `sendMedia failed: mediaUrl is too short or empty after trim`);
|
|
157
|
+
return {
|
|
158
|
+
channel: CHANNEL_ID,
|
|
159
|
+
messageId: "",
|
|
160
|
+
error: new Error(`mediaUrl appears to be invalid: "${trimmedUrl}"`),
|
|
161
|
+
deliveredAt: Date.now(),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const account = resolveQQAccount({ cfg });
|
|
165
|
+
if (!account) {
|
|
166
|
+
log.warn("outbound", `sendMedia failed: Account not found: ${accountId}`);
|
|
167
|
+
return {
|
|
168
|
+
channel: CHANNEL_ID,
|
|
169
|
+
messageId: "",
|
|
170
|
+
error: new Error(`Account not found: ${accountId}`),
|
|
171
|
+
deliveredAt: Date.now(),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const connection = getConnection();
|
|
175
|
+
if (!connection?.isConnected()) {
|
|
176
|
+
log.warn("outbound", `sendMedia failed: Not connected for account: ${accountId}`);
|
|
177
|
+
return {
|
|
178
|
+
channel: CHANNEL_ID,
|
|
179
|
+
messageId: "",
|
|
180
|
+
error: new Error(`Not connected for account: ${accountId}`),
|
|
181
|
+
deliveredAt: Date.now(),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// Parse target (format: private:xxx or group:xxx)
|
|
185
|
+
const parts = to.split(":");
|
|
186
|
+
const type = parts[0];
|
|
187
|
+
const id = parts[1];
|
|
188
|
+
const chatType = type === "group" ? "group" : "direct";
|
|
189
|
+
const chatId = id || to;
|
|
190
|
+
log.debug("outbound", `Sending media to ${chatType}:${chatId}, url: ${trimmedUrl.substring(0, 100)}${trimmedUrl.length > 100 ? "..." : ""}`);
|
|
191
|
+
try {
|
|
192
|
+
// Build media segment - NapCat requires 'file' field
|
|
193
|
+
// file can be: URL, file path, or base64
|
|
194
|
+
const mediaSegment = {
|
|
195
|
+
type: "image",
|
|
196
|
+
data: {
|
|
197
|
+
file: trimmedUrl,
|
|
198
|
+
url: trimmedUrl,
|
|
199
|
+
summary: "[图片]",
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
// Build message segments with optional reply
|
|
203
|
+
const messageSegments = [];
|
|
204
|
+
if (replyToId) {
|
|
205
|
+
messageSegments.push({ type: "reply", data: { id: replyToId } });
|
|
206
|
+
}
|
|
207
|
+
messageSegments.push(mediaSegment);
|
|
208
|
+
log.debug("outbound", `Message segments: ${JSON.stringify(messageSegments)}`);
|
|
209
|
+
const response = await sendMsg({
|
|
210
|
+
message_type: chatType === "direct" ? "private" : "group",
|
|
211
|
+
user_id: chatType === "direct" ? chatId : undefined,
|
|
212
|
+
group_id: chatType === "group" ? chatId : undefined,
|
|
213
|
+
message: messageSegments,
|
|
214
|
+
});
|
|
215
|
+
log.debug("outbound", `NapCat response - status: ${response.status}, retcode: ${response.retcode}, msg: ${response.msg ?? "none"}, data: ${JSON.stringify(response.data)}`);
|
|
216
|
+
// Update lastOutboundAt timestamp on successful send
|
|
217
|
+
if (response.status === "ok") {
|
|
218
|
+
setContextStatus({
|
|
219
|
+
lastOutboundAt: Date.now(),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (response.status === "ok" && response.data) {
|
|
223
|
+
const data = response.data;
|
|
224
|
+
log.debug("outbound", `Media sent successfully, message_id: ${data.message_id}`);
|
|
225
|
+
return {
|
|
226
|
+
channel: CHANNEL_ID,
|
|
227
|
+
messageId: messageIdToString(data.message_id),
|
|
228
|
+
deliveredAt: Date.now(),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
const errorMsg = response.msg || "Send media failed";
|
|
233
|
+
log.warn("outbound", `sendMedia failed - status: ${response.status}, retcode: ${response.retcode}, msg: ${errorMsg}`);
|
|
234
|
+
return {
|
|
235
|
+
channel: CHANNEL_ID,
|
|
236
|
+
messageId: "",
|
|
237
|
+
error: new Error(`NapCat error [${response.retcode ?? "unknown"}]: ${errorMsg}`),
|
|
238
|
+
deliveredAt: Date.now(),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
244
|
+
log.error("outbound", `sendMedia exception: ${errorMessage}`);
|
|
245
|
+
return {
|
|
246
|
+
channel: CHANNEL_ID,
|
|
247
|
+
messageId: "",
|
|
248
|
+
error: new Error(`sendMedia error: ${errorMessage}`),
|
|
249
|
+
deliveredAt: Date.now(),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
status: {
|
|
255
|
+
buildAccountSnapshot: ({ account, runtime }) => {
|
|
256
|
+
return {
|
|
257
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
258
|
+
name: CHANNEL_ID,
|
|
259
|
+
enabled: account.enabled,
|
|
260
|
+
configured: Boolean(account.wsUrl),
|
|
261
|
+
...runtime,
|
|
262
|
+
};
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
gateway: {
|
|
266
|
+
startAccount: async (ctx) => {
|
|
267
|
+
setContext(ctx);
|
|
268
|
+
const { account } = ctx;
|
|
269
|
+
log.info('gateway', `Starting gateway`);
|
|
270
|
+
// Update start time
|
|
271
|
+
ctx.setStatus({
|
|
272
|
+
...ctx.getStatus(),
|
|
273
|
+
running: true,
|
|
274
|
+
lastStartAt: Date.now(),
|
|
275
|
+
});
|
|
276
|
+
// Create new connection manager
|
|
277
|
+
const connection = new ConnectionManager(account);
|
|
278
|
+
connection.on("event", (event) => eventListener(event));
|
|
279
|
+
connection.on("state-changed", (status) => {
|
|
280
|
+
log.info('gateway', `State: ${status.state}`);
|
|
281
|
+
if (status.state === "connected") {
|
|
282
|
+
setContextStatus({
|
|
283
|
+
connected: true,
|
|
284
|
+
lastConnectedAt: Date.now(),
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
else if (status.state === "disconnected" || status.state === "failed") {
|
|
288
|
+
setContextStatus({
|
|
289
|
+
connected: false,
|
|
290
|
+
lastError: status.error,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
await connection.start();
|
|
295
|
+
setConnection(connection);
|
|
296
|
+
log.info('gateway', `Started gateway`);
|
|
297
|
+
},
|
|
298
|
+
stopAccount: async (_ctx) => {
|
|
299
|
+
const connection = getConnection();
|
|
300
|
+
if (connection) {
|
|
301
|
+
await connection.stop();
|
|
302
|
+
clearConnection();
|
|
303
|
+
}
|
|
304
|
+
setContextStatus({
|
|
305
|
+
running: false,
|
|
306
|
+
connected: false,
|
|
307
|
+
lastStopAt: Date.now(),
|
|
308
|
+
});
|
|
309
|
+
clearContext();
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQ 配置管理
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
5
|
+
import type { QQConfig } from "../types/index.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
export declare const CHANNEL_ID = "qq";
|
|
8
|
+
/**
|
|
9
|
+
* 列出所有 QQ 账户ID
|
|
10
|
+
*/
|
|
11
|
+
export declare function listQQAccountIds(cfg: OpenClawConfig): string[];
|
|
12
|
+
/**
|
|
13
|
+
* 解析 QQ 账户配置
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveQQAccount(params: {
|
|
16
|
+
cfg: OpenClawConfig;
|
|
17
|
+
}): QQConfig;
|
|
18
|
+
export declare const QQConfigSchema: z.ZodObject<{
|
|
19
|
+
wsUrl: z.ZodDefault<z.ZodString>;
|
|
20
|
+
accessToken: z.ZodDefault<z.ZodString>;
|
|
21
|
+
enable: z.ZodDefault<z.ZodBoolean>;
|
|
22
|
+
}, z.core.$strip>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QQ 配置管理
|
|
3
|
+
*/
|
|
4
|
+
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
export const CHANNEL_ID = "qq";
|
|
7
|
+
/**
|
|
8
|
+
* 列出所有 QQ 账户ID
|
|
9
|
+
*/
|
|
10
|
+
export function listQQAccountIds(cfg) {
|
|
11
|
+
const config = cfg.channels?.[CHANNEL_ID];
|
|
12
|
+
if (config?.wsUrl) {
|
|
13
|
+
return [DEFAULT_ACCOUNT_ID];
|
|
14
|
+
}
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 解析 QQ 账户配置
|
|
19
|
+
*/
|
|
20
|
+
export function resolveQQAccount(params) {
|
|
21
|
+
const config = params.cfg.channels?.[CHANNEL_ID];
|
|
22
|
+
return {
|
|
23
|
+
enabled: config?.enabled !== false,
|
|
24
|
+
wsUrl: config?.wsUrl ?? "",
|
|
25
|
+
accessToken: config?.accessToken,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export const QQConfigSchema = z.object({
|
|
29
|
+
wsUrl: z.string().default("ws://127.0.0.1:3001"),
|
|
30
|
+
accessToken: z.string().default("access-token"),
|
|
31
|
+
enable: z.boolean().default(true)
|
|
32
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Connection Manager for NapCat
|
|
3
|
+
* Handles per-account WebSocket connections with auto-reconnect and heartbeat
|
|
4
|
+
*/
|
|
5
|
+
import EventEmitter from 'events';
|
|
6
|
+
import type { NapCatResp, QQConfig, ConnectionStatus, NapCatAction } from '../types/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Connection Manager for a single NapCat account
|
|
9
|
+
*/
|
|
10
|
+
export declare class ConnectionManager extends EventEmitter {
|
|
11
|
+
private config;
|
|
12
|
+
private ws;
|
|
13
|
+
private state;
|
|
14
|
+
private lastHeartbeatTime;
|
|
15
|
+
private totalReconnectAttempts;
|
|
16
|
+
private reconnectTimer?;
|
|
17
|
+
private reconnectAttempts;
|
|
18
|
+
private shouldReconnect;
|
|
19
|
+
private pendingRequests;
|
|
20
|
+
private healthStatus;
|
|
21
|
+
constructor(config: QQConfig);
|
|
22
|
+
/**
|
|
23
|
+
* Start the connection
|
|
24
|
+
*/
|
|
25
|
+
start(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Stop the connection
|
|
28
|
+
*/
|
|
29
|
+
stop(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Establish WebSocket connection
|
|
32
|
+
*/
|
|
33
|
+
private connect;
|
|
34
|
+
/**
|
|
35
|
+
* Close WebSocket connection
|
|
36
|
+
*/
|
|
37
|
+
private close;
|
|
38
|
+
private handleOpen;
|
|
39
|
+
private handleMessage;
|
|
40
|
+
/**
|
|
41
|
+
* Handle OneBot 11 meta_event (lifecycle and heartbeat)
|
|
42
|
+
*/
|
|
43
|
+
private handleMetaEvent;
|
|
44
|
+
private handleError;
|
|
45
|
+
private handleClose;
|
|
46
|
+
private handleConnectionFailed;
|
|
47
|
+
private handleResponse;
|
|
48
|
+
private isNormalClosure;
|
|
49
|
+
private scheduleReconnect;
|
|
50
|
+
private clearReconnectTimer;
|
|
51
|
+
/**
|
|
52
|
+
* Send a request and wait for response
|
|
53
|
+
*/
|
|
54
|
+
sendRequest<Req = unknown, Resp = unknown>(action: NapCatAction, params?: Req): Promise<NapCatResp<Resp>>;
|
|
55
|
+
private setState;
|
|
56
|
+
/**
|
|
57
|
+
* Get current connection status
|
|
58
|
+
*/
|
|
59
|
+
getStatus(): ConnectionStatus;
|
|
60
|
+
/**
|
|
61
|
+
* Check if connected
|
|
62
|
+
*/
|
|
63
|
+
isConnected(): boolean;
|
|
64
|
+
}
|
|
65
|
+
export declare function failResp<T>(msg?: string): Promise<NapCatResp<T>>;
|