@laplace.live/ws 6.3.4 → 6.3.6

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.
@@ -0,0 +1,55 @@
1
+ type Inflates = {
2
+ inflateAsync: (b: Uint8Array) => Uint8Array | Promise<Uint8Array>;
3
+ brotliDecompressAsync: (b: Uint8Array) => Uint8Array | Promise<Uint8Array>;
4
+ };
5
+
6
+ type LiveOptions = {
7
+ protover?: 1 | 2 | 3;
8
+ key?: string;
9
+ authBody?: any;
10
+ uid?: number;
11
+ buvid?: string;
12
+ };
13
+ declare class DataEvent<T> extends Event {
14
+ data: T;
15
+ constructor(type: string, data: T);
16
+ }
17
+ declare class EventEvent extends Event {
18
+ event: Event;
19
+ constructor(event: Event);
20
+ }
21
+ declare class Live extends EventTarget {
22
+ roomid: number;
23
+ online: number;
24
+ live: boolean;
25
+ closed: boolean;
26
+ timeout: ReturnType<typeof setTimeout>;
27
+ send: (data: Uint8Array) => void;
28
+ close: () => void;
29
+ constructor(inflates: Inflates, roomid: number, { send, close, protover, key, authBody, uid, buvid, }: {
30
+ send: (data: Uint8Array) => void;
31
+ close: () => void;
32
+ } & LiveOptions);
33
+ dispatchEvent(event: Event): boolean;
34
+ heartbeat(): void;
35
+ getOnline(): Promise<number>;
36
+ }
37
+ declare class KeepLive<Base extends typeof Live> extends EventTarget {
38
+ params: ConstructorParameters<Base>;
39
+ closed: boolean;
40
+ interval: number;
41
+ timeout: number;
42
+ connection: InstanceType<Base>;
43
+ Base: Base;
44
+ constructor(Base: Base, ...params: ConstructorParameters<Base>);
45
+ dispatchEvent(event: Event): boolean;
46
+ connect(reconnect?: boolean): void;
47
+ get online(): number;
48
+ get roomid(): number;
49
+ close(): void;
50
+ heartbeat(): void;
51
+ getOnline(): Promise<number>;
52
+ send(data: Uint8Array): void;
53
+ }
54
+
55
+ export { DataEvent as D, EventEvent as E, type Inflates as I, KeepLive as K, Live as L, type LiveOptions as a };
@@ -0,0 +1,68 @@
1
+ import { L as Live, I as Inflates, a as LiveOptions, K as KeepLive } from './common-D1XOmtU3.js';
2
+ export { D as DataEvent, E as EventEvent } from './common-D1XOmtU3.js';
3
+ import { Socket } from 'node:net';
4
+ import { Agent } from 'node:http';
5
+ import WS from 'ws';
6
+
7
+ type TCPOptions = LiveOptions & {
8
+ host?: string;
9
+ port?: number;
10
+ };
11
+ declare class LiveTCPBase extends Live {
12
+ socket: Socket;
13
+ buf: Buffer;
14
+ i: number;
15
+ constructor(inflates: Inflates, roomid: number, { host, port, ...options }?: TCPOptions);
16
+ splitBuffer(): void;
17
+ }
18
+
19
+ type WSOptions = LiveOptions & {
20
+ address?: string;
21
+ agent?: Agent;
22
+ };
23
+ declare class LiveWSBase extends Live {
24
+ ws: WS;
25
+ constructor(inflates: Inflates, roomid: number, { address, agent, ...options }?: WSOptions);
26
+ }
27
+
28
+ type GET_DANMU_INFO = {
29
+ code: number;
30
+ message: string;
31
+ ttl: number;
32
+ data: {
33
+ business_id: number;
34
+ group: string;
35
+ host_list: {
36
+ host: string;
37
+ port: number;
38
+ wss_port: number;
39
+ ws_port: number;
40
+ }[];
41
+ max_delay: number;
42
+ refresh_rate: number;
43
+ refresh_row_factor: number;
44
+ token: string;
45
+ };
46
+ };
47
+ declare const getConf: (roomid: number) => Promise<{
48
+ key: string;
49
+ host: string;
50
+ address: string;
51
+ raw: GET_DANMU_INFO;
52
+ }>;
53
+ declare const getRoomid: (short: number) => Promise<any>;
54
+
55
+ declare class LiveWS extends LiveWSBase {
56
+ constructor(roomid: number, opts?: WSOptions);
57
+ }
58
+ declare class LiveTCP extends LiveTCPBase {
59
+ constructor(roomid: number, opts?: TCPOptions);
60
+ }
61
+ declare class KeepLiveWS extends KeepLive<typeof LiveWSBase> {
62
+ constructor(roomid: number, opts?: WSOptions);
63
+ }
64
+ declare class KeepLiveTCP extends KeepLive<typeof LiveTCPBase> {
65
+ constructor(roomid: number, opts?: TCPOptions);
66
+ }
67
+
68
+ export { KeepLiveTCP, KeepLiveWS, LiveOptions, LiveTCP, LiveWS, type TCPOptions, type WSOptions, getConf, getRoomid };
package/dist/index.js ADDED
@@ -0,0 +1,395 @@
1
+ // src/buffer.ts
2
+ var textEncoder = new TextEncoder();
3
+ var textDecoder = new TextDecoder();
4
+ function concatUint8Arrays(arrs) {
5
+ let totalLength = 0;
6
+ for (const arr of arrs) totalLength += arr.length;
7
+ const result = new Uint8Array(totalLength);
8
+ let offset = 0;
9
+ for (const arr of arrs) {
10
+ result.set(arr, offset);
11
+ offset += arr.length;
12
+ }
13
+ return result;
14
+ }
15
+ var cutBuffer = (buffer) => {
16
+ const bufferPacks = [];
17
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
18
+ let size;
19
+ for (let i = 0; i < buffer.length; i += size) {
20
+ size = view.getInt32(i);
21
+ bufferPacks.push(buffer.slice(i, i + size));
22
+ }
23
+ return bufferPacks;
24
+ };
25
+ var makeDecoder = ({ inflateAsync: inflateAsync2, brotliDecompressAsync: brotliDecompressAsync2 }) => {
26
+ const decoder = async (buffer) => {
27
+ const packs = await Promise.all(
28
+ cutBuffer(buffer).map(async (buf) => {
29
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
30
+ const body = buf.slice(16);
31
+ const protocol = view.getInt16(6);
32
+ const operation = view.getInt32(8);
33
+ let type = "unknow";
34
+ if (operation === 3) {
35
+ type = "heartbeat";
36
+ } else if (operation === 5) {
37
+ type = "message";
38
+ } else if (operation === 8) {
39
+ type = "welcome";
40
+ }
41
+ let data;
42
+ if (protocol === 0) {
43
+ data = JSON.parse(textDecoder.decode(body));
44
+ }
45
+ if (protocol === 1 && body.length === 4) {
46
+ const bodyView = new DataView(body.buffer, body.byteOffset, body.byteLength);
47
+ data = bodyView.getUint32(0);
48
+ }
49
+ if (protocol === 2) {
50
+ data = await decoder(await inflateAsync2(body));
51
+ }
52
+ if (protocol === 3) {
53
+ data = await decoder(await brotliDecompressAsync2(body));
54
+ }
55
+ return { buf, type, protocol, data };
56
+ })
57
+ );
58
+ return packs.flatMap((pack) => {
59
+ if (pack.protocol === 2 || pack.protocol === 3) {
60
+ return pack.data;
61
+ }
62
+ return pack;
63
+ });
64
+ };
65
+ return decoder;
66
+ };
67
+ var encoder = (type, body = "") => {
68
+ if (typeof body !== "string") {
69
+ body = JSON.stringify(body);
70
+ }
71
+ const head = new Uint8Array(16);
72
+ const headView = new DataView(head.buffer, head.byteOffset, head.byteLength);
73
+ const buffer = textEncoder.encode(body);
74
+ headView.setInt32(0, buffer.length + head.length);
75
+ headView.setInt16(4, 16);
76
+ headView.setInt16(6, 1);
77
+ if (type === "heartbeat") {
78
+ headView.setInt32(8, 2);
79
+ }
80
+ if (type === "join") {
81
+ headView.setInt32(8, 7);
82
+ }
83
+ headView.setInt32(12, 1);
84
+ return concatUint8Arrays([head, buffer]);
85
+ };
86
+
87
+ // src/common.ts
88
+ var DataEvent = class extends Event {
89
+ data;
90
+ constructor(type, data) {
91
+ super(type);
92
+ this.data = data;
93
+ }
94
+ };
95
+ var EventEvent = class extends Event {
96
+ event;
97
+ constructor(event) {
98
+ super("event");
99
+ this.event = event;
100
+ }
101
+ };
102
+ var Live = class extends EventTarget {
103
+ roomid;
104
+ online;
105
+ live;
106
+ closed;
107
+ timeout;
108
+ send;
109
+ close;
110
+ constructor(inflates2, roomid, {
111
+ send,
112
+ close,
113
+ protover = 3,
114
+ key,
115
+ authBody,
116
+ uid = 0,
117
+ buvid
118
+ }) {
119
+ if (typeof roomid !== "number" || Number.isNaN(roomid)) {
120
+ throw new Error(`roomid ${roomid} must be Number not NaN`);
121
+ }
122
+ super();
123
+ this.roomid = roomid;
124
+ this.online = 0;
125
+ this.live = false;
126
+ this.closed = false;
127
+ this.timeout = setTimeout(() => {
128
+ }, 0);
129
+ this.send = send;
130
+ this.close = () => {
131
+ this.closed = true;
132
+ close();
133
+ };
134
+ const decode = makeDecoder(inflates2);
135
+ this.addEventListener("message", async (e) => {
136
+ const buffer = e.data;
137
+ const packs = await decode(buffer);
138
+ packs.forEach(({ type, data }) => {
139
+ if (type === "welcome") {
140
+ this.live = true;
141
+ this.dispatchEvent(new Event("live"));
142
+ this.send(encoder("heartbeat"));
143
+ }
144
+ if (type === "heartbeat") {
145
+ this.online = data;
146
+ clearTimeout(this.timeout);
147
+ this.timeout = setTimeout(() => this.heartbeat(), 1e3 * 30);
148
+ this.dispatchEvent(new DataEvent("heartbeat", this.online));
149
+ }
150
+ if (type === "message") {
151
+ this.dispatchEvent(new DataEvent("msg", data));
152
+ const cmd = data.cmd || data.msg?.cmd;
153
+ if (cmd) {
154
+ if (cmd.includes("DANMU_MSG")) {
155
+ this.dispatchEvent(new DataEvent("DANMU_MSG", data));
156
+ } else {
157
+ this.dispatchEvent(new DataEvent(cmd, data));
158
+ }
159
+ }
160
+ }
161
+ });
162
+ });
163
+ this.addEventListener("open", () => {
164
+ if (authBody) {
165
+ if (typeof authBody === "object") {
166
+ authBody = encoder("join", authBody);
167
+ }
168
+ this.send(authBody);
169
+ } else {
170
+ const hi = { uid, roomid, protover, platform: "web", type: 2 };
171
+ if (key) {
172
+ hi.key = key;
173
+ }
174
+ if (buvid) {
175
+ hi.buvid = buvid;
176
+ }
177
+ const buf = encoder("join", hi);
178
+ this.send(buf);
179
+ }
180
+ });
181
+ this.addEventListener("close", () => {
182
+ clearTimeout(this.timeout);
183
+ });
184
+ this.addEventListener("_error", () => {
185
+ this.close();
186
+ this.dispatchEvent(new Event("error"));
187
+ });
188
+ }
189
+ dispatchEvent(event) {
190
+ const result = super.dispatchEvent(event);
191
+ super.dispatchEvent(new EventEvent(event));
192
+ return result;
193
+ }
194
+ heartbeat() {
195
+ this.send(encoder("heartbeat"));
196
+ }
197
+ getOnline() {
198
+ this.heartbeat();
199
+ return new Promise(
200
+ (resolve) => this.addEventListener("heartbeat", (e) => resolve(e.data), { once: true })
201
+ );
202
+ }
203
+ };
204
+ var KeepLive = class extends EventTarget {
205
+ params;
206
+ closed;
207
+ interval;
208
+ timeout;
209
+ connection;
210
+ Base;
211
+ constructor(Base, ...params) {
212
+ super();
213
+ this.params = params;
214
+ this.closed = false;
215
+ this.interval = 100;
216
+ this.timeout = 45 * 1e3;
217
+ this.connection = new Base(...this.params);
218
+ this.Base = Base;
219
+ this.connect(false);
220
+ }
221
+ dispatchEvent(event) {
222
+ const result = super.dispatchEvent(event);
223
+ super.dispatchEvent(new EventEvent(event));
224
+ return result;
225
+ }
226
+ connect(reconnect = true) {
227
+ if (reconnect) {
228
+ this.connection.close();
229
+ this.connection = new this.Base(...this.params);
230
+ }
231
+ const connection = this.connection;
232
+ let timeout = setTimeout(() => {
233
+ connection.close();
234
+ connection.dispatchEvent(new Event("timeout"));
235
+ }, this.timeout);
236
+ connection.addEventListener("event", (e) => {
237
+ const evt = e.event;
238
+ if (evt.type !== "error") {
239
+ if (evt instanceof DataEvent) {
240
+ this.dispatchEvent(new DataEvent(evt.type, evt.data));
241
+ } else {
242
+ this.dispatchEvent(new Event(evt.type));
243
+ }
244
+ }
245
+ });
246
+ connection.addEventListener("error", () => this.dispatchEvent(new Event("e")));
247
+ connection.addEventListener("close", () => {
248
+ if (!this.closed) {
249
+ setTimeout(() => this.connect(), this.interval);
250
+ }
251
+ });
252
+ connection.addEventListener("heartbeat", () => {
253
+ clearTimeout(timeout);
254
+ timeout = setTimeout(() => {
255
+ connection.close();
256
+ connection.dispatchEvent(new Event("timeout"));
257
+ }, this.timeout);
258
+ });
259
+ connection.addEventListener("close", () => {
260
+ clearTimeout(timeout);
261
+ });
262
+ }
263
+ get online() {
264
+ return this.connection.online;
265
+ }
266
+ get roomid() {
267
+ return this.connection.roomid;
268
+ }
269
+ close() {
270
+ this.closed = true;
271
+ this.connection.close();
272
+ }
273
+ heartbeat() {
274
+ return this.connection.heartbeat();
275
+ }
276
+ getOnline() {
277
+ return this.connection.getOnline();
278
+ }
279
+ send(data) {
280
+ return this.connection.send(data);
281
+ }
282
+ };
283
+
284
+ // src/inflate/node.ts
285
+ import { promisify } from "util";
286
+ import { brotliDecompress, inflate } from "zlib";
287
+ var _inflate = promisify(inflate);
288
+ var _brotli = promisify(brotliDecompress);
289
+ var inflateAsync = (b) => _inflate(b);
290
+ var brotliDecompressAsync = (b) => _brotli(b);
291
+ var inflates = { inflateAsync, brotliDecompressAsync };
292
+
293
+ // src/tcp.ts
294
+ import net from "net";
295
+ var LiveTCPBase = class extends Live {
296
+ socket;
297
+ buf;
298
+ i;
299
+ constructor(inflates2, roomid, { host = "broadcastlv.chat.bilibili.com", port = 2243, ...options } = {}) {
300
+ const socket = net.connect(port, host);
301
+ const send = (data) => {
302
+ socket.write(data);
303
+ };
304
+ const close = () => this.socket.end();
305
+ super(inflates2, roomid, { send, close, ...options });
306
+ this.i = 0;
307
+ this.buf = Buffer.alloc(0);
308
+ socket.on("ready", () => this.dispatchEvent(new Event("open")));
309
+ socket.on("close", () => this.dispatchEvent(new Event("close")));
310
+ socket.on("error", () => this.dispatchEvent(new Event("_error")));
311
+ socket.on("data", (buffer) => {
312
+ this.buf = Buffer.concat([this.buf, buffer]);
313
+ this.splitBuffer();
314
+ });
315
+ this.socket = socket;
316
+ }
317
+ splitBuffer() {
318
+ while (this.buf.length >= 4 && this.buf.readInt32BE(0) <= this.buf.length) {
319
+ const size = this.buf.readInt32BE(0);
320
+ const pack = this.buf.slice(0, size);
321
+ this.buf = this.buf.slice(size);
322
+ this.i++;
323
+ if (this.i > 5) {
324
+ this.i = 0;
325
+ this.buf = Buffer.from(this.buf);
326
+ }
327
+ this.dispatchEvent(new DataEvent("message", pack));
328
+ }
329
+ }
330
+ };
331
+
332
+ // src/ws-node.ts
333
+ import WS from "ws";
334
+ var LiveWSBase = class extends Live {
335
+ ws;
336
+ constructor(inflates2, roomid, { address = "wss://broadcastlv.chat.bilibili.com/sub", agent, ...options } = {}) {
337
+ const ws = new WS(address, { agent });
338
+ const send = (data) => {
339
+ if (ws.readyState === 1) {
340
+ ws.send(data);
341
+ }
342
+ };
343
+ const close = () => this.ws.close();
344
+ super(inflates2, roomid, { send, close, ...options });
345
+ ws.on("open", () => this.dispatchEvent(new Event("open")));
346
+ ws.on("message", (data) => this.dispatchEvent(new DataEvent("message", data)));
347
+ ws.on("close", () => this.dispatchEvent(new Event("close")));
348
+ ws.on("error", () => this.dispatchEvent(new Event("_error")));
349
+ this.ws = ws;
350
+ }
351
+ };
352
+
353
+ // src/extra.ts
354
+ var getConf = async (roomid) => {
355
+ const raw = await fetch(`https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=${roomid}`).then((w) => w.json());
356
+ const { data: { token: key, host_list: [{ host }] } } = raw;
357
+ const address = `wss://${host}/sub`;
358
+ return { key, host, address, raw };
359
+ };
360
+ var getRoomid = async (short) => {
361
+ const { data: { room_id } } = await fetch(`https://api.live.bilibili.com/room/v1/Room/mobileRoomInit?id=${short}`).then((w) => w.json());
362
+ return room_id;
363
+ };
364
+
365
+ // src/index.ts
366
+ var LiveWS = class extends LiveWSBase {
367
+ constructor(roomid, opts) {
368
+ super(inflates, roomid, opts);
369
+ }
370
+ };
371
+ var LiveTCP = class extends LiveTCPBase {
372
+ constructor(roomid, opts) {
373
+ super(inflates, roomid, opts);
374
+ }
375
+ };
376
+ var KeepLiveWS = class extends KeepLive {
377
+ constructor(roomid, opts) {
378
+ super(LiveWSBase, inflates, roomid, opts);
379
+ }
380
+ };
381
+ var KeepLiveTCP = class extends KeepLive {
382
+ constructor(roomid, opts) {
383
+ super(LiveTCPBase, inflates, roomid, opts);
384
+ }
385
+ };
386
+ export {
387
+ DataEvent,
388
+ EventEvent,
389
+ KeepLiveTCP,
390
+ KeepLiveWS,
391
+ LiveTCP,
392
+ LiveWS,
393
+ getConf,
394
+ getRoomid
395
+ };
package/package.json CHANGED
@@ -1,22 +1,41 @@
1
1
  {
2
2
  "name": "@laplace.live/ws",
3
- "version": "6.3.4",
3
+ "version": "6.3.6",
4
4
  "description": "Bilibili Live WebSocket/TCP API",
5
5
  "type": "module",
6
- "main": "./src/index.ts",
7
- "browser": "./src/browser.ts",
6
+ "main": "./dist/index.js",
7
+ "browser": "./dist/browser.js",
8
+ "types": "./dist/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
- "browser": "./src/browser.ts",
11
- "default": "./src/index.ts"
11
+ "browser": {
12
+ "types": "./dist/browser.d.ts",
13
+ "default": "./dist/browser.js"
14
+ },
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
12
17
  },
13
- "./server": "./src/index.ts",
14
- "./client": "./src/browser.ts",
15
- "./browser": "./src/browser.ts"
18
+ "./server": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./client": {
23
+ "types": "./dist/browser.d.ts",
24
+ "default": "./dist/browser.js"
25
+ },
26
+ "./browser": {
27
+ "types": "./dist/browser.d.ts",
28
+ "default": "./dist/browser.js"
29
+ }
16
30
  },
31
+ "files": [
32
+ "dist"
33
+ ],
17
34
  "scripts": {
35
+ "build": "tsup",
18
36
  "check": "tsc --noEmit",
19
- "test": "bun test --timeout 5000"
37
+ "test": "bun test --timeout 5000",
38
+ "prepublishOnly": "bun run build"
20
39
  },
21
40
  "repository": {
22
41
  "type": "git",
@@ -41,8 +60,6 @@
41
60
  "provenance": true
42
61
  },
43
62
  "dependencies": {
44
- "buffer": "^6.0.3",
45
- "events": "^3.3.0",
46
63
  "pako": "^2.1.0",
47
64
  "ws": "^8.19.0"
48
65
  },
@@ -51,6 +68,7 @@
51
68
  "@types/bun": "^1.3.10",
52
69
  "@types/pako": "^2.0.4",
53
70
  "@types/ws": "^8.18.1",
71
+ "tsup": "^8.5.1",
54
72
  "typescript": "^5.9.3"
55
73
  }
56
74
  }
package/src/browser.ts DELETED
@@ -1,20 +0,0 @@
1
- import { KeepLive } from './common.ts'
2
- import { inflates } from './inflate/browser.ts'
3
- import { LiveWSBase, type WSOptions } from './ws-client.ts'
4
-
5
- export type { LiveOptions } from './common.ts'
6
- export type { WSOptions } from './ws-client.ts'
7
-
8
- export { relayEvent } from './common.ts'
9
-
10
- export class LiveWS extends LiveWSBase {
11
- constructor(roomid: number, opts?: WSOptions) {
12
- super(inflates, roomid, opts)
13
- }
14
- }
15
-
16
- export class KeepLiveWS extends KeepLive<typeof LiveWSBase> {
17
- constructor(roomid: number, opts?: WSOptions) {
18
- super(LiveWSBase, inflates, roomid, opts)
19
- }
20
- }
package/src/buffer.ts DELETED
@@ -1,82 +0,0 @@
1
- export type { Buffer } from 'buffer'
2
- export type Inflates = { inflateAsync: (b: Buffer) => Buffer | Promise<Buffer>, brotliDecompressAsync: (b: Buffer) => Buffer | Promise<Buffer>, Buffer: typeof Buffer }
3
-
4
- // https://github.com/lovelyyoshino/Bilibili-Live-API/blob/master/API.WebSocket.md
5
-
6
- const cutBuffer = (buffer: Buffer) => {
7
- const bufferPacks: Buffer[] = []
8
- let size: number
9
- for (let i = 0; i < buffer.length; i += size) {
10
- size = buffer.readInt32BE(i)
11
- bufferPacks.push(buffer.slice(i, i + size))
12
- }
13
- return bufferPacks
14
- }
15
-
16
- export const makeDecoder = ({ inflateAsync, brotliDecompressAsync }: Inflates) => {
17
- const decoder = async (buffer: Buffer) => {
18
- const packs = await Promise.all(cutBuffer(buffer)
19
- .map(async buf => {
20
- const body = buf.slice(16)
21
- const protocol = buf.readInt16BE(6)
22
- const operation = buf.readInt32BE(8)
23
-
24
- let type = 'unknow'
25
- if (operation === 3) {
26
- type = 'heartbeat'
27
- } else if (operation === 5) {
28
- type = 'message'
29
- } else if (operation === 8) {
30
- type = 'welcome'
31
- }
32
-
33
- let data: any
34
- if (protocol === 0) {
35
- data = JSON.parse(String(body))
36
- }
37
- if (protocol === 1 && body.length === 4) {
38
- data = body.readUIntBE(0, 4)
39
- }
40
- if (protocol === 2) {
41
- data = await decoder(await inflateAsync(body))
42
- }
43
- if (protocol === 3) {
44
- data = await decoder(await brotliDecompressAsync(body))
45
- }
46
-
47
- return { buf, type, protocol, data }
48
- }))
49
-
50
- return packs.flatMap(pack => {
51
- if (pack.protocol === 2 || pack.protocol === 3) {
52
- return pack.data as typeof packs
53
- }
54
- return pack
55
- })
56
- }
57
-
58
- return decoder
59
- }
60
-
61
- type EncodeType = 'heartbeat' | 'join'
62
-
63
- export const encoder = (type: EncodeType, { Buffer }: Inflates, body: any = '') => {
64
- const blank = Buffer.alloc(16)
65
- if (typeof body !== 'string') {
66
- body = JSON.stringify(body)
67
- }
68
- const head = Buffer.from(blank)
69
- const buffer = Buffer.from(body)
70
-
71
- head.writeInt32BE(buffer.length + head.length, 0)
72
- head.writeInt16BE(16, 4)
73
- head.writeInt16BE(1, 6)
74
- if (type === 'heartbeat') {
75
- head.writeInt32BE(2, 8)
76
- }
77
- if (type === 'join') {
78
- head.writeInt32BE(7, 8)
79
- }
80
- head.writeInt32BE(1, 12)
81
- return Buffer.concat([head, buffer])
82
- }