@kevisual/cnb 0.0.25 → 0.0.26

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.
@@ -1,5 +1,16 @@
1
1
  // WebSocket Keep-Alive Client Library
2
- import WebSocket from "ws";
2
+ // 运行时检测:Bun 使用原生 WebSocket,Node.js 使用 ws
3
+ let WebSocketModule: any;
4
+
5
+ if (typeof Bun !== 'undefined') {
6
+ // Bun 环境:使用原生 WebSocket
7
+ WebSocketModule = { WebSocket: globalThis.WebSocket };
8
+ } else {
9
+ // Node.js 环境:使用 ws 库
10
+ WebSocketModule = await import('ws');
11
+ }
12
+
13
+ const WebSocket = WebSocketModule.WebSocket;
3
14
 
4
15
  export interface KeepAliveConfig {
5
16
  wsUrl: string;
@@ -31,6 +42,7 @@ export class WSKeepAlive {
31
42
  private pingTimer: NodeJS.Timeout | null = null;
32
43
  private messageHandlers: Set<MessageHandler> = new Set();
33
44
  private url: URL;
45
+ private readonly isBun: boolean;
34
46
 
35
47
  constructor(config: KeepAliveConfig) {
36
48
  this.config = {
@@ -48,6 +60,7 @@ export class WSKeepAlive {
48
60
  debug: config.debug ?? false,
49
61
  };
50
62
  this.url = new URL(this.config.wsUrl);
63
+ this.isBun = typeof Bun !== 'undefined';
51
64
  }
52
65
 
53
66
  private log(message: string) {
@@ -107,44 +120,91 @@ export class WSKeepAlive {
107
120
  }
108
121
  });
109
122
 
110
- this.ws.on("open", () => {
111
- debug && this.log("Connected!");
112
- this.reconnectAttempts = 0;
113
- this.config.onConnect();
114
- this.startPing();
115
- });
116
-
117
- this.ws.on("message", (data: any) => {
118
- if (Buffer.isBuffer(data)) {
119
- const parsed = this.parseMessage(data);
120
- this.config.onMessage(parsed?.raw ?? data);
121
-
122
- this.messageHandlers.forEach(handler => {
123
- if (parsed) handler(parsed);
124
- });
125
- } else {
126
- this.config.onMessage(data);
127
- }
128
- });
123
+ if (this.isBun) {
124
+ // Bun 环境:使用标准 Web API
125
+ const ws = this.ws as any;
126
+ ws.onopen = () => {
127
+ debug && this.log("Connected!");
128
+ this.reconnectAttempts = 0;
129
+ this.config.onConnect();
130
+ this.startPing();
131
+ };
132
+
133
+ ws.onmessage = async (event: MessageEvent) => {
134
+ let data: Buffer | string;
135
+
136
+ if (event.data instanceof Blob) {
137
+ data = Buffer.from(await event.data.arrayBuffer());
138
+ } else if (event.data instanceof ArrayBuffer) {
139
+ data = Buffer.from(event.data);
140
+ } else if (typeof event.data === 'string') {
141
+ data = event.data;
142
+ } else {
143
+ data = Buffer.from(event.data);
144
+ }
129
145
 
130
- this.ws.on("close", (code: number) => {
131
- debug && this.log(`Disconnected (code: ${code})`);
132
- this.stopPing();
133
- this.config.onDisconnect(code);
134
- this.handleReconnect();
135
- });
146
+ this.handleMessage(data);
147
+ };
148
+
149
+ ws.onclose = (event: CloseEvent) => {
150
+ debug && this.log(`Disconnected (code: ${event.code})`);
151
+ this.stopPing();
152
+ this.config.onDisconnect(event.code);
153
+ this.handleReconnect();
154
+ };
155
+
156
+ ws.onerror = (event: Event) => {
157
+ debug && this.log(`Error: ${event}`);
158
+ this.config.onError(new Error("WebSocket error"));
159
+ };
160
+ } else {
161
+ // Node.js (ws 库):使用 EventEmitter 模式
162
+ const ws = this.ws as any;
163
+ ws.on("open", () => {
164
+ debug && this.log("Connected!");
165
+ this.reconnectAttempts = 0;
166
+ this.config.onConnect();
167
+ this.startPing();
168
+ });
169
+
170
+ ws.on("message", (data: any) => {
171
+ this.handleMessage(data);
172
+ });
173
+
174
+ ws.on("close", (code: number) => {
175
+ debug && this.log(`Disconnected (code: ${code})`);
176
+ this.stopPing();
177
+ this.config.onDisconnect(code);
178
+ this.handleReconnect();
179
+ });
180
+
181
+ ws.on("error", (err: Error) => {
182
+ debug && this.log(`Error: ${err.message}`);
183
+ this.config.onError(err);
184
+ });
185
+ }
186
+ }
136
187
 
137
- this.ws.on("error", (err: Error) => {
138
- debug && this.log(`Error: ${err.message}`);
139
- this.config.onError(err);
140
- });
188
+ // 统一的消息处理方法
189
+ private handleMessage(data: Buffer | string) {
190
+ if (Buffer.isBuffer(data)) {
191
+ const parsed = this.parseMessage(data);
192
+ this.config.onMessage(parsed?.raw ?? data);
193
+
194
+ this.messageHandlers.forEach(handler => {
195
+ if (parsed) handler(parsed);
196
+ });
197
+ } else {
198
+ this.config.onMessage(data);
199
+ }
141
200
  }
142
201
 
143
202
  private startPing() {
144
203
  this.stopPing();
145
204
  this.pingTimer = setInterval(() => {
146
205
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
147
- this.ws.ping();
206
+ // 使用 JSON 格式的 ping 消息,兼容 Bun 和 Node.js
207
+ this.ws.send(JSON.stringify({ type: "ping", timestamp: Date.now() }));
148
208
  this.log("Sent ping");
149
209
  }
150
210
  }, this.config.pingInterval);