@laplace.live/ws 7.1.9 → 7.1.10
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/dist/browser.d.ts +6 -7
- package/dist/browser.js +2155 -2135
- package/dist/index.d.ts +38 -34
- package/dist/index.js +212 -444
- package/dist/ws-DHkTB1_n.d.ts +312 -0
- package/dist/ws-DfVxzRDM.js +426 -0
- package/package.json +7 -6
- package/dist/ws-mjTot1Nb.d.ts +0 -301
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
//#region src/events.ts
|
|
2
|
+
/**
|
|
3
|
+
* A typed {@link Event} that carries an arbitrary data payload.
|
|
4
|
+
*
|
|
5
|
+
* Used throughout the library to deliver structured messages such as
|
|
6
|
+
* heartbeat counts, danmaku payloads, and other server-pushed data.
|
|
7
|
+
*
|
|
8
|
+
* Also used internally with `LaplaceRawEvent<Event>` as a catch-all meta-event
|
|
9
|
+
* (type `"event"`) to forward all events through {@link KeepLive}.
|
|
10
|
+
*
|
|
11
|
+
* @typeParam T - The type of the data payload attached to this event.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* live.addEventListener('heartbeat', (e) => {
|
|
16
|
+
* console.log('online:', e.data)
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
var LaplaceRawEvent = class extends Event {
|
|
21
|
+
data;
|
|
22
|
+
constructor(type, data) {
|
|
23
|
+
super(type);
|
|
24
|
+
this.data = data;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Typed {@link EventTarget} base class for live connections.
|
|
29
|
+
*
|
|
30
|
+
* Provides typed `addEventListener` / `removeEventListener` via
|
|
31
|
+
* {@link LiveEventMap} and a `dispatchEvent` override that emits a
|
|
32
|
+
* catch-all `"event"` meta-event for every dispatched event.
|
|
33
|
+
*
|
|
34
|
+
* Extend this instead of `EventTarget` when building wrappers around
|
|
35
|
+
* `LiveWS` / `KeepLiveWS` to inherit typed event signatures
|
|
36
|
+
* automatically — no `declare` duplication required.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { LaplaceEventTarget, LaplaceRawEvent } from '@laplace.live/ws'
|
|
41
|
+
*
|
|
42
|
+
* class MyWrapper extends LaplaceEventTarget {
|
|
43
|
+
* // addEventListener is already typed — no extra `declare` needed
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
var LaplaceEventTarget = class extends EventTarget {
|
|
48
|
+
dispatchEvent(event) {
|
|
49
|
+
const result = super.dispatchEvent(event);
|
|
50
|
+
super.dispatchEvent(new LaplaceRawEvent("event", event));
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/keep-live.ts
|
|
56
|
+
/**
|
|
57
|
+
* Auto-reconnecting wrapper around a {@link Live} subclass.
|
|
58
|
+
*
|
|
59
|
+
* `KeepLive` maintains a persistent connection to a Bilibili live room by
|
|
60
|
+
* automatically re-creating the underlying {@link Live} instance whenever
|
|
61
|
+
* the connection drops or a heartbeat timeout is reached. All events from
|
|
62
|
+
* the inner connection are forwarded to this instance.
|
|
63
|
+
*
|
|
64
|
+
* @typeParam T - The concrete {@link Live} instance type being managed.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const keep = new KeepLiveWS(12345, { key: '...' })
|
|
69
|
+
* keep.addEventListener('heartbeat', (e) => console.log('online:', e.data))
|
|
70
|
+
* keep.addEventListener('DANMU_MSG', ({ data }) => console.log('danmaku:', data.msg_id))
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
var KeepLive = class extends LaplaceEventTarget {
|
|
74
|
+
/** @internal Factory that creates a fresh connection with the original arguments. */
|
|
75
|
+
createConnection;
|
|
76
|
+
/** `true` after {@link close} has been called; prevents further reconnects. */
|
|
77
|
+
closed;
|
|
78
|
+
/** Delay in milliseconds before attempting a reconnect. */
|
|
79
|
+
interval;
|
|
80
|
+
/** Maximum milliseconds to wait for a heartbeat before forcing a reconnect. */
|
|
81
|
+
timeout;
|
|
82
|
+
/** The current underlying connection instance. */
|
|
83
|
+
connection;
|
|
84
|
+
constructor(createConnection) {
|
|
85
|
+
super();
|
|
86
|
+
this.createConnection = createConnection;
|
|
87
|
+
this.closed = false;
|
|
88
|
+
this.interval = 3e3;
|
|
89
|
+
this.timeout = 45 * 1e3;
|
|
90
|
+
this.connection = this.createConnection();
|
|
91
|
+
this.connect(false);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Wire up event forwarding and timeout handling on the current connection.
|
|
95
|
+
* When `reconnect` is `true`, the previous connection is closed and a fresh
|
|
96
|
+
* one is created via the factory.
|
|
97
|
+
*
|
|
98
|
+
* @param reconnect - Whether to tear down and recreate the connection first.
|
|
99
|
+
*/
|
|
100
|
+
connect(reconnect = true) {
|
|
101
|
+
if (reconnect) {
|
|
102
|
+
const old = this.connection;
|
|
103
|
+
this.connection = this.createConnection();
|
|
104
|
+
old.close();
|
|
105
|
+
}
|
|
106
|
+
const connection = this.connection;
|
|
107
|
+
let timeout = setTimeout(() => {
|
|
108
|
+
connection.close();
|
|
109
|
+
connection.dispatchEvent(new Event("timeout"));
|
|
110
|
+
}, this.timeout);
|
|
111
|
+
connection.addEventListener("event", (e) => {
|
|
112
|
+
if (this.connection !== connection) return;
|
|
113
|
+
const evt = e.data;
|
|
114
|
+
if (evt.type !== "error") if (evt instanceof LaplaceRawEvent) this.dispatchEvent(new LaplaceRawEvent(evt.type, evt.data));
|
|
115
|
+
else this.dispatchEvent(new Event(evt.type));
|
|
116
|
+
});
|
|
117
|
+
connection.addEventListener("error", () => this.dispatchEvent(new Event("e")));
|
|
118
|
+
connection.addEventListener("close", () => {
|
|
119
|
+
if (!this.closed && this.connection === connection) setTimeout(() => this.connect(), this.interval);
|
|
120
|
+
});
|
|
121
|
+
connection.addEventListener("heartbeat", () => {
|
|
122
|
+
if (this.connection !== connection) return;
|
|
123
|
+
clearTimeout(timeout);
|
|
124
|
+
timeout = setTimeout(() => {
|
|
125
|
+
connection.close();
|
|
126
|
+
connection.dispatchEvent(new Event("timeout"));
|
|
127
|
+
}, this.timeout);
|
|
128
|
+
});
|
|
129
|
+
connection.addEventListener("close", () => {
|
|
130
|
+
clearTimeout(timeout);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** Latest known online viewer count from the underlying connection. */
|
|
134
|
+
get online() {
|
|
135
|
+
return this.connection.online;
|
|
136
|
+
}
|
|
137
|
+
/** The live room ID. */
|
|
138
|
+
get roomid() {
|
|
139
|
+
return this.connection.roomid;
|
|
140
|
+
}
|
|
141
|
+
/** Permanently close the connection and stop reconnecting. */
|
|
142
|
+
close() {
|
|
143
|
+
this.closed = true;
|
|
144
|
+
this.connection.close();
|
|
145
|
+
}
|
|
146
|
+
/** Send a heartbeat packet to the server. */
|
|
147
|
+
heartbeat() {
|
|
148
|
+
return this.connection.heartbeat();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Send a heartbeat and resolve with the online viewer count from the
|
|
152
|
+
* next heartbeat response.
|
|
153
|
+
* @returns A promise that resolves with the current online count.
|
|
154
|
+
*/
|
|
155
|
+
getOnline() {
|
|
156
|
+
return this.connection.getOnline();
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Send raw binary data through the underlying connection.
|
|
160
|
+
* @param data - The binary packet to send.
|
|
161
|
+
*/
|
|
162
|
+
send(data) {
|
|
163
|
+
return this.connection.send(data);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/buffer.ts
|
|
168
|
+
const textEncoder = new TextEncoder();
|
|
169
|
+
const textDecoder = new TextDecoder();
|
|
170
|
+
function concatUint8Arrays(arrs) {
|
|
171
|
+
let totalLength = 0;
|
|
172
|
+
for (const arr of arrs) totalLength += arr.length;
|
|
173
|
+
const result = new Uint8Array(totalLength);
|
|
174
|
+
let offset = 0;
|
|
175
|
+
for (const arr of arrs) {
|
|
176
|
+
result.set(arr, offset);
|
|
177
|
+
offset += arr.length;
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
const cutBuffer = (buffer) => {
|
|
182
|
+
const bufferPacks = [];
|
|
183
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
184
|
+
let size;
|
|
185
|
+
for (let i = 0; i < buffer.length; i += size) {
|
|
186
|
+
size = view.getInt32(i);
|
|
187
|
+
bufferPacks.push(buffer.slice(i, i + size));
|
|
188
|
+
}
|
|
189
|
+
return bufferPacks;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Create an async decoder function that parses raw Bilibili live WebSocket
|
|
193
|
+
* frames into structured packets.
|
|
194
|
+
*
|
|
195
|
+
* Each frame has a 16-byte header:
|
|
196
|
+
* - bytes 0–3: total packet length (int32 BE)
|
|
197
|
+
* - bytes 4–5: header length (int16 BE, always 16)
|
|
198
|
+
* - bytes 6–7: protocol version (0 = JSON, 1 = heartbeat, 2 = zlib, 3 = brotli)
|
|
199
|
+
* - bytes 8–11: operation (2 = heartbeat req, 3 = heartbeat resp, 5 = message, 7 = join, 8 = welcome)
|
|
200
|
+
* - bytes 12–15: sequence id
|
|
201
|
+
*
|
|
202
|
+
* Compressed frames (protocol 2/3) are recursively decoded after inflation.
|
|
203
|
+
*
|
|
204
|
+
* @link https://github.com/lovelyyoshino/Bilibili-Live-API/blob/master/API.WebSocket.md
|
|
205
|
+
* @param inflates - Platform-specific decompression implementations.
|
|
206
|
+
* @returns An async function that decodes a raw `Uint8Array` frame into an
|
|
207
|
+
* array of `{ buf, type, protocol, data }` packets.
|
|
208
|
+
*/
|
|
209
|
+
const makeDecoder = ({ inflateAsync, brotliDecompressAsync }) => {
|
|
210
|
+
const decoder = async (buffer) => {
|
|
211
|
+
return (await Promise.all(cutBuffer(buffer).map(async (buf) => {
|
|
212
|
+
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
213
|
+
const body = buf.slice(16);
|
|
214
|
+
const protocol = view.getInt16(6);
|
|
215
|
+
const operation = view.getInt32(8);
|
|
216
|
+
let type = "unknow";
|
|
217
|
+
if (operation === 3) type = "heartbeat";
|
|
218
|
+
else if (operation === 5) type = "message";
|
|
219
|
+
else if (operation === 8) type = "welcome";
|
|
220
|
+
let data;
|
|
221
|
+
if (protocol === 0) data = JSON.parse(textDecoder.decode(body));
|
|
222
|
+
if (protocol === 1 && body.length === 4) data = new DataView(body.buffer, body.byteOffset, body.byteLength).getUint32(0);
|
|
223
|
+
if (protocol === 2) data = await decoder(await inflateAsync(body));
|
|
224
|
+
if (protocol === 3) data = await decoder(await brotliDecompressAsync(body));
|
|
225
|
+
return {
|
|
226
|
+
buf,
|
|
227
|
+
type,
|
|
228
|
+
protocol,
|
|
229
|
+
data
|
|
230
|
+
};
|
|
231
|
+
}))).flatMap((pack) => {
|
|
232
|
+
if (pack.protocol === 2 || pack.protocol === 3) return pack.data;
|
|
233
|
+
return pack;
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
return decoder;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Encode a Bilibili live protocol packet with a 16-byte header and an
|
|
240
|
+
* optional body.
|
|
241
|
+
*
|
|
242
|
+
* Header layout:
|
|
243
|
+
* - bytes 0–3: total length (header + body)
|
|
244
|
+
* - bytes 4–5: header length (16)
|
|
245
|
+
* - bytes 6–7: protocol version (1)
|
|
246
|
+
* - bytes 8–11: operation (`2` for heartbeat, `7` for join)
|
|
247
|
+
* - bytes 12–15: sequence id (1)
|
|
248
|
+
*
|
|
249
|
+
* @param type - Packet type: `"heartbeat"` (keep-alive) or `"join"` (room enter).
|
|
250
|
+
* @param body - Optional payload. Objects are JSON-stringified; strings are
|
|
251
|
+
* encoded as UTF-8. Defaults to an empty string.
|
|
252
|
+
* @returns The encoded packet as a `Uint8Array`.
|
|
253
|
+
*/
|
|
254
|
+
const encoder = (type, body = "") => {
|
|
255
|
+
const encoded = typeof body === "string" ? body : JSON.stringify(body);
|
|
256
|
+
const head = new Uint8Array(16);
|
|
257
|
+
const headView = new DataView(head.buffer, head.byteOffset, head.byteLength);
|
|
258
|
+
const buffer = textEncoder.encode(encoded);
|
|
259
|
+
headView.setInt32(0, buffer.length + head.length);
|
|
260
|
+
headView.setInt16(4, 16);
|
|
261
|
+
headView.setInt16(6, 1);
|
|
262
|
+
if (type === "heartbeat") headView.setInt32(8, 2);
|
|
263
|
+
if (type === "join") headView.setInt32(8, 7);
|
|
264
|
+
headView.setInt32(12, 1);
|
|
265
|
+
return concatUint8Arrays([head, buffer]);
|
|
266
|
+
};
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/live.ts
|
|
269
|
+
/**
|
|
270
|
+
* Base class for a single Bilibili live room connection.
|
|
271
|
+
*
|
|
272
|
+
* Extends {@link LaplaceEventTarget} and emits the following events:
|
|
273
|
+
*
|
|
274
|
+
* | Event | Payload | Description |
|
|
275
|
+
* |---------------|--------------------|--------------------------------------------------|
|
|
276
|
+
* | `open` | — | Underlying transport connected. |
|
|
277
|
+
* | `live` | — | Server acknowledged the join (room entered). |
|
|
278
|
+
* | `heartbeat` | `LaplaceRawEvent<number>`| Online viewer count received from server. |
|
|
279
|
+
* | `msg` | `LaplaceRawEvent<any>` | Any server command message. |
|
|
280
|
+
* | `DANMU_MSG` | `LaplaceRawEvent<any>` | Danmaku (chat) message. |
|
|
281
|
+
* | `close` | — | Connection closed. |
|
|
282
|
+
* | `error` | — | Unrecoverable error (connection is closed). |
|
|
283
|
+
* | `event` | `LaplaceRawEvent<Event>` | Meta-event wrapping every dispatched event. |
|
|
284
|
+
*
|
|
285
|
+
* Subclasses ({@link LiveWSBase}, {@link LiveTCPBase}) provide the concrete
|
|
286
|
+
* transport and supply `send` / `close` callbacks to this constructor.
|
|
287
|
+
*
|
|
288
|
+
* @param inflates - Platform-specific inflate + brotli decompressors.
|
|
289
|
+
* @param roomid - Numeric Bilibili live room ID.
|
|
290
|
+
* @param options - Transport callbacks and authentication options.
|
|
291
|
+
*
|
|
292
|
+
* @throws {Error} If `roomid` is not a finite number.
|
|
293
|
+
*/
|
|
294
|
+
var Live = class extends LaplaceEventTarget {
|
|
295
|
+
/** The live room ID this instance is connected to. */
|
|
296
|
+
roomid;
|
|
297
|
+
/** Latest known online viewer count, updated on each heartbeat. */
|
|
298
|
+
online;
|
|
299
|
+
/** `true` after the server acknowledges the join (`welcome` packet). */
|
|
300
|
+
live;
|
|
301
|
+
/** `true` after {@link close} has been called. */
|
|
302
|
+
closed;
|
|
303
|
+
/** @internal Handle for the heartbeat interval timer. */
|
|
304
|
+
timeout;
|
|
305
|
+
/** Send raw binary data over the underlying transport. */
|
|
306
|
+
send;
|
|
307
|
+
/** Gracefully close the connection and set {@link closed} to `true`. */
|
|
308
|
+
close;
|
|
309
|
+
constructor(inflates, roomid, { send, close, protover = 3, key, authBody, uid = 0, buvid }) {
|
|
310
|
+
if (typeof roomid !== "number" || Number.isNaN(roomid)) throw new Error(`roomid ${roomid} must be Number not NaN`);
|
|
311
|
+
super();
|
|
312
|
+
this.roomid = roomid;
|
|
313
|
+
this.online = 0;
|
|
314
|
+
this.live = false;
|
|
315
|
+
this.closed = false;
|
|
316
|
+
this.timeout = setTimeout(() => {}, 0);
|
|
317
|
+
this.send = send;
|
|
318
|
+
this.close = () => {
|
|
319
|
+
if (this.closed) return;
|
|
320
|
+
this.closed = true;
|
|
321
|
+
close();
|
|
322
|
+
this.dispatchEvent(new Event("close"));
|
|
323
|
+
};
|
|
324
|
+
const decode = makeDecoder(inflates);
|
|
325
|
+
this.addEventListener("message", async (e) => {
|
|
326
|
+
const buffer = e.data;
|
|
327
|
+
(await decode(buffer)).forEach(({ type, data }) => {
|
|
328
|
+
if (type === "welcome") {
|
|
329
|
+
this.live = true;
|
|
330
|
+
this.dispatchEvent(new Event("live"));
|
|
331
|
+
this.send(encoder("heartbeat"));
|
|
332
|
+
}
|
|
333
|
+
if (type === "heartbeat") {
|
|
334
|
+
this.online = data;
|
|
335
|
+
clearTimeout(this.timeout);
|
|
336
|
+
this.timeout = setTimeout(() => this.heartbeat(), 1e3 * 30);
|
|
337
|
+
this.dispatchEvent(new LaplaceRawEvent("heartbeat", this.online));
|
|
338
|
+
}
|
|
339
|
+
if (type === "message") {
|
|
340
|
+
this.dispatchEvent(new LaplaceRawEvent("msg", data));
|
|
341
|
+
const cmd = data.cmd || data.msg?.cmd;
|
|
342
|
+
if (cmd) this.dispatchEvent(new LaplaceRawEvent(cmd, data));
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
this.addEventListener("open", () => {
|
|
347
|
+
if (authBody) this.send(authBody instanceof Uint8Array ? authBody : encoder("join", authBody));
|
|
348
|
+
else {
|
|
349
|
+
const hi = {
|
|
350
|
+
uid,
|
|
351
|
+
roomid,
|
|
352
|
+
protover,
|
|
353
|
+
platform: "web",
|
|
354
|
+
type: 2
|
|
355
|
+
};
|
|
356
|
+
if (key) hi.key = key;
|
|
357
|
+
if (buvid) hi.buvid = buvid;
|
|
358
|
+
const buf = encoder("join", hi);
|
|
359
|
+
this.send(buf);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
this.addEventListener("close", () => {
|
|
363
|
+
clearTimeout(this.timeout);
|
|
364
|
+
});
|
|
365
|
+
this.addEventListener("_error", () => {
|
|
366
|
+
this.close();
|
|
367
|
+
this.dispatchEvent(new Event("error"));
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
/** Send a heartbeat packet to the server. */
|
|
371
|
+
heartbeat() {
|
|
372
|
+
this.send(encoder("heartbeat"));
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Send a heartbeat and resolve with the online viewer count from the
|
|
376
|
+
* next heartbeat response.
|
|
377
|
+
* @returns A promise that resolves with the current online count.
|
|
378
|
+
*/
|
|
379
|
+
getOnline() {
|
|
380
|
+
this.heartbeat();
|
|
381
|
+
return new Promise((resolve) => this.addEventListener("heartbeat", (e) => resolve(e.data), { once: true }));
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/ws.ts
|
|
386
|
+
/**
|
|
387
|
+
* WebSocket transport for Bilibili live room connections.
|
|
388
|
+
*
|
|
389
|
+
* Wraps a native {@link WebSocket}, wiring its lifecycle events (`open`,
|
|
390
|
+
* `message`, `close`, `error`) into the {@link Live} event system. Binary
|
|
391
|
+
* frames are forwarded as `LaplaceRawEvent<Uint8Array>` for protocol decoding.
|
|
392
|
+
*
|
|
393
|
+
* Not typically instantiated directly — use {@link LiveWS} (server) or the
|
|
394
|
+
* browser-specific `LiveWS` which inject the appropriate inflate
|
|
395
|
+
* implementation.
|
|
396
|
+
*
|
|
397
|
+
* @param inflates - Platform-specific inflate/brotli decompressors.
|
|
398
|
+
* @param roomid - Numeric Bilibili live room ID.
|
|
399
|
+
* @param options - WebSocket address and authentication options.
|
|
400
|
+
*/
|
|
401
|
+
var LiveWSBase = class extends Live {
|
|
402
|
+
/** The underlying native WebSocket instance. */
|
|
403
|
+
ws;
|
|
404
|
+
constructor(inflates, roomid, { address = "wss://broadcastlv.chat.bilibili.com/sub", createWebSocket, ...options } = {}) {
|
|
405
|
+
const ws = createWebSocket ? createWebSocket(address) : new WebSocket(address);
|
|
406
|
+
const send = (data) => {
|
|
407
|
+
if (ws.readyState === 1) ws.send(data);
|
|
408
|
+
};
|
|
409
|
+
const close = () => this.ws.close();
|
|
410
|
+
super(inflates, roomid, {
|
|
411
|
+
send,
|
|
412
|
+
close,
|
|
413
|
+
...options
|
|
414
|
+
});
|
|
415
|
+
ws.binaryType = "arraybuffer";
|
|
416
|
+
ws.addEventListener("open", (e) => this.dispatchEvent(new Event(e.type)));
|
|
417
|
+
ws.addEventListener("message", (e) => this.dispatchEvent(new LaplaceRawEvent("message", new Uint8Array(e.data))));
|
|
418
|
+
ws.addEventListener("close", (e) => {
|
|
419
|
+
if (!this.closed) this.dispatchEvent(new Event(e.type));
|
|
420
|
+
});
|
|
421
|
+
ws.addEventListener("error", () => this.dispatchEvent(new Event("_error")));
|
|
422
|
+
this.ws = ws;
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
//#endregion
|
|
426
|
+
export { LaplaceRawEvent as a, LaplaceEventTarget as i, Live as n, KeepLive as r, LiveWSBase as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@laplace.live/ws",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.10",
|
|
4
4
|
"description": "LAPLACE Live! flavored bilibili live WebSocket/TCP API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -32,12 +32,13 @@
|
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
34
|
"scripts": {
|
|
35
|
-
"build": "
|
|
35
|
+
"build": "tsdown",
|
|
36
36
|
"check": "tsc --noEmit",
|
|
37
37
|
"test": "bun test --timeout 5000",
|
|
38
38
|
"prepublishOnly": "bun run build",
|
|
39
39
|
"release": "changeset publish",
|
|
40
|
-
"version": "changeset version"
|
|
40
|
+
"version": "changeset version",
|
|
41
|
+
"lint": "biome check"
|
|
41
42
|
},
|
|
42
43
|
"repository": {
|
|
43
44
|
"type": "git",
|
|
@@ -62,14 +63,14 @@
|
|
|
62
63
|
"provenance": true
|
|
63
64
|
},
|
|
64
65
|
"dependencies": {
|
|
65
|
-
"@laplace.live/internal": "^1.3.
|
|
66
|
+
"@laplace.live/internal": "^1.3.9"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@biomejs/biome": "^2.4.12",
|
|
69
|
-
"@changesets/cli": "^2.
|
|
70
|
+
"@changesets/cli": "^2.31.0",
|
|
70
71
|
"@types/bun": "^1.3.12",
|
|
71
72
|
"playwright": "^1.59.1",
|
|
72
|
-
"
|
|
73
|
+
"tsdown": "^0.21.9",
|
|
73
74
|
"typescript": "^5.9.3"
|
|
74
75
|
}
|
|
75
76
|
}
|