@laplace.live/ws 7.0.2 → 7.1.0

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/README.md CHANGED
@@ -8,7 +8,7 @@ This project is based on [bilibili-live-ws](https://github.com/simon300000/bilib
8
8
  - Uses web-standard `EventTarget`/`Event` instead of Node.js `EventEmitter` polyfills
9
9
  - Uses native `WebSocket` API directly, removing `isomorphic-ws` and `ws` dependencies
10
10
  - No `Buffer` polyfills
11
- - Typed `on<T>()`/`off<T>()` convenience methods
11
+ - Typed `addEventListener` via `LiveEventMap` with [`@laplace.live/internal`](https://github.com/laplace-live/internal) types
12
12
  - Conditional `exports` field with `./server`, `./client`, `./browser` sub-path exports
13
13
 
14
14
  ## Install
@@ -19,16 +19,58 @@ bun add @laplace.live/ws
19
19
 
20
20
  ## Usage
21
21
 
22
+ Known Bilibili events are auto-typed via `LiveEventMap` — no manual generics
23
+ or casting needed:
24
+
25
+ ```typescript
26
+ import { LiveWS } from "@laplace.live/ws";
27
+
28
+ const live = new LiveWS(25034104, { key: "...", address: "wss://..." });
29
+
30
+ // Built-in events are typed automatically
31
+ live.addEventListener("open", () => console.log("Connection established"));
32
+ live.addEventListener("live", () => console.log("Room entered"));
33
+ live.addEventListener("heartbeat", ({ data }) => console.log("Online:", data));
34
+
35
+ // Known Bilibili commands are typed from @laplace.live/internal
36
+ live.addEventListener("DANMU_MSG", ({ data }) => console.log(data.msg_id));
37
+ live.addEventListener("SEND_GIFT", ({ data }) => console.log(data.giftName));
38
+ live.addEventListener("SUPER_CHAT_MESSAGE", ({ data }) =>
39
+ console.log(data.message),
40
+ );
41
+
42
+ // Dynamic/unknown events use a generic fallback
43
+ live.addEventListener<{ custom: string }>("NEW_CMD", ({ data }) =>
44
+ console.log(data.custom),
45
+ );
46
+ ```
47
+
48
+ ### Browser
49
+
22
50
  ```typescript
23
- // Or specifically use @laplace.live/ws/server or @laplace.live/ws/client
24
- import { LiveWS, LiveTCP, KeepLiveWS, KeepLiveTCP } from "@laplace.live/ws";
51
+ import { LiveWS, KeepLiveWS } from "@laplace.live/ws/browser";
25
52
 
26
- const live = new LiveWS(25034104);
53
+ const live = new LiveWS(25034104, { key: "...", address: "wss://..." });
54
+ live.addEventListener("DANMU_MSG", ({ data }) => console.log(data.msg_id));
55
+ ```
56
+
57
+ ### Auto-reconnecting
58
+
59
+ ```typescript
60
+ import { KeepLiveWS } from "@laplace.live/ws";
61
+
62
+ const keep = new KeepLiveWS(25034104, { key: "...", address: "wss://..." });
63
+ keep.addEventListener("heartbeat", ({ data }) => console.log("Online:", data));
64
+ keep.addEventListener("DANMU_MSG", ({ data }) => console.log(data.msg_id));
65
+ ```
66
+
67
+ ### TCP (Node.js / Bun only)
68
+
69
+ ```typescript
70
+ import { LiveTCP } from "@laplace.live/ws";
27
71
 
28
- live.on<T>("open", () => console.log("Connection established"));
29
- live.on("live", () => {
30
- live.on<T>("heartbeat", console.log);
31
- });
72
+ const live = new LiveTCP(25034104, { key: "..." });
73
+ live.addEventListener("heartbeat", ({ data }) => console.log("Online:", data));
32
74
  ```
33
75
 
34
76
  ## License
package/dist/browser.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { K as KeepLive, b as LiveWSBase, W as WSOptions } from './ws-D63GKJdI.js';
2
- export { c as LaplaceRawEvent, a as LiveOptions } from './ws-D63GKJdI.js';
1
+ import { K as KeepLive, b as LiveWSBase, W as WSOptions } from './ws-Cd0ulctk.js';
2
+ export { c as LaplaceRawEvent, d as LiveEventMap, a as LiveOptions } from './ws-Cd0ulctk.js';
3
+ import '@laplace.live/internal';
3
4
 
4
5
  /**
5
6
  * WebSocket client for a Bilibili live room (browser).
@@ -39,7 +40,7 @@ declare class LiveWS extends LiveWSBase {
39
40
  * keep.on('DANMU_MSG', (e) => console.log(e.data))
40
41
  * ```
41
42
  */
42
- declare class KeepLiveWS extends KeepLive<typeof LiveWSBase> {
43
+ declare class KeepLiveWS extends KeepLive<LiveWSBase> {
43
44
  constructor(roomid: number, opts?: WSOptions);
44
45
  }
45
46
 
package/dist/browser.js CHANGED
@@ -1798,8 +1798,8 @@ var LaplaceRawEvent = class extends Event {
1798
1798
 
1799
1799
  // src/keep-live.ts
1800
1800
  var KeepLive = class extends EventTarget {
1801
- /** @internal Stored constructor arguments for reconnection. */
1802
- params;
1801
+ /** @internal Factory that creates a fresh connection with the original arguments. */
1802
+ createConnection;
1803
1803
  /** `true` after {@link close} has been called; prevents further reconnects. */
1804
1804
  closed;
1805
1805
  /** Delay in milliseconds before attempting a reconnect. */
@@ -1808,16 +1808,13 @@ var KeepLive = class extends EventTarget {
1808
1808
  timeout;
1809
1809
  /** The current underlying connection instance. */
1810
1810
  connection;
1811
- /** @internal The base class constructor used to create new connections. */
1812
- Base;
1813
- constructor(Base, ...params) {
1811
+ constructor(createConnection) {
1814
1812
  super();
1815
- this.params = params;
1813
+ this.createConnection = createConnection;
1816
1814
  this.closed = false;
1817
1815
  this.interval = 100;
1818
1816
  this.timeout = 45 * 1e3;
1819
- this.connection = new Base(...this.params);
1820
- this.Base = Base;
1817
+ this.connection = this.createConnection();
1821
1818
  this.connect(false);
1822
1819
  }
1823
1820
  /**
@@ -1832,14 +1829,14 @@ var KeepLive = class extends EventTarget {
1832
1829
  /**
1833
1830
  * Wire up event forwarding and timeout handling on the current connection.
1834
1831
  * When `reconnect` is `true`, the previous connection is closed and a fresh
1835
- * one is created from the stored constructor parameters.
1832
+ * one is created via the factory.
1836
1833
  *
1837
1834
  * @param reconnect - Whether to tear down and recreate the connection first.
1838
1835
  */
1839
1836
  connect(reconnect = true) {
1840
1837
  if (reconnect) {
1841
1838
  this.connection.close();
1842
- this.connection = new this.Base(...this.params);
1839
+ this.connection = this.createConnection();
1843
1840
  }
1844
1841
  const connection = this.connection;
1845
1842
  let timeout = setTimeout(() => {
@@ -1905,28 +1902,6 @@ var KeepLive = class extends EventTarget {
1905
1902
  send(data) {
1906
1903
  return this.connection.send(data);
1907
1904
  }
1908
- /**
1909
- * Subscribe to an event type with a typed {@link LaplaceRawEvent} listener.
1910
- *
1911
- * @typeParam T - Expected data type carried by the event.
1912
- * @param type - Event name (e.g. `"heartbeat"`, `"msg"`, `"DANMU_MSG"`).
1913
- * @param listener - Callback receiving a {@link LaplaceRawEvent LaplaceRawEvent\<T\>}.
1914
- * @param options - Standard `addEventListener` options.
1915
- */
1916
- on(type, listener, options) {
1917
- this.addEventListener(type, listener, options);
1918
- }
1919
- /**
1920
- * Unsubscribe a previously registered listener.
1921
- *
1922
- * @typeParam T - Data type matching the original subscription.
1923
- * @param type - Event name.
1924
- * @param listener - The same function reference passed to {@link on}.
1925
- * @param options - Standard `removeEventListener` options.
1926
- */
1927
- off(type, listener, options) {
1928
- this.removeEventListener(type, listener, options);
1929
- }
1930
1905
  };
1931
1906
 
1932
1907
  // src/buffer.ts
@@ -2125,33 +2100,7 @@ var Live = class extends EventTarget {
2125
2100
  */
2126
2101
  getOnline() {
2127
2102
  this.heartbeat();
2128
- return new Promise(
2129
- (resolve) => this.addEventListener("heartbeat", (e) => resolve(e.data), { once: true })
2130
- );
2131
- }
2132
- /**
2133
- * Subscribe to an event type with a typed {@link LaplaceRawEvent} listener.
2134
- * Convenience wrapper around {@link EventTarget.addEventListener}.
2135
- *
2136
- * @typeParam T - Expected data type carried by the event.
2137
- * @param type - Event name (e.g. `"heartbeat"`, `"msg"`, `"DANMU_MSG"`).
2138
- * @param listener - Callback receiving a {@link LaplaceRawEvent LaplaceRawEvent\<T\>}.
2139
- * @param options - Standard `addEventListener` options.
2140
- */
2141
- on(type, listener, options) {
2142
- this.addEventListener(type, listener, options);
2143
- }
2144
- /**
2145
- * Unsubscribe a previously registered listener.
2146
- * Convenience wrapper around {@link EventTarget.removeEventListener}.
2147
- *
2148
- * @typeParam T - Data type matching the original subscription.
2149
- * @param type - Event name.
2150
- * @param listener - The same function reference passed to {@link on}.
2151
- * @param options - Standard `removeEventListener` options.
2152
- */
2153
- off(type, listener, options) {
2154
- this.removeEventListener(type, listener, options);
2103
+ return new Promise((resolve) => this.addEventListener("heartbeat", (e) => resolve(e.data), { once: true }));
2155
2104
  }
2156
2105
  };
2157
2106
 
@@ -2170,10 +2119,7 @@ var LiveWSBase = class extends Live {
2170
2119
  super(inflates2, roomid, { send, close, ...options });
2171
2120
  ws.binaryType = "arraybuffer";
2172
2121
  ws.addEventListener("open", (e) => this.dispatchEvent(new Event(e.type)));
2173
- ws.addEventListener(
2174
- "message",
2175
- (e) => this.dispatchEvent(new LaplaceRawEvent("message", new Uint8Array(e.data)))
2176
- );
2122
+ ws.addEventListener("message", (e) => this.dispatchEvent(new LaplaceRawEvent("message", new Uint8Array(e.data))));
2177
2123
  ws.addEventListener("close", (e) => this.dispatchEvent(new Event(e.type)));
2178
2124
  ws.addEventListener("error", () => this.dispatchEvent(new Event("_error")));
2179
2125
  this.ws = ws;
@@ -2188,7 +2134,7 @@ var LiveWS = class extends LiveWSBase {
2188
2134
  };
2189
2135
  var KeepLiveWS = class extends KeepLive {
2190
2136
  constructor(roomid, opts) {
2191
- super(LiveWSBase, inflates, roomid, opts);
2137
+ super(() => new LiveWSBase(inflates, roomid, opts));
2192
2138
  }
2193
2139
  };
2194
2140
  export {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { L as Live, I as Inflates, a as LiveOptions, K as KeepLive, b as LiveWSBase, W as WSOptions } from './ws-D63GKJdI.js';
2
- export { c as LaplaceRawEvent } from './ws-D63GKJdI.js';
1
+ import { L as Live, I as Inflates, a as LiveOptions, K as KeepLive, b as LiveWSBase, W as WSOptions } from './ws-Cd0ulctk.js';
2
+ export { c as LaplaceRawEvent, d as LiveEventMap } from './ws-Cd0ulctk.js';
3
3
  import { Socket } from 'node:net';
4
+ import { BilibiliInternal } from '@laplace.live/internal';
4
5
 
5
6
  /**
6
7
  * Configuration options for TCP-based live connections.
@@ -42,25 +43,6 @@ declare class LiveTCPBase extends Live {
42
43
  splitBuffer(): void;
43
44
  }
44
45
 
45
- type GET_DANMU_INFO = {
46
- code: number;
47
- message: string;
48
- ttl: number;
49
- data: {
50
- business_id: number;
51
- group: string;
52
- host_list: {
53
- host: string;
54
- port: number;
55
- wss_port: number;
56
- ws_port: number;
57
- }[];
58
- max_delay: number;
59
- refresh_rate: number;
60
- refresh_row_factor: number;
61
- token: string;
62
- };
63
- };
64
46
  /**
65
47
  * Fetch WebSocket connection configuration for a Bilibili live room directly
66
48
  * from the Bilibili API (`getDanmuInfo`).
@@ -82,7 +64,7 @@ declare const getConf: (roomid: number) => Promise<{
82
64
  key: string;
83
65
  host: string;
84
66
  address: string;
85
- raw: GET_DANMU_INFO;
67
+ json: BilibiliInternal.HTTPS.Prod.GetDanmuInfo;
86
68
  }>;
87
69
  /**
88
70
  * Resolve a short (vanity) room ID to its real numeric room ID via the
@@ -154,7 +136,7 @@ declare class LiveTCP extends LiveTCPBase {
154
136
  * keep.on('DANMU_MSG', (e) => console.log(e.data))
155
137
  * ```
156
138
  */
157
- declare class KeepLiveWS extends KeepLive<typeof LiveWSBase> {
139
+ declare class KeepLiveWS extends KeepLive<LiveWSBase> {
158
140
  constructor(roomid: number, opts?: WSOptions);
159
141
  }
160
142
  /**
@@ -176,7 +158,7 @@ declare class KeepLiveWS extends KeepLive<typeof LiveWSBase> {
176
158
  * keep.on('heartbeat', (e) => console.log('online:', e.data))
177
159
  * ```
178
160
  */
179
- declare class KeepLiveTCP extends KeepLive<typeof LiveTCPBase> {
161
+ declare class KeepLiveTCP extends KeepLive<LiveTCPBase> {
180
162
  constructor(roomid: number, opts?: TCPOptions);
181
163
  }
182
164
 
package/dist/index.js CHANGED
@@ -18,8 +18,8 @@ var LaplaceRawEvent = class extends Event {
18
18
 
19
19
  // src/keep-live.ts
20
20
  var KeepLive = class extends EventTarget {
21
- /** @internal Stored constructor arguments for reconnection. */
22
- params;
21
+ /** @internal Factory that creates a fresh connection with the original arguments. */
22
+ createConnection;
23
23
  /** `true` after {@link close} has been called; prevents further reconnects. */
24
24
  closed;
25
25
  /** Delay in milliseconds before attempting a reconnect. */
@@ -28,16 +28,13 @@ var KeepLive = class extends EventTarget {
28
28
  timeout;
29
29
  /** The current underlying connection instance. */
30
30
  connection;
31
- /** @internal The base class constructor used to create new connections. */
32
- Base;
33
- constructor(Base, ...params) {
31
+ constructor(createConnection) {
34
32
  super();
35
- this.params = params;
33
+ this.createConnection = createConnection;
36
34
  this.closed = false;
37
35
  this.interval = 100;
38
36
  this.timeout = 45 * 1e3;
39
- this.connection = new Base(...this.params);
40
- this.Base = Base;
37
+ this.connection = this.createConnection();
41
38
  this.connect(false);
42
39
  }
43
40
  /**
@@ -52,14 +49,14 @@ var KeepLive = class extends EventTarget {
52
49
  /**
53
50
  * Wire up event forwarding and timeout handling on the current connection.
54
51
  * When `reconnect` is `true`, the previous connection is closed and a fresh
55
- * one is created from the stored constructor parameters.
52
+ * one is created via the factory.
56
53
  *
57
54
  * @param reconnect - Whether to tear down and recreate the connection first.
58
55
  */
59
56
  connect(reconnect = true) {
60
57
  if (reconnect) {
61
58
  this.connection.close();
62
- this.connection = new this.Base(...this.params);
59
+ this.connection = this.createConnection();
63
60
  }
64
61
  const connection = this.connection;
65
62
  let timeout = setTimeout(() => {
@@ -125,28 +122,6 @@ var KeepLive = class extends EventTarget {
125
122
  send(data) {
126
123
  return this.connection.send(data);
127
124
  }
128
- /**
129
- * Subscribe to an event type with a typed {@link LaplaceRawEvent} listener.
130
- *
131
- * @typeParam T - Expected data type carried by the event.
132
- * @param type - Event name (e.g. `"heartbeat"`, `"msg"`, `"DANMU_MSG"`).
133
- * @param listener - Callback receiving a {@link LaplaceRawEvent LaplaceRawEvent\<T\>}.
134
- * @param options - Standard `addEventListener` options.
135
- */
136
- on(type, listener, options) {
137
- this.addEventListener(type, listener, options);
138
- }
139
- /**
140
- * Unsubscribe a previously registered listener.
141
- *
142
- * @typeParam T - Data type matching the original subscription.
143
- * @param type - Event name.
144
- * @param listener - The same function reference passed to {@link on}.
145
- * @param options - Standard `removeEventListener` options.
146
- */
147
- off(type, listener, options) {
148
- this.removeEventListener(type, listener, options);
149
- }
150
125
  };
151
126
 
152
127
  // src/tcp.ts
@@ -348,33 +323,7 @@ var Live = class extends EventTarget {
348
323
  */
349
324
  getOnline() {
350
325
  this.heartbeat();
351
- return new Promise(
352
- (resolve) => this.addEventListener("heartbeat", (e) => resolve(e.data), { once: true })
353
- );
354
- }
355
- /**
356
- * Subscribe to an event type with a typed {@link LaplaceRawEvent} listener.
357
- * Convenience wrapper around {@link EventTarget.addEventListener}.
358
- *
359
- * @typeParam T - Expected data type carried by the event.
360
- * @param type - Event name (e.g. `"heartbeat"`, `"msg"`, `"DANMU_MSG"`).
361
- * @param listener - Callback receiving a {@link LaplaceRawEvent LaplaceRawEvent\<T\>}.
362
- * @param options - Standard `addEventListener` options.
363
- */
364
- on(type, listener, options) {
365
- this.addEventListener(type, listener, options);
366
- }
367
- /**
368
- * Unsubscribe a previously registered listener.
369
- * Convenience wrapper around {@link EventTarget.removeEventListener}.
370
- *
371
- * @typeParam T - Data type matching the original subscription.
372
- * @param type - Event name.
373
- * @param listener - The same function reference passed to {@link on}.
374
- * @param options - Standard `removeEventListener` options.
375
- */
376
- off(type, listener, options) {
377
- this.removeEventListener(type, listener, options);
326
+ return new Promise((resolve) => this.addEventListener("heartbeat", (e) => resolve(e.data), { once: true }));
378
327
  }
379
328
  };
380
329
 
@@ -440,10 +389,7 @@ var LiveWSBase = class extends Live {
440
389
  super(inflates2, roomid, { send, close, ...options });
441
390
  ws.binaryType = "arraybuffer";
442
391
  ws.addEventListener("open", (e) => this.dispatchEvent(new Event(e.type)));
443
- ws.addEventListener(
444
- "message",
445
- (e) => this.dispatchEvent(new LaplaceRawEvent("message", new Uint8Array(e.data)))
446
- );
392
+ ws.addEventListener("message", (e) => this.dispatchEvent(new LaplaceRawEvent("message", new Uint8Array(e.data))));
447
393
  ws.addEventListener("close", (e) => this.dispatchEvent(new Event(e.type)));
448
394
  ws.addEventListener("error", () => this.dispatchEvent(new Event("_error")));
449
395
  this.ws = ws;
@@ -452,20 +398,19 @@ var LiveWSBase = class extends Live {
452
398
 
453
399
  // src/extra.ts
454
400
  var getConf = async (roomid) => {
455
- const raw = await fetch(`https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=${roomid}`).then(
456
- (w) => w.json()
457
- );
458
- if (!raw.data) {
459
- throw new Error(`getConf failed for room ${roomid}: ${raw.message || "no data"} (code: ${raw.code})`);
401
+ const resp = await fetch(`https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=${roomid}`);
402
+ const json = await resp.json();
403
+ if (!json.data) {
404
+ throw new Error(`getConf failed for room ${roomid}: ${json.message || "no data"} (code: ${json.code})`);
460
405
  }
461
406
  const {
462
407
  data: {
463
408
  token: key,
464
409
  host_list: [{ host }]
465
410
  }
466
- } = raw;
411
+ } = json;
467
412
  const address = `wss://${host}/sub`;
468
- return { key, host, address, raw };
413
+ return { key, host, address, json };
469
414
  };
470
415
  var getRoomid = async (short) => {
471
416
  const {
@@ -487,12 +432,12 @@ var LiveTCP = class extends LiveTCPBase {
487
432
  };
488
433
  var KeepLiveWS = class extends KeepLive {
489
434
  constructor(roomid, opts) {
490
- super(LiveWSBase, inflates, roomid, opts);
435
+ super(() => new LiveWSBase(inflates, roomid, opts));
491
436
  }
492
437
  };
493
438
  var KeepLiveTCP = class extends KeepLive {
494
439
  constructor(roomid, opts) {
495
- super(LiveTCPBase, inflates, roomid, opts);
440
+ super(() => new LiveTCPBase(inflates, roomid, opts));
496
441
  }
497
442
  };
498
443
  export {
@@ -0,0 +1,318 @@
1
+ import { BilibiliInternal } from '@laplace.live/internal';
2
+
3
+ /**
4
+ * Platform-specific inflate/decompress implementations injected into the
5
+ * decoder at construction time.
6
+ *
7
+ * - **Node / Bun**: backed by `node:zlib` (`inflate` + `brotliDecompress`).
8
+ * - **Browser**: backed by `pako` (inflate) + a bundled JS Brotli decoder.
9
+ */
10
+ type Inflates = {
11
+ inflateAsync: (b: Uint8Array) => Uint8Array | Promise<Uint8Array>;
12
+ brotliDecompressAsync: (b: Uint8Array) => Uint8Array | Promise<Uint8Array>;
13
+ };
14
+
15
+ /**
16
+ * A typed {@link Event} that carries an arbitrary data payload.
17
+ *
18
+ * Used throughout the library to deliver structured messages such as
19
+ * heartbeat counts, danmaku payloads, and other server-pushed data.
20
+ *
21
+ * Also used internally with `LaplaceRawEvent<Event>` as a catch-all meta-event
22
+ * (type `"event"`) to forward all events through {@link KeepLive}.
23
+ *
24
+ * @typeParam T - The type of the data payload attached to this event.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * live.addEventListener('heartbeat', (e) => {
29
+ * console.log('online:', e.data)
30
+ * })
31
+ * ```
32
+ */
33
+ declare class LaplaceRawEvent<T> extends Event {
34
+ data: T;
35
+ constructor(type: string, data: T);
36
+ }
37
+ /**
38
+ * Maps known event names to their event types for typed `addEventListener`.
39
+ *
40
+ * - Built-in lifecycle events (`open`, `live`, `close`, etc.) map to plain `Event`.
41
+ * - `heartbeat` maps to `LaplaceRawEvent<number>` (online viewer count).
42
+ * - `msg` maps to `LaplaceRawEvent<unknown>` (any server command).
43
+ * - Bilibili commands map to `LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.*>`.
44
+ * - Unknown/dynamic events fall through to a generic overload on `addEventListener`.
45
+ */
46
+ interface LiveEventMap {
47
+ open: Event;
48
+ live: Event;
49
+ close: Event;
50
+ error: Event;
51
+ heartbeat: LaplaceRawEvent<number>;
52
+ msg: LaplaceRawEvent<unknown>;
53
+ event: LaplaceRawEvent<Event>;
54
+ DANMU_MSG: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.DANMU_MSG>;
55
+ RECALL_DANMU_MSG: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.RECALL_DANMU_MSG>;
56
+ INTERACT_WORD: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.INTERACT_WORD>;
57
+ ENTRY_EFFECT: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ENTRY_EFFECT>;
58
+ USER_TOAST_MSG: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.USER_TOAST_MSG>;
59
+ USER_TOAST_MSG_V2: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.USER_TOAST_MSG_V2>;
60
+ SEND_GIFT: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.SEND_GIFT>;
61
+ SEND_GIFT_V2: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.SEND_GIFT_V2>;
62
+ INTERACT_WORD_V2: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.INTERACT_WORD_V2>;
63
+ SUPER_CHAT_MESSAGE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.SUPER_CHAT_MESSAGE>;
64
+ SUPER_CHAT_MESSAGE_DELETE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.SUPER_CHAT_MESSAGE_DELETE>;
65
+ USER_VIRTUAL_MVP: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.USER_VIRTUAL_MVP>;
66
+ LIKE_INFO_V3_CLICK: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.LIKE_INFO_V3_CLICK>;
67
+ POPULARITY_RED_POCKET_START: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.POPULARITY_RED_POCKET_START>;
68
+ POPULARITY_RED_POCKET_V2_START: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.POPULARITY_RED_POCKET_V2_START>;
69
+ POPULARITY_RED_POCKET_WINNER_LIST: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.POPULARITY_RED_POCKET_WINNER_LIST>;
70
+ POPULARITY_RED_POCKET_V2_WINNER_LIST: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.POPULARITY_RED_POCKET_V2_WINNER_LIST>;
71
+ ANCHOR_LOT_START: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ANCHOR_LOT_START>;
72
+ ANCHOR_LOT_AWARD: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ANCHOR_LOT_AWARD>;
73
+ COMMON_NOTICE_DANMAKU: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.COMMON_NOTICE_DANMAKU>;
74
+ EFFECT_DANMAKU_MSG: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.EFFECT_DANMAKU_MSG>;
75
+ DANMU_ACTIVITY_CONFIG: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.DANMU_ACTIVITY_CONFIG>;
76
+ ROOM_CHANGE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_CHANGE>;
77
+ ROOM_SILENT_ON: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_SILENT_ON>;
78
+ ROOM_SILENT_OFF: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_SILENT_OFF>;
79
+ WATCHED_CHANGE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.WATCHED_CHANGE>;
80
+ LIKE_INFO_V3_UPDATE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.LIKE_INFO_V3_UPDATE>;
81
+ ONLINE_RANK_COUNT: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ONLINE_RANK_COUNT>;
82
+ ONLINE_RANK_V2: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ONLINE_RANK_V2>;
83
+ ONLINE_RANK_V3: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ONLINE_RANK_V3>;
84
+ ROOM_REAL_TIME_MESSAGE_UPDATE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_REAL_TIME_MESSAGE_UPDATE>;
85
+ ROOM_REAL_TIME_MESSAGE_UPDATE_V2: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_REAL_TIME_MESSAGE_UPDATE_V2>;
86
+ LIVE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.LIVE>;
87
+ PREPARING: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.PREPARING>;
88
+ WARNING: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.WARNING>;
89
+ CUT_OFF: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.CUT_OFF>;
90
+ ROOM_BLOCK_MSG: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_BLOCK_MSG>;
91
+ ROOM_ADMINS: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_ADMINS>;
92
+ room_admin_entrance: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.room_admin_entrance>;
93
+ ROOM_ADMIN_REVOKE: LaplaceRawEvent<BilibiliInternal.WebSocket.Prod.ROOM_ADMIN_REVOKE>;
94
+ LIVE_OPEN_PLATFORM_DM: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_DM>;
95
+ LIVE_OPEN_PLATFORM_SEND_GIFT: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_SEND_GIFT>;
96
+ LIVE_OPEN_PLATFORM_SUPER_CHAT: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_SUPER_CHAT>;
97
+ LIVE_OPEN_PLATFORM_GUARD: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_GUARD>;
98
+ LIVE_OPEN_PLATFORM_LIKE: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_LIKE>;
99
+ LIVE_OPEN_PLATFORM_LIVE_ROOM_ENTER: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_LIVE_ROOM_ENTER>;
100
+ LIVE_OPEN_PLATFORM_LIVE_START: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_LIVE_START>;
101
+ LIVE_OPEN_PLATFORM_LIVE_END: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_LIVE_END>;
102
+ LIVE_OPEN_PLATFORM_INTERACTION_END: LaplaceRawEvent<BilibiliInternal.WebSocket.OpenPlatform.LIVE_OPEN_PLATFORM_INTERACTION_END>;
103
+ }
104
+
105
+ /**
106
+ * Options for configuring the Bilibili live connection authentication.
107
+ *
108
+ * When {@link authBody} is provided it takes precedence over all other
109
+ * fields and is sent as the join payload verbatim.
110
+ */
111
+ type LiveOptions = {
112
+ /** Protocol version. Defaults to `3` (brotli-compressed). */
113
+ protover?: 1 | 2 | 3;
114
+ /** Authentication token obtained from the danmaku info API. */
115
+ key?: string;
116
+ /**
117
+ * Pre-built authentication body. When supplied as a `Uint8Array` it is
118
+ * sent raw; when supplied as an object it is JSON-encoded before sending.
119
+ * Takes precedence over {@link key}, {@link uid}, and {@link buvid}.
120
+ */
121
+ authBody?: Uint8Array | Record<string, unknown>;
122
+ /** User ID. Defaults to `0` (anonymous). */
123
+ uid?: number;
124
+ /** Browser unique visitor ID used for risk-control tracking. */
125
+ buvid?: string;
126
+ };
127
+ /**
128
+ * Base class for a single Bilibili live room connection.
129
+ *
130
+ * Extends {@link EventTarget} and emits the following events:
131
+ *
132
+ * | Event | Payload | Description |
133
+ * |---------------|--------------------|--------------------------------------------------|
134
+ * | `open` | — | Underlying transport connected. |
135
+ * | `live` | — | Server acknowledged the join (room entered). |
136
+ * | `heartbeat` | `LaplaceRawEvent<number>`| Online viewer count received from server. |
137
+ * | `msg` | `LaplaceRawEvent<any>` | Any server command message. |
138
+ * | `DANMU_MSG` | `LaplaceRawEvent<any>` | Danmaku (chat) message. |
139
+ * | `close` | — | Connection closed. |
140
+ * | `error` | — | Unrecoverable error (connection is closed). |
141
+ * | `event` | `LaplaceRawEvent<Event>` | Meta-event wrapping every dispatched event. |
142
+ *
143
+ * Subclasses ({@link LiveWSBase}, {@link LiveTCPBase}) provide the concrete
144
+ * transport and supply `send` / `close` callbacks to this constructor.
145
+ *
146
+ * @param inflates - Platform-specific inflate + brotli decompressors.
147
+ * @param roomid - Numeric Bilibili live room ID.
148
+ * @param options - Transport callbacks and authentication options.
149
+ *
150
+ * @throws {Error} If `roomid` is not a finite number.
151
+ */
152
+ declare class Live extends EventTarget {
153
+ /** The live room ID this instance is connected to. */
154
+ roomid: number;
155
+ /** Latest known online viewer count, updated on each heartbeat. */
156
+ online: number;
157
+ /** `true` after the server acknowledges the join (`welcome` packet). */
158
+ live: boolean;
159
+ /** `true` after {@link close} has been called. */
160
+ closed: boolean;
161
+ /** @internal Handle for the heartbeat interval timer. */
162
+ timeout: ReturnType<typeof setTimeout>;
163
+ /** Send raw binary data over the underlying transport. */
164
+ send: (data: Uint8Array) => void;
165
+ /** Gracefully close the connection and set {@link closed} to `true`. */
166
+ close: () => void;
167
+ constructor(inflates: Inflates, roomid: number, { send, close, protover, key, authBody, uid, buvid, }: {
168
+ send: (data: Uint8Array) => void;
169
+ close: () => void;
170
+ } & LiveOptions);
171
+ /**
172
+ * Overridden to also dispatch a `LaplaceRawEvent<Event>` with type `"event"`
173
+ * for every event, enabling catch-all listeners.
174
+ */
175
+ dispatchEvent(event: Event): boolean;
176
+ /** Send a heartbeat packet to the server. */
177
+ heartbeat(): void;
178
+ /**
179
+ * Send a heartbeat and resolve with the online viewer count from the
180
+ * next heartbeat response.
181
+ * @returns A promise that resolves with the current online count.
182
+ */
183
+ getOnline(): Promise<number>;
184
+ /**
185
+ * Typed `addEventListener` that narrows the inherited {@link EventTarget}
186
+ * signature using {@link LiveEventMap}.
187
+ *
188
+ * - Known events (e.g. `"heartbeat"`, `"DANMU_MSG"`) are auto-typed.
189
+ * - Unknown/dynamic events accept a generic `<T>` for the payload type.
190
+ *
191
+ * Uses `declare` to shadow the inherited type without emitting code —
192
+ * at runtime this is still `EventTarget.prototype.addEventListener`.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * live.addEventListener('heartbeat', (e) => console.log(e.data))
197
+ * live.addEventListener('DANMU_MSG', ({ data }) => console.log(data.msg_id))
198
+ * live.addEventListener<CustomType>('NEW_CMD', ({ data }) => console.log(data))
199
+ * ```
200
+ */
201
+ addEventListener: {
202
+ <K extends keyof LiveEventMap>(type: K, listener: (ev: LiveEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
203
+ <T = unknown>(type: string, listener: (ev: LaplaceRawEvent<T>) => void, options?: boolean | AddEventListenerOptions): void;
204
+ };
205
+ /**
206
+ * Typed `removeEventListener` matching {@link addEventListener}.
207
+ *
208
+ * Uses `declare` to shadow the inherited type without emitting code.
209
+ */
210
+ removeEventListener: {
211
+ <K extends keyof LiveEventMap>(type: K, listener: (ev: LiveEventMap[K]) => void, options?: boolean | EventListenerOptions): void;
212
+ (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
213
+ };
214
+ }
215
+
216
+ /**
217
+ * Auto-reconnecting wrapper around a {@link Live} subclass.
218
+ *
219
+ * `KeepLive` maintains a persistent connection to a Bilibili live room by
220
+ * automatically re-creating the underlying {@link Live} instance whenever
221
+ * the connection drops or a heartbeat timeout is reached. All events from
222
+ * the inner connection are forwarded to this instance.
223
+ *
224
+ * @typeParam T - The concrete {@link Live} instance type being managed.
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * const keep = new KeepLiveWS(12345, { key: '...' })
229
+ * keep.addEventListener('heartbeat', (e) => console.log('online:', e.data))
230
+ * keep.addEventListener('DANMU_MSG', ({ data }) => console.log('danmaku:', data.msg_id))
231
+ * ```
232
+ */
233
+ declare class KeepLive<T extends Live> extends EventTarget {
234
+ /** @internal Factory that creates a fresh connection with the original arguments. */
235
+ private createConnection;
236
+ /** `true` after {@link close} has been called; prevents further reconnects. */
237
+ closed: boolean;
238
+ /** Delay in milliseconds before attempting a reconnect. */
239
+ interval: number;
240
+ /** Maximum milliseconds to wait for a heartbeat before forcing a reconnect. */
241
+ timeout: number;
242
+ /** The current underlying connection instance. */
243
+ connection: T;
244
+ constructor(createConnection: () => T);
245
+ /**
246
+ * Overridden to also dispatch a `LaplaceRawEvent<Event>` with type `"event"`
247
+ * for every event, enabling catch-all listeners.
248
+ */
249
+ dispatchEvent(event: Event): boolean;
250
+ /**
251
+ * Wire up event forwarding and timeout handling on the current connection.
252
+ * When `reconnect` is `true`, the previous connection is closed and a fresh
253
+ * one is created via the factory.
254
+ *
255
+ * @param reconnect - Whether to tear down and recreate the connection first.
256
+ */
257
+ connect(reconnect?: boolean): void;
258
+ /** Latest known online viewer count from the underlying connection. */
259
+ get online(): number;
260
+ /** The live room ID. */
261
+ get roomid(): number;
262
+ /** Permanently close the connection and stop reconnecting. */
263
+ close(): void;
264
+ /** Send a heartbeat packet to the server. */
265
+ heartbeat(): void;
266
+ /**
267
+ * Send a heartbeat and resolve with the online viewer count from the
268
+ * next heartbeat response.
269
+ * @returns A promise that resolves with the current online count.
270
+ */
271
+ getOnline(): Promise<number>;
272
+ /**
273
+ * Send raw binary data through the underlying connection.
274
+ * @param data - The binary packet to send.
275
+ */
276
+ send(data: Uint8Array): void;
277
+ /** {@inheritDoc Live.addEventListener} */
278
+ addEventListener: {
279
+ <K extends keyof LiveEventMap>(type: K, listener: (ev: LiveEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
280
+ <T = unknown>(type: string, listener: (ev: LaplaceRawEvent<T>) => void, options?: boolean | AddEventListenerOptions): void;
281
+ };
282
+ /** {@inheritDoc Live.removeEventListener} */
283
+ removeEventListener: {
284
+ <K extends keyof LiveEventMap>(type: K, listener: (ev: LiveEventMap[K]) => void, options?: boolean | EventListenerOptions): void;
285
+ (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
286
+ };
287
+ }
288
+
289
+ /**
290
+ * Configuration options for WebSocket-based live connections.
291
+ * Extends {@link LiveOptions} with an optional WebSocket server address.
292
+ */
293
+ type WSOptions = LiveOptions & {
294
+ /** WebSocket server URL. Defaults to `wss://broadcastlv.chat.bilibili.com/sub`. */
295
+ address?: string;
296
+ };
297
+ /**
298
+ * WebSocket transport for Bilibili live room connections.
299
+ *
300
+ * Wraps a native {@link WebSocket}, wiring its lifecycle events (`open`,
301
+ * `message`, `close`, `error`) into the {@link Live} event system. Binary
302
+ * frames are forwarded as `LaplaceRawEvent<Uint8Array>` for protocol decoding.
303
+ *
304
+ * Not typically instantiated directly — use {@link LiveWS} (server) or the
305
+ * browser-specific `LiveWS` which inject the appropriate inflate
306
+ * implementation.
307
+ *
308
+ * @param inflates - Platform-specific inflate/brotli decompressors.
309
+ * @param roomid - Numeric Bilibili live room ID.
310
+ * @param options - WebSocket address and authentication options.
311
+ */
312
+ declare class LiveWSBase extends Live {
313
+ /** The underlying native WebSocket instance. */
314
+ ws: WebSocket;
315
+ constructor(inflates: Inflates, roomid: number, { address, ...options }?: WSOptions);
316
+ }
317
+
318
+ export { type Inflates as I, KeepLive as K, Live as L, type WSOptions as W, type LiveOptions as a, LiveWSBase as b, LaplaceRawEvent as c, type LiveEventMap as d };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laplace.live/ws",
3
- "version": "7.0.2",
3
+ "version": "7.1.0",
4
4
  "description": "Bilibili Live WebSocket/TCP API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,6 +60,7 @@
60
60
  "provenance": true
61
61
  },
62
62
  "dependencies": {
63
+ "@laplace.live/internal": "^1.3.4",
63
64
  "pako": "^2.1.0"
64
65
  },
65
66
  "devDependencies": {
@@ -1,250 +0,0 @@
1
- /**
2
- * Platform-specific inflate/decompress implementations injected into the
3
- * decoder at construction time.
4
- *
5
- * - **Node / Bun**: backed by `node:zlib` (`inflate` + `brotliDecompress`).
6
- * - **Browser**: backed by `pako` (inflate) + a bundled JS Brotli decoder.
7
- */
8
- type Inflates = {
9
- inflateAsync: (b: Uint8Array) => Uint8Array | Promise<Uint8Array>;
10
- brotliDecompressAsync: (b: Uint8Array) => Uint8Array | Promise<Uint8Array>;
11
- };
12
-
13
- /**
14
- * A typed {@link Event} that carries an arbitrary data payload.
15
- *
16
- * Used throughout the library to deliver structured messages such as
17
- * heartbeat counts, danmaku payloads, and other server-pushed data.
18
- *
19
- * Also used internally with `LaplaceRawEvent<Event>` as a catch-all meta-event
20
- * (type `"event"`) to forward all events through {@link KeepLive}.
21
- *
22
- * @typeParam T - The type of the data payload attached to this event.
23
- *
24
- * @example
25
- * ```ts
26
- * live.on<number>('heartbeat', (e) => {
27
- * console.log('online:', e.data)
28
- * })
29
- * ```
30
- */
31
- declare class LaplaceRawEvent<T> extends Event {
32
- data: T;
33
- constructor(type: string, data: T);
34
- }
35
-
36
- /**
37
- * Options for configuring the Bilibili live connection authentication.
38
- *
39
- * When {@link authBody} is provided it takes precedence over all other
40
- * fields and is sent as the join payload verbatim.
41
- */
42
- type LiveOptions = {
43
- /** Protocol version. Defaults to `3` (brotli-compressed). */
44
- protover?: 1 | 2 | 3;
45
- /** Authentication token obtained from the danmaku info API. */
46
- key?: string;
47
- /**
48
- * Pre-built authentication body. When supplied as a `Uint8Array` it is
49
- * sent raw; when supplied as an object it is JSON-encoded before sending.
50
- * Takes precedence over {@link key}, {@link uid}, and {@link buvid}.
51
- */
52
- authBody?: Uint8Array | Record<string, unknown>;
53
- /** User ID. Defaults to `0` (anonymous). */
54
- uid?: number;
55
- /** Browser unique visitor ID used for risk-control tracking. */
56
- buvid?: string;
57
- };
58
- /**
59
- * Base class for a single Bilibili live room connection.
60
- *
61
- * Extends {@link EventTarget} and emits the following events:
62
- *
63
- * | Event | Payload | Description |
64
- * |---------------|--------------------|--------------------------------------------------|
65
- * | `open` | — | Underlying transport connected. |
66
- * | `live` | — | Server acknowledged the join (room entered). |
67
- * | `heartbeat` | `LaplaceRawEvent<number>`| Online viewer count received from server. |
68
- * | `msg` | `LaplaceRawEvent<any>` | Any server command message. |
69
- * | `DANMU_MSG` | `LaplaceRawEvent<any>` | Danmaku (chat) message. |
70
- * | `close` | — | Connection closed. |
71
- * | `error` | — | Unrecoverable error (connection is closed). |
72
- * | `event` | `LaplaceRawEvent<Event>` | Meta-event wrapping every dispatched event. |
73
- *
74
- * Subclasses ({@link LiveWSBase}, {@link LiveTCPBase}) provide the concrete
75
- * transport and supply `send` / `close` callbacks to this constructor.
76
- *
77
- * @param inflates - Platform-specific inflate + brotli decompressors.
78
- * @param roomid - Numeric Bilibili live room ID.
79
- * @param options - Transport callbacks and authentication options.
80
- *
81
- * @throws {Error} If `roomid` is not a finite number.
82
- */
83
- declare class Live extends EventTarget {
84
- /** The live room ID this instance is connected to. */
85
- roomid: number;
86
- /** Latest known online viewer count, updated on each heartbeat. */
87
- online: number;
88
- /** `true` after the server acknowledges the join (`welcome` packet). */
89
- live: boolean;
90
- /** `true` after {@link close} has been called. */
91
- closed: boolean;
92
- /** @internal Handle for the heartbeat interval timer. */
93
- timeout: ReturnType<typeof setTimeout>;
94
- /** Send raw binary data over the underlying transport. */
95
- send: (data: Uint8Array) => void;
96
- /** Gracefully close the connection and set {@link closed} to `true`. */
97
- close: () => void;
98
- constructor(inflates: Inflates, roomid: number, { send, close, protover, key, authBody, uid, buvid, }: {
99
- send: (data: Uint8Array) => void;
100
- close: () => void;
101
- } & LiveOptions);
102
- /**
103
- * Overridden to also dispatch a `LaplaceRawEvent<Event>` with type `"event"`
104
- * for every event, enabling catch-all listeners.
105
- */
106
- dispatchEvent(event: Event): boolean;
107
- /** Send a heartbeat packet to the server. */
108
- heartbeat(): void;
109
- /**
110
- * Send a heartbeat and resolve with the online viewer count from the
111
- * next heartbeat response.
112
- * @returns A promise that resolves with the current online count.
113
- */
114
- getOnline(): Promise<number>;
115
- /**
116
- * Subscribe to an event type with a typed {@link LaplaceRawEvent} listener.
117
- * Convenience wrapper around {@link EventTarget.addEventListener}.
118
- *
119
- * @typeParam T - Expected data type carried by the event.
120
- * @param type - Event name (e.g. `"heartbeat"`, `"msg"`, `"DANMU_MSG"`).
121
- * @param listener - Callback receiving a {@link LaplaceRawEvent LaplaceRawEvent\<T\>}.
122
- * @param options - Standard `addEventListener` options.
123
- */
124
- on<T = unknown>(type: string, listener: (event: LaplaceRawEvent<T>) => void, options?: boolean | AddEventListenerOptions): void;
125
- /**
126
- * Unsubscribe a previously registered listener.
127
- * Convenience wrapper around {@link EventTarget.removeEventListener}.
128
- *
129
- * @typeParam T - Data type matching the original subscription.
130
- * @param type - Event name.
131
- * @param listener - The same function reference passed to {@link on}.
132
- * @param options - Standard `removeEventListener` options.
133
- */
134
- off<T = unknown>(type: string, listener: (event: LaplaceRawEvent<T>) => void, options?: boolean | EventListenerOptions): void;
135
- }
136
-
137
- /**
138
- * Auto-reconnecting wrapper around a {@link Live} subclass.
139
- *
140
- * `KeepLive` maintains a persistent connection to a Bilibili live room by
141
- * automatically re-creating the underlying {@link Live} instance whenever
142
- * the connection drops or a heartbeat timeout is reached. All events from
143
- * the inner connection are forwarded to this instance.
144
- *
145
- * @typeParam Base - The concrete {@link Live} subclass to manage
146
- * (e.g. `typeof LiveWSBase` or `typeof LiveTCPBase`).
147
- *
148
- * @example
149
- * ```ts
150
- * const keep = new KeepLiveWS(12345, { key: '...' })
151
- * keep.on('heartbeat', (e) => console.log('online:', e.data))
152
- * keep.on('DANMU_MSG', (e) => console.log('danmaku:', e.data))
153
- * ```
154
- */
155
- declare class KeepLive<Base extends typeof Live> extends EventTarget {
156
- /** @internal Stored constructor arguments for reconnection. */
157
- params: ConstructorParameters<Base>;
158
- /** `true` after {@link close} has been called; prevents further reconnects. */
159
- closed: boolean;
160
- /** Delay in milliseconds before attempting a reconnect. */
161
- interval: number;
162
- /** Maximum milliseconds to wait for a heartbeat before forcing a reconnect. */
163
- timeout: number;
164
- /** The current underlying connection instance. */
165
- connection: InstanceType<Base>;
166
- /** @internal The base class constructor used to create new connections. */
167
- Base: Base;
168
- constructor(Base: Base, ...params: ConstructorParameters<Base>);
169
- /**
170
- * Overridden to also dispatch a `LaplaceRawEvent<Event>` with type `"event"`
171
- * for every event, enabling catch-all listeners.
172
- */
173
- dispatchEvent(event: Event): boolean;
174
- /**
175
- * Wire up event forwarding and timeout handling on the current connection.
176
- * When `reconnect` is `true`, the previous connection is closed and a fresh
177
- * one is created from the stored constructor parameters.
178
- *
179
- * @param reconnect - Whether to tear down and recreate the connection first.
180
- */
181
- connect(reconnect?: boolean): void;
182
- /** Latest known online viewer count from the underlying connection. */
183
- get online(): number;
184
- /** The live room ID. */
185
- get roomid(): number;
186
- /** Permanently close the connection and stop reconnecting. */
187
- close(): void;
188
- /** Send a heartbeat packet to the server. */
189
- heartbeat(): void;
190
- /**
191
- * Send a heartbeat and resolve with the online viewer count from the
192
- * next heartbeat response.
193
- * @returns A promise that resolves with the current online count.
194
- */
195
- getOnline(): Promise<number>;
196
- /**
197
- * Send raw binary data through the underlying connection.
198
- * @param data - The binary packet to send.
199
- */
200
- send(data: Uint8Array): void;
201
- /**
202
- * Subscribe to an event type with a typed {@link LaplaceRawEvent} listener.
203
- *
204
- * @typeParam T - Expected data type carried by the event.
205
- * @param type - Event name (e.g. `"heartbeat"`, `"msg"`, `"DANMU_MSG"`).
206
- * @param listener - Callback receiving a {@link LaplaceRawEvent LaplaceRawEvent\<T\>}.
207
- * @param options - Standard `addEventListener` options.
208
- */
209
- on<T = unknown>(type: string, listener: (event: LaplaceRawEvent<T>) => void, options?: boolean | AddEventListenerOptions): void;
210
- /**
211
- * Unsubscribe a previously registered listener.
212
- *
213
- * @typeParam T - Data type matching the original subscription.
214
- * @param type - Event name.
215
- * @param listener - The same function reference passed to {@link on}.
216
- * @param options - Standard `removeEventListener` options.
217
- */
218
- off<T = unknown>(type: string, listener: (event: LaplaceRawEvent<T>) => void, options?: boolean | EventListenerOptions): void;
219
- }
220
-
221
- /**
222
- * Configuration options for WebSocket-based live connections.
223
- * Extends {@link LiveOptions} with an optional WebSocket server address.
224
- */
225
- type WSOptions = LiveOptions & {
226
- /** WebSocket server URL. Defaults to `wss://broadcastlv.chat.bilibili.com/sub`. */
227
- address?: string;
228
- };
229
- /**
230
- * WebSocket transport for Bilibili live room connections.
231
- *
232
- * Wraps a native {@link WebSocket}, wiring its lifecycle events (`open`,
233
- * `message`, `close`, `error`) into the {@link Live} event system. Binary
234
- * frames are forwarded as `LaplaceRawEvent<Uint8Array>` for protocol decoding.
235
- *
236
- * Not typically instantiated directly — use {@link LiveWS} (server) or the
237
- * browser-specific `LiveWS` which inject the appropriate inflate
238
- * implementation.
239
- *
240
- * @param inflates - Platform-specific inflate/brotli decompressors.
241
- * @param roomid - Numeric Bilibili live room ID.
242
- * @param options - WebSocket address and authentication options.
243
- */
244
- declare class LiveWSBase extends Live {
245
- /** The underlying native WebSocket instance. */
246
- ws: WebSocket;
247
- constructor(inflates: Inflates, roomid: number, { address, ...options }?: WSOptions);
248
- }
249
-
250
- export { type Inflates as I, KeepLive as K, Live as L, type WSOptions as W, type LiveOptions as a, LiveWSBase as b, LaplaceRawEvent as c };