openclaw-stepfun 0.2.2

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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/index.d.ts +13 -0
  4. package/dist/index.js +18 -0
  5. package/dist/src/accounts.d.ts +22 -0
  6. package/dist/src/accounts.js +43 -0
  7. package/dist/src/bot.d.ts +16 -0
  8. package/dist/src/bot.js +100 -0
  9. package/dist/src/channel.d.ts +4 -0
  10. package/dist/src/channel.js +206 -0
  11. package/dist/src/client.d.ts +51 -0
  12. package/dist/src/client.js +206 -0
  13. package/dist/src/monitor.d.ts +19 -0
  14. package/dist/src/monitor.js +153 -0
  15. package/dist/src/proto/capy/botauth/auth_common_pb.d.ts +82 -0
  16. package/dist/src/proto/capy/botauth/auth_common_pb.js +35 -0
  17. package/dist/src/proto/capy/botauth/botauth_connect.d.ts +118 -0
  18. package/dist/src/proto/capy/botauth/botauth_connect.js +118 -0
  19. package/dist/src/proto/capy/botauth/botauth_pb.d.ts +1065 -0
  20. package/dist/src/proto/capy/botauth/botauth_pb.js +348 -0
  21. package/dist/src/proto/capy/botauth/public_connect.d.ts +62 -0
  22. package/dist/src/proto/capy/botauth/public_connect.js +62 -0
  23. package/dist/src/proto/capy/botauth/public_pb.d.ts +254 -0
  24. package/dist/src/proto/capy/botauth/public_pb.js +105 -0
  25. package/dist/src/proto/capy/botmsg/botmsg_connect.d.ts +72 -0
  26. package/dist/src/proto/capy/botmsg/botmsg_connect.js +72 -0
  27. package/dist/src/proto/capy/botmsg/botmsg_pb.d.ts +426 -0
  28. package/dist/src/proto/capy/botmsg/botmsg_pb.js +160 -0
  29. package/dist/src/proto/capy/botway/ctrl_connect.d.ts +61 -0
  30. package/dist/src/proto/capy/botway/ctrl_connect.js +61 -0
  31. package/dist/src/proto/capy/botway/ctrl_pb.d.ts +267 -0
  32. package/dist/src/proto/capy/botway/ctrl_pb.js +120 -0
  33. package/dist/src/proto/capy/botway/stream_connect.d.ts +26 -0
  34. package/dist/src/proto/capy/botway/stream_connect.js +26 -0
  35. package/dist/src/proto/capy/botway/stream_pb.d.ts +495 -0
  36. package/dist/src/proto/capy/botway/stream_pb.js +165 -0
  37. package/dist/src/reply-dispatcher.d.ts +17 -0
  38. package/dist/src/reply-dispatcher.js +234 -0
  39. package/dist/src/runtime.d.ts +4 -0
  40. package/dist/src/runtime.js +11 -0
  41. package/dist/src/send.d.ts +19 -0
  42. package/dist/src/send.js +66 -0
  43. package/dist/src/types.d.ts +65 -0
  44. package/dist/src/types.js +2 -0
  45. package/dist/src/websocket/cacheEvent.d.ts +17 -0
  46. package/dist/src/websocket/cacheEvent.js +61 -0
  47. package/dist/src/websocket/connect.d.ts +32 -0
  48. package/dist/src/websocket/connect.js +79 -0
  49. package/dist/src/websocket/constant.d.ts +8 -0
  50. package/dist/src/websocket/constant.js +10 -0
  51. package/dist/src/websocket/eventBus.d.ts +15 -0
  52. package/dist/src/websocket/eventBus.js +46 -0
  53. package/dist/src/websocket/index.d.ts +117 -0
  54. package/dist/src/websocket/index.js +637 -0
  55. package/dist/src/websocket/service.d.ts +36 -0
  56. package/dist/src/websocket/service.js +4 -0
  57. package/dist/src/websocket/stream.d.ts +10 -0
  58. package/dist/src/websocket/stream.js +24 -0
  59. package/dist/src/websocket/streamConnect.d.ts +40 -0
  60. package/dist/src/websocket/streamConnect.js +48 -0
  61. package/openclaw.plugin.json +23 -0
  62. package/package.json +69 -0
  63. package/scripts/setup.mjs +381 -0
  64. package/scripts/switch-env.mjs +98 -0
@@ -0,0 +1,637 @@
1
+ import { ErrorRes, HeartbeatReq, StreamMsg, } from "./streamConnect.js";
2
+ import { BotAuthBindReq, BotAuthBindRes, } from "../proto/capy/botway/stream_pb.js";
3
+ import { CacheEvent } from "./cacheEvent.js";
4
+ // import { useAuthStore } from '@/store/authInfo';
5
+ import { commonEventBus, Event } from "./eventBus.js";
6
+ // import { refreshToken } from "..";
7
+ import { BASE_URL, Env } from "./constant.js";
8
+ import { MethodKind } from "@bufbuild/protobuf";
9
+ const cache = new CacheEvent();
10
+ export const uuid = () => {
11
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
12
+ const r = (Math.random() * 16) | 0;
13
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
14
+ return v.toString(16);
15
+ });
16
+ };
17
+ export var SocketConnectState;
18
+ (function (SocketConnectState) {
19
+ SocketConnectState["Initial"] = "initial";
20
+ SocketConnectState["Connecting"] = "connecting";
21
+ SocketConnectState["Connected"] = "connected";
22
+ SocketConnectState["Token"] = "token";
23
+ SocketConnectState["Auth"] = "auth";
24
+ SocketConnectState["Disconnect"] = "disconnect";
25
+ })(SocketConnectState || (SocketConnectState = {}));
26
+ export var AuthState;
27
+ (function (AuthState) {
28
+ // 鉴权状态
29
+ AuthState["Initial"] = "initial";
30
+ AuthState["Anonymous"] = "anonymous";
31
+ AuthState["User"] = "user";
32
+ })(AuthState || (AuthState = {}));
33
+ export var ErrorCode;
34
+ (function (ErrorCode) {
35
+ ErrorCode[ErrorCode["Common"] = 1] = "Common";
36
+ ErrorCode[ErrorCode["Auth"] = 2] = "Auth";
37
+ ErrorCode[ErrorCode["Socket"] = 3] = "Socket";
38
+ ErrorCode[ErrorCode["Login"] = -1006] = "Login";
39
+ })(ErrorCode || (ErrorCode = {}));
40
+ // 鉴权包错误
41
+ export var AuthSocketError;
42
+ (function (AuthSocketError) {
43
+ // 鉴权失败,未知原因
44
+ AuthSocketError[AuthSocketError["AuthCodeFail"] = -1001] = "AuthCodeFail";
45
+ // 鉴权失败,access token过期
46
+ AuthSocketError[AuthSocketError["AuthCodeExpired"] = -1002] = "AuthCodeExpired";
47
+ // 鉴权失败,用户被封禁
48
+ AuthSocketError[AuthSocketError["AuthCodeBanned"] = -1003] = "AuthCodeBanned";
49
+ // 鉴权失败,用户未被激活
50
+ AuthSocketError[AuthSocketError["AuthCodeNotActivated"] = -1004] = "AuthCodeNotActivated";
51
+ })(AuthSocketError || (AuthSocketError = {}));
52
+ export var WebsocketCloseCode;
53
+ (function (WebsocketCloseCode) {
54
+ // CloseCodeNormal 正常关闭
55
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeNormal"] = 1000] = "CloseCodeNormal";
56
+ // 客户端主动断连
57
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeErrorClient"] = 1001] = "CloseCodeErrorClient";
58
+ // 客户端主动断连
59
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeClient"] = 1006] = "CloseCodeClient";
60
+ // CloseCodeAuthFailed 鉴权失败
61
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeAuthFailed"] = 4001] = "CloseCodeAuthFailed";
62
+ //CloseCodeAuthTimeout 鉴权超时失败
63
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeAuthTimeout"] = 4002] = "CloseCodeAuthTimeout";
64
+ //CloseCodeHeartbeatTimeout 心跳超时失败
65
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeHeartbeatTimeout"] = 4003] = "CloseCodeHeartbeatTimeout";
66
+ // CloseCodeSameUserReconnect 同用户连接冲突
67
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeSameUserReconnect"] = 4004] = "CloseCodeSameUserReconnect";
68
+ // CloseCodeKickOut 踢下线
69
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeKickOut"] = 4005] = "CloseCodeKickOut";
70
+ // CloseCodeUserForbidden 用户封禁
71
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeUserForbidden"] = 4006] = "CloseCodeUserForbidden";
72
+ // CloseCodeParseMsgFailed 解析数据失败
73
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeParseMsgFailed"] = 4007] = "CloseCodeParseMsgFailed";
74
+ // CloseCodeServerRestart 服务重启
75
+ WebsocketCloseCode[WebsocketCloseCode["CloseCodeServerRestart"] = 4008] = "CloseCodeServerRestart";
76
+ })(WebsocketCloseCode || (WebsocketCloseCode = {}));
77
+ const RECONNECT_CODES = [
78
+ WebsocketCloseCode.CloseCodeNormal,
79
+ WebsocketCloseCode.CloseCodeErrorClient,
80
+ WebsocketCloseCode.CloseCodeClient,
81
+ // WebsocketCloseCode.CloseCodeAuthTimeout,
82
+ WebsocketCloseCode.CloseCodeHeartbeatTimeout,
83
+ WebsocketCloseCode.CloseCodeParseMsgFailed,
84
+ WebsocketCloseCode.CloseCodeServerRestart,
85
+ ];
86
+ const RETRY_MAX = 3;
87
+ const CONNECT_RETRY_MAX = 7;
88
+ const socketEvent = new Event();
89
+ class _Socket {
90
+ _conn = null;
91
+ // static isConnected = false
92
+ // static _connecting = 0
93
+ _state = SocketConnectState.Initial; // 当前的连接状态
94
+ _authState = AuthState.Initial; // 当前的鉴权状态
95
+ _sendQueue = [];
96
+ _connectId = null;
97
+ _retryAuthTime = 0; // 鉴权重试次数
98
+ _retryConnectTime = 0; // 重连重试次数
99
+ _heartHandler = null; // todo
100
+ _requestTasks = new Set();
101
+ _requestStreams = new Set();
102
+ auth = null;
103
+ heartbeatTime = 30 * 1000;
104
+ errorCount = 0;
105
+ testCount = 0;
106
+ limit = 5;
107
+ events = socketEvent;
108
+ onAuthErr;
109
+ onAuthSuccess;
110
+ constructor(options) {
111
+ this.heartbeatTime = options?.heartbeatTime || this.heartbeatTime;
112
+ this.onAuthErr = options?.onAuthErr;
113
+ this.onAuthSuccess = options?.onAuthSuccess;
114
+ if (!options?.ignoreCreate) {
115
+ // Use void to explicitly mark this as intentionally unawaited
116
+ // Errors are handled internally by the socket's event system
117
+ void this.create("new socket").catch((err) => {
118
+ console.error("[websocket] Constructor create failed:", err);
119
+ // Error is logged but not thrown, to prevent affecting the gateway
120
+ });
121
+ }
122
+ commonEventBus.on("tokenUpdate", () => {
123
+ // Wrap sendAuth to catch any errors and prevent unhandled rejections
124
+ this.sendAuth().catch((err) => {
125
+ console.error("[websocket] sendAuth failed:", err);
126
+ });
127
+ });
128
+ }
129
+ // Custom WebSocket URL
130
+ _customWsUrl;
131
+ async create(scene, url) {
132
+ if (this._state !== SocketConnectState.Initial && this._conn) {
133
+ console.log(`[websocket] create skipped - already has connection (state: ${this._state})`);
134
+ return this._conn;
135
+ }
136
+ const wsUrl = url || this._customWsUrl || BASE_URL[Env.Prod].ws;
137
+ console.log(`[websocket] creating new connection - scene: "${scene}", url: ${wsUrl.replace(/token=[^&]+/, "token=***")}`);
138
+ this._state = SocketConnectState.Connecting; // 将状态变更为连接中
139
+ const conn = new WebSocket(wsUrl);
140
+ conn.binaryType = "arraybuffer";
141
+ this._conn = conn;
142
+ cache.clear();
143
+ // Add event handlers BEFORE awaiting initAuth to avoid race condition
144
+ // where WebSocket connects before handlers are attached
145
+ this.addConnEvents();
146
+ try {
147
+ await this.initAuth();
148
+ }
149
+ catch (err) {
150
+ console.error("[websocket] initAuth failed in create:", err);
151
+ // Don't throw - let the connection attempt continue
152
+ // The auth will be retried or the connection will fail naturally
153
+ }
154
+ this._state = SocketConnectState.Connecting; // 将状态变更为连接中
155
+ return conn;
156
+ }
157
+ /**
158
+ * Set custom WebSocket URL
159
+ */
160
+ setUrl(url) {
161
+ this._customWsUrl = url;
162
+ }
163
+ /**
164
+ * Set authentication credentials
165
+ */
166
+ setAuth(token, appId) {
167
+ this.auth = new BotAuthBindReq({
168
+ token,
169
+ appId,
170
+ });
171
+ }
172
+ async initAuth() {
173
+ // 获取鉴权信息
174
+ try {
175
+ // Auth should be set externally via setAuth() before connection
176
+ // If not set, we'll wait for it to be set later
177
+ if (!this.auth) {
178
+ console.log("[websocket]initAuth: auth not set, waiting for setAuth() call");
179
+ // Don't throw error, just don't complete the cache
180
+ // The connection will wait for auth to be set
181
+ return;
182
+ }
183
+ console.log("[websocket]initAuth", this.auth.token);
184
+ cache.complete("getToken");
185
+ }
186
+ catch (e) {
187
+ console.error("[websocket]initAuth error:", e);
188
+ // Use setTimeout to avoid stack overflow from recursive calls
189
+ if (this._retryAuthTime < RETRY_MAX) {
190
+ this._retryAuthTime += 1;
191
+ setTimeout(() => {
192
+ void this.initAuth();
193
+ }, 1000 * this._retryAuthTime); // Exponential backoff
194
+ }
195
+ else {
196
+ console.error("[websocket]initAuth: max retries exceeded");
197
+ }
198
+ }
199
+ }
200
+ addConnEvents() {
201
+ if (!this._conn)
202
+ return;
203
+ const { _conn } = this;
204
+ if (_conn.onmessage)
205
+ return;
206
+ _conn.onopen = () => {
207
+ console.log(`[websocket] WebSocket connected - transitioning to auth phase`);
208
+ this._state = SocketConnectState.Connected;
209
+ cache.do(async () => {
210
+ this._state = SocketConnectState.Token; // 保证状态变化的线性,所以在connected后再变更状态至token
211
+ try {
212
+ await this.sendAuth();
213
+ console.log(`[websocket] connection fully established - auth successful, state: ${this._state}`);
214
+ this.events.emit("open");
215
+ this.errorCount = 0;
216
+ }
217
+ catch (err) {
218
+ // Auth failed - this is expected when credentials are invalid
219
+ // Error is already logged by sendAuth, just ensure we don't crash
220
+ console.error("[websocket] Auth failed in onopen:", err);
221
+ // Don't rethrow - let the connection close and retry handle it
222
+ }
223
+ }, ["getToken"]);
224
+ };
225
+ _conn.onmessage = (event) => {
226
+ // 假如是心跳包,只发不解
227
+ if (event.data instanceof ArrayBuffer) {
228
+ const uint8Array = new Uint8Array(event.data);
229
+ const { body, head } = StreamMsg.fromBinary(uint8Array);
230
+ this.events.emit("message", body);
231
+ // this.testCount++;
232
+ // if (this.testCount >= this.limit) {
233
+ // console.log('==lin==manual onclose');
234
+ // _conn.onclose?.(
235
+ // new CloseEvent('', {
236
+ // code: WebsocketCloseCode.CloseCodeClient,
237
+ // }),
238
+ // );
239
+ // this.testCount = 0;
240
+ // this.limit = this.limit * 2;
241
+ // }
242
+ if (head?.msgType === 4 || !body) {
243
+ // todo 要定义枚举值
244
+ const error = body
245
+ ? ErrorRes.fromBinary(body)
246
+ : new ErrorRes({ code: 1, reason: "回包异常" });
247
+ this.events.emit(`error:${head?.msgId}`, error);
248
+ this.events.emit(`error:${head?.module}/${head?.command}`, error);
249
+ this.events.emit(`error`, error);
250
+ if (error.code === ErrorCode.Login) {
251
+ this.onError(new ErrorRes({ code: ErrorCode.Login, reason: "login required" }));
252
+ }
253
+ else {
254
+ this.onError(error);
255
+ }
256
+ // this.testCount = 0;
257
+ // this.limit = this.limit * 5;
258
+ return;
259
+ }
260
+ if (head?.msgId) {
261
+ this.events.emit(head?.msgId, body);
262
+ this._requestTasks.delete(head?.msgId);
263
+ }
264
+ if (head?.command && head?.module) {
265
+ this.events.emit(`${head.module}/${head.command}`, body);
266
+ }
267
+ }
268
+ };
269
+ _conn.onerror = (e) => {
270
+ console.error("[websocket] WebSocket error occurred:", e);
271
+ };
272
+ _conn.onclose = (e) => {
273
+ // 给没完成的请求发错误通知
274
+ this._requestTasks.forEach((v) => {
275
+ this.events.emit(`error:${v}`, new ErrorRes({
276
+ code: 1,
277
+ reason: "network error",
278
+ }));
279
+ });
280
+ this._requestTasks = new Set();
281
+ this._requestStreams.forEach((v) => {
282
+ this.events.emit(`error:${v}`, new ErrorRes({
283
+ code: 1,
284
+ reason: "network error",
285
+ }));
286
+ });
287
+ this._requestStreams = new Set();
288
+ // 正常关闭
289
+ if (this._retryConnectTime > CONNECT_RETRY_MAX) {
290
+ // 重试10次失败忽视
291
+ return;
292
+ }
293
+ // 打印详细的关闭原因
294
+ const closeReason = this.getCloseReason(e.code);
295
+ const wasClean = e.wasClean ? "clean" : "unclean";
296
+ console.log(`[websocket] connection closed - code: ${e.code} (${closeReason}), reason: "${e.reason || "N/A"}", wasClean: ${wasClean}, retryCount: ${this._retryConnectTime}`);
297
+ this._retryConnectTime += 1;
298
+ this.events.emit("disconnect", e);
299
+ if (RECONNECT_CODES.includes(e.code)) {
300
+ const willReconnect = RECONNECT_CODES.includes(e.code);
301
+ console.log(`[websocket] close code ${e.code} (${closeReason}) is in RECONNECT_CODES, will reconnect: ${willReconnect}`);
302
+ this.events.emit("close", e);
303
+ this.reconnect(`onclose_${closeReason}`);
304
+ }
305
+ else {
306
+ console.log(`[websocket] close code ${e.code} (${closeReason}) is NOT in RECONNECT_CODES, no automatic reconnect will be triggered`);
307
+ }
308
+ // 鉴权失败
309
+ if (e.code === WebsocketCloseCode.CloseCodeAuthFailed ||
310
+ e.code === WebsocketCloseCode.CloseCodeAuthTimeout ||
311
+ e.code === WebsocketCloseCode.CloseCodeKickOut) {
312
+ console.log(`[websocket] auth error detected (code: ${e.code}), clearing auth and reconnecting...`);
313
+ this.clearAuth();
314
+ this.reconnect("auth_error");
315
+ }
316
+ if (e.code === WebsocketCloseCode.CloseCodeKickOut ||
317
+ e.code === WebsocketCloseCode.CloseCodeUserForbidden) {
318
+ console.log(`[websocket] user kicked out or forbidden (code: ${e.code}), clearing auth and reconnecting...`);
319
+ this.clearAuth();
320
+ // useAuthStore.getState().logout();
321
+ this.reconnect("logout");
322
+ }
323
+ };
324
+ }
325
+ async onError(err) {
326
+ try {
327
+ if (err.code === ErrorCode.Auth && this.onAuthErr) {
328
+ this._state = SocketConnectState.Initial;
329
+ // 鉴权失败回调
330
+ this._authState = AuthState.Initial;
331
+ this.auth = null;
332
+ // this.disconnect('error_auth');
333
+ this.onAuthErr();
334
+ }
335
+ else if (this.errorCount < 5) {
336
+ if (err.code === -1002) {
337
+ // await refreshToken();
338
+ }
339
+ this._state = SocketConnectState.Initial;
340
+ void this.reconnect("onerror");
341
+ this.errorCount++;
342
+ }
343
+ }
344
+ catch (e) {
345
+ console.error("[websocket] onError handler failed:", e);
346
+ // Error is logged but not thrown, to prevent affecting the gateway
347
+ }
348
+ }
349
+ clearAuth() {
350
+ this._authState = AuthState.Initial;
351
+ this.auth = null;
352
+ }
353
+ startHeartbeat() {
354
+ if (this._heartHandler) {
355
+ clearTimeout(this._heartHandler);
356
+ this._heartHandler = null;
357
+ }
358
+ this.heartbeat();
359
+ this._heartHandler = setTimeout(() => {
360
+ this.startHeartbeat();
361
+ }, this.heartbeatTime);
362
+ }
363
+ // 发鉴权包
364
+ sendAuth(oMsgId) {
365
+ const msgId = oMsgId || uuid();
366
+ console.log("[websocket]sendAuth", this.auth, msgId);
367
+ return new Promise((resolve, reject) => {
368
+ if (!this.auth) {
369
+ this.onError(new ErrorRes({ code: ErrorCode.Auth, reason: "没有鉴权信息" }));
370
+ return msgId;
371
+ }
372
+ this.send({
373
+ module: "Stream",
374
+ command: "Auth",
375
+ body: this.auth.toBinary(),
376
+ }, msgId, true);
377
+ this.on(msgId, (buff) => {
378
+ if (buff instanceof ErrorRes) {
379
+ const err = new ErrorRes({
380
+ code: ErrorCode.Auth,
381
+ reason: "auth error",
382
+ });
383
+ console.log("[websocket]sendAuth error", buff);
384
+ this.handleAuthError(err?.code);
385
+ this.onError(err);
386
+ reject(err);
387
+ return msgId;
388
+ }
389
+ else {
390
+ const data = BotAuthBindRes.fromBinary(buff);
391
+ console.log("[websocket]sendAuth data", data);
392
+ const uid = data?.uid.toString() || "";
393
+ // if (data.logined) {
394
+ // useAuthStore.getState().login(uid);
395
+ // } else {
396
+ // useAuthStore.getState().logout();
397
+ // }
398
+ this._connectId = data.conn || null;
399
+ if (data?.code) {
400
+ const err = new ErrorRes({
401
+ code: ErrorCode.Auth,
402
+ reason: `auth error${JSON.stringify(data)}`,
403
+ });
404
+ this.handleAuthError(data?.code);
405
+ this.onError(err);
406
+ reject(err);
407
+ return msgId;
408
+ }
409
+ const logined = data.uid;
410
+ this._state = SocketConnectState.Auth;
411
+ this._authState = logined ? AuthState.User : AuthState.Anonymous;
412
+ this._retryConnectTime = 0; // 连接成功后重置重连次数
413
+ this.startHeartbeat(); // 鉴权成功才开始发心跳包
414
+ this._sendQueue.forEach(({ msgId, data }) => {
415
+ this.send(data, msgId);
416
+ });
417
+ this._sendQueue = [];
418
+ this.events.emit("connected", { logined, uid: data.uid.toString() });
419
+ if (this.onAuthSuccess) {
420
+ this.onAuthSuccess();
421
+ }
422
+ resolve(this._authState);
423
+ }
424
+ });
425
+ });
426
+ }
427
+ // 发心跳包
428
+ heartbeat(oMsgId) {
429
+ const msgId = oMsgId || uuid();
430
+ this.send({
431
+ module: "Stream",
432
+ command: "Heartbeat",
433
+ body: new HeartbeatReq({}).toBinary(),
434
+ }, msgId);
435
+ let isReceivedHeartbeat = 0;
436
+ this.on(msgId, (buff) => {
437
+ isReceivedHeartbeat = 1;
438
+ });
439
+ return msgId;
440
+ }
441
+ // 发普通包
442
+ send(params, oMsgId, isAuthPack) {
443
+ const msgId = oMsgId || uuid();
444
+ const { body: _, type = MethodKind.Unary, ...rest } = params;
445
+ if (params.command !== "Heartbeat") {
446
+ if (type === MethodKind.Unary) {
447
+ this._requestTasks.add(msgId);
448
+ }
449
+ else {
450
+ this._requestStreams.add(msgId);
451
+ }
452
+ }
453
+ if (this._retryConnectTime >= CONNECT_RETRY_MAX) {
454
+ this.disconnect("send_retry");
455
+ }
456
+ this._retryConnectTime = 0; // 重置重连次数
457
+ if (!this._conn ||
458
+ this._state === SocketConnectState.Initial ||
459
+ this._conn?.readyState !== WebSocket.OPEN) {
460
+ if (!isAuthPack) {
461
+ // 非鉴权包才入请求队列
462
+ this._sendQueue.push({
463
+ msgId,
464
+ data: params,
465
+ });
466
+ }
467
+ this.create("send");
468
+ return msgId;
469
+ }
470
+ if (!isAuthPack && this._state !== SocketConnectState.Auth) {
471
+ this._sendQueue.push({
472
+ msgId,
473
+ data: params,
474
+ });
475
+ return msgId;
476
+ }
477
+ const { module, command, body } = params;
478
+ if (!body) {
479
+ return msgId;
480
+ }
481
+ const data = {
482
+ head: {
483
+ frameType: 1, // 包体数据类型,0=text, 1=pb
484
+ msgType: 0, // 0=上行req,1=上行req的回包rsp,2=下行的push,3=下行push的回包(ack)
485
+ msgId: msgId,
486
+ module,
487
+ command,
488
+ reserved: {},
489
+ },
490
+ body,
491
+ };
492
+ console.log("[websocket]send ", new Date().toLocaleTimeString(), JSON.stringify({
493
+ command,
494
+ module,
495
+ _connectId: this._connectId,
496
+ msgId,
497
+ }));
498
+ try {
499
+ this._conn.send(new StreamMsg(data).toBinary());
500
+ }
501
+ catch (e) {
502
+ if (!isAuthPack) {
503
+ // 非鉴权包才加入请求队列
504
+ this._sendQueue.push({
505
+ msgId,
506
+ data: params,
507
+ });
508
+ }
509
+ this.create("send catch");
510
+ }
511
+ return msgId;
512
+ }
513
+ // 主动断连
514
+ disconnect(type, onClose) {
515
+ const readyState = this._conn?.readyState;
516
+ const stateNames = {
517
+ [WebSocket.CONNECTING]: "CONNECTING",
518
+ [WebSocket.OPEN]: "OPEN",
519
+ [WebSocket.CLOSING]: "CLOSING",
520
+ [WebSocket.CLOSED]: "CLOSED",
521
+ };
522
+ console.log(`[websocket] disconnect initiated - reason: "${type}", currentState: ${this._state}, readyState: ${stateNames[readyState ?? -1] || readyState}`);
523
+ if (!this._conn || this._state === SocketConnectState.Initial) {
524
+ console.log(`[websocket] disconnect skipped - no active connection`);
525
+ return;
526
+ }
527
+ if (this._conn?.readyState !== WebSocket.CLOSED) {
528
+ try {
529
+ this._conn.onclose = (e) => {
530
+ console.log(`[websocket] connection closed by disconnect() - code: ${e.code}, reason: "${e.reason || "N/A"}"`);
531
+ this._conn = null;
532
+ setTimeout(() => {
533
+ onClose?.();
534
+ }, 1000);
535
+ };
536
+ this._conn.close();
537
+ }
538
+ catch (e) {
539
+ console.error("[websocket] disconnect error during close():", e);
540
+ }
541
+ }
542
+ else {
543
+ console.log(`[websocket] disconnect skipped - connection already closed (readyState: ${readyState})`);
544
+ }
545
+ this.clearConnection();
546
+ }
547
+ // 重连
548
+ async reconnect(scene) {
549
+ console.log(`[websocket] starting reconnect sequence - trigger: "${scene}", attempt: ${this._retryConnectTime + 1}/${CONNECT_RETRY_MAX}`);
550
+ this.disconnect("connect", async () => {
551
+ try {
552
+ console.log(`[websocket] creating new connection after disconnect...`);
553
+ await this.create("reconnect");
554
+ console.log(`[websocket] reconnect successful`);
555
+ this.events.emit("reconnect");
556
+ }
557
+ catch (err) {
558
+ const errorMsg = err instanceof Error ? err.message : String(err);
559
+ console.error(`[websocket] reconnect failed: ${errorMsg}`);
560
+ // Error is logged but not thrown, to prevent affecting the gateway
561
+ }
562
+ });
563
+ }
564
+ // 清除连接
565
+ clearConnection() {
566
+ this._conn = null;
567
+ this._connectId = null;
568
+ this.events.off("close");
569
+ this.events.off("open");
570
+ this.events.off("disconnect");
571
+ this.events.off("message");
572
+ // this.events.off('auth-error');
573
+ // this.events = new Event();
574
+ }
575
+ /**
576
+ * 获取 WebSocket 关闭代码的文字说明
577
+ */
578
+ getCloseReason(code) {
579
+ const reasons = {
580
+ 1000: "normal closure",
581
+ 1001: "going away",
582
+ 1002: "protocol error",
583
+ 1003: "unsupported data",
584
+ 1005: "no status received",
585
+ 1006: "abnormal closure",
586
+ 1007: "invalid frame payload data",
587
+ 1008: "policy violation",
588
+ 1009: "message too big",
589
+ 1010: "mandatory extension",
590
+ 1011: "internal server error",
591
+ 1012: "service restart",
592
+ 1013: "try again later",
593
+ 1014: "bad gateway",
594
+ 1015: "TLS handshake",
595
+ 4001: "auth failed",
596
+ 4002: "auth timeout",
597
+ 4003: "heartbeat timeout",
598
+ 4004: "same user reconnect",
599
+ 4005: "kicked out",
600
+ 4006: "user forbidden",
601
+ 4007: "parse message failed",
602
+ 4008: "server restart",
603
+ };
604
+ return reasons[code] || `unknown code ${code}`;
605
+ }
606
+ handleAuthError(code) {
607
+ console.log("[websocket]handleAuthError", code);
608
+ if ([
609
+ AuthSocketError.AuthCodeBanned,
610
+ AuthSocketError.AuthCodeExpired,
611
+ AuthSocketError.AuthCodeFail,
612
+ AuthSocketError.AuthCodeNotActivated,
613
+ ].includes(code)) {
614
+ this.events.emit("auth-error", { code });
615
+ this.clearAuth();
616
+ this.disconnect("auth_error");
617
+ }
618
+ }
619
+ on(key, fn) {
620
+ this.events.on(key, fn);
621
+ }
622
+ emit(key, args) {
623
+ this.events.emit(key, args);
624
+ }
625
+ }
626
+ export let Socket;
627
+ export { _Socket };
628
+ export function getSocket() {
629
+ if (!Socket) {
630
+ Socket = new _Socket();
631
+ }
632
+ return Socket;
633
+ }
634
+ export function setSocket(socket) {
635
+ Socket = socket;
636
+ }
637
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,36 @@
1
+ export declare const BotMsgSocketClient: import("./connect").PromiseClient<{
2
+ readonly typeName: "step.capy.botmsg.BotMsg";
3
+ readonly methods: {
4
+ readonly fetchMessages: {
5
+ readonly name: "FetchMessages";
6
+ readonly I: typeof import("../proto/capy/botmsg/botmsg_pb").FetchMessagesRequest;
7
+ readonly O: typeof import("../proto/capy/botmsg/botmsg_pb").FetchMessagesResponse;
8
+ readonly kind: import("@bufbuild/protobuf").MethodKind.Unary;
9
+ };
10
+ readonly hasNewMessages: {
11
+ readonly name: "HasNewMessages";
12
+ readonly I: typeof import("../proto/capy/botmsg/botmsg_pb").HasNewMessagesRequest;
13
+ readonly O: typeof import("../proto/capy/botmsg/botmsg_pb").HasNewMessagesResponse;
14
+ readonly kind: import("@bufbuild/protobuf").MethodKind.Unary;
15
+ };
16
+ readonly sendMessages: {
17
+ readonly name: "SendMessages";
18
+ readonly I: typeof import("../proto/capy/botmsg/botmsg_pb").SendMessagesRequest;
19
+ readonly O: typeof import("../proto/capy/botmsg/botmsg_pb").SendMessagesResponse;
20
+ readonly kind: import("@bufbuild/protobuf").MethodKind.Unary;
21
+ };
22
+ readonly pushMessages: {
23
+ readonly name: "PushMessages";
24
+ readonly I: typeof import("../proto/capy/botmsg/botmsg_pb").PushMessagesRequest;
25
+ readonly O: typeof import("../proto/capy/botmsg/botmsg_pb").PushMessagesResponse;
26
+ readonly kind: import("@bufbuild/protobuf").MethodKind.Unary;
27
+ };
28
+ readonly checkBotOnline: {
29
+ readonly name: "CheckBotOnline";
30
+ readonly I: typeof import("../proto/capy/botmsg/botmsg_pb").CheckBotOnlineRequest;
31
+ readonly O: typeof import("../proto/capy/botmsg/botmsg_pb").CheckBotOnlineResponse;
32
+ readonly kind: import("@bufbuild/protobuf").MethodKind.Unary;
33
+ };
34
+ };
35
+ }>;
36
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { createSocketConnect } from './connect';
2
+ import { BotMsg } from '../proto/capy/botmsg/botmsg_connect';
3
+ export const BotMsgSocketClient = createSocketConnect('BotMsg', BotMsg);
4
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1,10 @@
1
+ import type { SocketCallbacks } from './connect';
2
+ type StreamFuncs<I, O> = {
3
+ start: (cb?: SocketCallbacks<O>['onStart']) => StreamFuncs<I, O>;
4
+ on: (cb?: SocketCallbacks<O>['onData']) => StreamFuncs<I, O>;
5
+ do: () => Promise<O>;
6
+ error: (cb?: SocketCallbacks<O>['onError']) => StreamFuncs<I, O>;
7
+ };
8
+ export declare const stream: <I, O>(method: (req: I, callbacks?: SocketCallbacks<O>, once?: boolean) => Promise<O>, payload: I) => StreamFuncs<I, O>;
9
+ export {};
10
+ //# sourceMappingURL=stream.d.ts.map