@laplace.live/ws 7.0.2 → 7.1.4
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 +50 -8
- package/dist/browser.d.ts +4 -3
- package/dist/browser.js +10 -64
- package/dist/index.d.ts +6 -24
- package/dist/index.js +17 -72
- package/dist/ws-Cd0ulctk.d.ts +318 -0
- package/package.json +6 -2
- package/dist/ws-D63GKJdI.d.ts +0 -250
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 `
|
|
11
|
+
- Typed `addEventListener` via `LiveEventMap` with `@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
|
-
|
|
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
|
|
29
|
-
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-
|
|
2
|
-
export { c as LaplaceRawEvent, a as LiveOptions } from './ws-
|
|
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<
|
|
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
|
|
1802
|
-
|
|
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
|
-
|
|
1812
|
-
Base;
|
|
1813
|
-
constructor(Base, ...params) {
|
|
1811
|
+
constructor(createConnection) {
|
|
1814
1812
|
super();
|
|
1815
|
-
this.
|
|
1813
|
+
this.createConnection = createConnection;
|
|
1816
1814
|
this.closed = false;
|
|
1817
1815
|
this.interval = 100;
|
|
1818
1816
|
this.timeout = 45 * 1e3;
|
|
1819
|
-
this.connection =
|
|
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
|
|
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 =
|
|
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
|
|
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-
|
|
2
|
-
export { c as LaplaceRawEvent } from './ws-
|
|
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
|
-
|
|
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<
|
|
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<
|
|
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
|
|
22
|
-
|
|
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
|
-
|
|
32
|
-
Base;
|
|
33
|
-
constructor(Base, ...params) {
|
|
31
|
+
constructor(createConnection) {
|
|
34
32
|
super();
|
|
35
|
-
this.
|
|
33
|
+
this.createConnection = createConnection;
|
|
36
34
|
this.closed = false;
|
|
37
35
|
this.interval = 100;
|
|
38
36
|
this.timeout = 45 * 1e3;
|
|
39
|
-
this.connection =
|
|
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
|
|
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 =
|
|
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
|
|
456
|
-
|
|
457
|
-
)
|
|
458
|
-
|
|
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
|
-
} =
|
|
411
|
+
} = json;
|
|
467
412
|
const address = `wss://${host}/sub`;
|
|
468
|
-
return { key, host, address,
|
|
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
|
|
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
|
|
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.
|
|
3
|
+
"version": "7.1.4",
|
|
4
4
|
"description": "Bilibili Live WebSocket/TCP API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
"build": "tsup",
|
|
36
36
|
"check": "tsc --noEmit",
|
|
37
37
|
"test": "bun test --timeout 5000",
|
|
38
|
-
"prepublishOnly": "bun run build"
|
|
38
|
+
"prepublishOnly": "bun run build",
|
|
39
|
+
"release": "changeset publish",
|
|
40
|
+
"version": "changeset version"
|
|
39
41
|
},
|
|
40
42
|
"repository": {
|
|
41
43
|
"type": "git",
|
|
@@ -60,10 +62,12 @@
|
|
|
60
62
|
"provenance": true
|
|
61
63
|
},
|
|
62
64
|
"dependencies": {
|
|
65
|
+
"@laplace.live/internal": "^1.3.4",
|
|
63
66
|
"pako": "^2.1.0"
|
|
64
67
|
},
|
|
65
68
|
"devDependencies": {
|
|
66
69
|
"@biomejs/biome": "^2.4.6",
|
|
70
|
+
"@changesets/cli": "^2.30.0",
|
|
67
71
|
"@types/bun": "^1.3.10",
|
|
68
72
|
"@types/pako": "^2.0.4",
|
|
69
73
|
"tsup": "^8.5.1",
|
package/dist/ws-D63GKJdI.d.ts
DELETED
|
@@ -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 };
|