@aka_openclaw_plugin/mychat 0.1.17 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4550 +0,0 @@
1
- import { c as __toCommonJS, i as setMychatRuntime, l as __toESM, n as init_runtime, o as __commonJSMin, r as runtime_exports, s as __require, t as getMychatRuntime } from "./runtime-PfFuZ2Rm.js";
2
- import { t as mychatConfigSchema } from "./config-schema-C42X7OSY.js";
3
- import { createChannelPluginBase, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
4
- import { createAccountStatusSink } from "openclaw/plugin-sdk/channel-lifecycle";
5
- import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/channel-plugin-common";
6
- //#region src/accounts.ts
7
- const DEFAULT_DM_POLICY = "open";
8
- const DEFAULT_GROUP_POLICY = "open";
9
- const DEFAULT_HISTORY_LIMIT = 50;
10
- const DEFAULT_MEDIA_MAX_MB = 10;
11
- function resolveWsUrl(baseUrl) {
12
- const url = new URL(baseUrl);
13
- url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
14
- url.pathname = url.pathname.replace(/\/+$/, "") + "/ws/bot";
15
- return url.toString();
16
- }
17
- function mergeAccountConfig(channel, account) {
18
- if (!account) return channel;
19
- return {
20
- ...channel,
21
- ...account,
22
- actions: {
23
- messages: account.actions?.messages ?? channel.actions?.messages ?? true,
24
- threads: account.actions?.threads ?? channel.actions?.threads ?? true,
25
- reactions: account.actions?.reactions ?? channel.actions?.reactions ?? true
26
- },
27
- groups: {
28
- ...channel.groups ?? {},
29
- ...account.groups ?? {}
30
- },
31
- reconnect: account.reconnect ?? channel.reconnect
32
- };
33
- }
34
- function resolveMychatAccounts(cfg) {
35
- const mychatConfig = cfg.channels?.mychat;
36
- if (!mychatConfig) return [];
37
- const accounts = mychatConfig.accounts ?? {};
38
- const accountIds = Object.keys(accounts);
39
- if (accountIds.length === 0) {
40
- const resolved = resolveSingleAccount({
41
- accountId: DEFAULT_ACCOUNT_ID,
42
- config: mychatConfig
43
- });
44
- return resolved ? [resolved] : [];
45
- }
46
- return accountIds.map((id) => {
47
- return resolveSingleAccount({
48
- accountId: id,
49
- config: mergeAccountConfig(mychatConfig, accounts[id])
50
- });
51
- }).filter(Boolean);
52
- }
53
- function resolveSingleAccount(params) {
54
- const { accountId, config } = params;
55
- const enabled = config.enabled ?? true;
56
- if (!enabled) return null;
57
- const token = resolveToken(config);
58
- if (!token) return null;
59
- const baseUrl = config.baseUrl.replace(/\/+$/, "");
60
- const wsUrl = config.wsUrl ?? resolveWsUrl(baseUrl);
61
- return {
62
- accountId: normalizeAccountId(accountId),
63
- enabled,
64
- name: config.name,
65
- baseUrl,
66
- wsUrl,
67
- token,
68
- defaultTo: config.defaultTo,
69
- dmPolicy: config.dmPolicy ?? DEFAULT_DM_POLICY,
70
- groupPolicy: config.groupPolicy ?? DEFAULT_GROUP_POLICY,
71
- allowFrom: config.allowFrom ?? [],
72
- groupAllowFrom: config.groupAllowFrom ?? [],
73
- requireMention: config.requireMention ?? false,
74
- historyLimit: config.historyLimit ?? DEFAULT_HISTORY_LIMIT,
75
- mediaMaxMb: config.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB,
76
- actions: {
77
- messages: config.actions?.messages ?? true,
78
- threads: config.actions?.threads ?? true,
79
- reactions: config.actions?.reactions ?? true
80
- },
81
- groups: config.groups ?? {},
82
- reconnect: config.reconnect ?? {}
83
- };
84
- }
85
- function resolveToken(config) {
86
- if (config.token) return config.token;
87
- if (typeof process !== "undefined") {
88
- const envToken = process.env.MYCHAT_BOT_TOKEN;
89
- if (envToken) return envToken;
90
- }
91
- return null;
92
- }
93
- function resolveMychatAccount(params) {
94
- const accounts = resolveMychatAccounts(params.cfg);
95
- if (accounts.length === 0) return null;
96
- if (!params.accountId) return accounts[0];
97
- return accounts.find((a) => a.accountId === params.accountId) ?? accounts[0] ?? null;
98
- }
99
- //#endregion
100
- //#region src/logger.ts
101
- const PREFIX = "mychat";
102
- function mychatLogPrefix(feature) {
103
- return `[${PREFIX}:${feature}]`;
104
- }
105
- function getMychatLogger() {
106
- try {
107
- const logger = ((init_runtime(), __toCommonJS(runtime_exports)).tryGetMychatRuntime?.())?.logger;
108
- if (!logger) return null;
109
- return {
110
- debug: (m) => logger.debug?.(m),
111
- info: (m) => logger.info(m),
112
- warn: (m) => logger.warn(m),
113
- error: (m) => logger.error(m)
114
- };
115
- } catch {
116
- return null;
117
- }
118
- }
119
- //#endregion
120
- //#region src/client/http-client.ts
121
- function createMychatHttpClient(params) {
122
- const { baseUrl, token, logger } = params;
123
- const base = baseUrl.replace(/\/+$/, "");
124
- const prefix = mychatLogPrefix("http");
125
- async function request(method, path, body) {
126
- const url = `${base}${path}`;
127
- try {
128
- const headers = { authorization: `Bearer ${token}` };
129
- if (body !== void 0) headers["content-type"] = "application/json";
130
- const response = await fetch(url, {
131
- method,
132
- headers,
133
- body: body !== void 0 ? JSON.stringify(body) : void 0
134
- });
135
- if (!response.ok) {
136
- let errorBody = "";
137
- try {
138
- errorBody = await response.text();
139
- } catch {}
140
- const msg = `${prefix} ${method} ${url} failed: ${response.status} ${response.statusText}${errorBody ? ` body=${errorBody.slice(0, 200)}` : ""}`;
141
- logger?.error(msg);
142
- return null;
143
- }
144
- return await response.json();
145
- } catch (err) {
146
- const errMsg = err instanceof Error ? `${err.message}` : String(err);
147
- logger?.error(`${prefix} ${method} ${url} error: ${errMsg}`);
148
- return null;
149
- }
150
- }
151
- return {
152
- async getSelf() {
153
- return request("GET", "/api/bot/self");
154
- },
155
- async getMe() {
156
- return request("GET", "/api/auth/me");
157
- },
158
- async sendMessage(body) {
159
- return request("POST", "/api/bot/messages", body);
160
- },
161
- async listMessages(params) {
162
- const searchParams = new URLSearchParams();
163
- if (params.conversationId) searchParams.set("conversationId", params.conversationId);
164
- if (params.limit) searchParams.set("limit", String(params.limit));
165
- if (params.after) searchParams.set("after", String(params.after));
166
- const qs = searchParams.toString();
167
- return (await request("GET", `/api/bot/messages${qs ? `?${qs}` : ""}`))?.messages ?? [];
168
- },
169
- async listConversations() {
170
- return (await request("GET", "/api/bot/conversations"))?.conversations?.map((c) => c.id) ?? [];
171
- },
172
- async addReaction(messageId, body) {
173
- return request("POST", `/api/bot/messages/${messageId}/reactions`, body);
174
- },
175
- async removeReaction(messageId, emoji) {
176
- return request("POST", `/api/bot/messages/${messageId}/reactions`, {
177
- emoji,
178
- action: "remove"
179
- });
180
- },
181
- async uploadFile(params) {
182
- const url = `${base}/api/bot/uploads`;
183
- try {
184
- const formData = new FormData();
185
- let blob;
186
- if (params.file instanceof Blob) blob = params.file;
187
- else {
188
- const bytes = new Uint8Array(params.file.buffer, params.file.byteOffset, params.file.byteLength);
189
- blob = new Blob([bytes], { type: params.mimeType });
190
- }
191
- formData.append("file", blob, params.filename);
192
- if (params.scopeKind) formData.append("scopeKind", params.scopeKind);
193
- if (params.scopeId) formData.append("scopeId", params.scopeId);
194
- const response = await fetch(url, {
195
- method: "POST",
196
- headers: { authorization: `Bearer ${token}` },
197
- body: formData
198
- });
199
- if (!response.ok) {
200
- let errorBody = "";
201
- try {
202
- errorBody = await response.text();
203
- } catch {}
204
- logger?.error(`${prefix} POST ${url} failed: ${response.status} ${response.statusText}${errorBody ? ` body=${errorBody.slice(0, 200)}` : ""}`);
205
- return null;
206
- }
207
- return await response.json();
208
- } catch (err) {
209
- const errMsg = err instanceof Error ? `${err.message}` : String(err);
210
- logger?.error(`${prefix} POST ${url} error: ${errMsg}`);
211
- return null;
212
- }
213
- },
214
- async healthCheck() {
215
- const url = `${base}/health`;
216
- const start = Date.now();
217
- try {
218
- const response = await fetch(url);
219
- const latencyMs = Date.now() - start;
220
- if (!response.ok) logger?.error(`${prefix} health check failed: ${url} status=${response.status} latencyMs=${latencyMs}`);
221
- return {
222
- ok: response.ok,
223
- latencyMs
224
- };
225
- } catch (err) {
226
- const errMsg = err instanceof Error ? `${err.message}` : String(err);
227
- logger?.error(`${prefix} health check error: ${url} error=${errMsg} latencyMs=${Date.now() - start}`);
228
- return {
229
- ok: false,
230
- latencyMs: Date.now() - start
231
- };
232
- }
233
- }
234
- };
235
- }
236
- //#endregion
237
- //#region ../../node_modules/ws/lib/constants.js
238
- var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
239
- const BINARY_TYPES = [
240
- "nodebuffer",
241
- "arraybuffer",
242
- "fragments"
243
- ];
244
- const hasBlob = typeof Blob !== "undefined";
245
- if (hasBlob) BINARY_TYPES.push("blob");
246
- module.exports = {
247
- BINARY_TYPES,
248
- CLOSE_TIMEOUT: 3e4,
249
- EMPTY_BUFFER: Buffer.alloc(0),
250
- GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
251
- hasBlob,
252
- kForOnEventAttribute: Symbol("kIsForOnEventAttribute"),
253
- kListener: Symbol("kListener"),
254
- kStatusCode: Symbol("status-code"),
255
- kWebSocket: Symbol("websocket"),
256
- NOOP: () => {}
257
- };
258
- }));
259
- //#endregion
260
- //#region ../../node_modules/ws/lib/buffer-util.js
261
- var require_buffer_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
262
- const { EMPTY_BUFFER } = require_constants();
263
- const FastBuffer = Buffer[Symbol.species];
264
- /**
265
- * Merges an array of buffers into a new buffer.
266
- *
267
- * @param {Buffer[]} list The array of buffers to concat
268
- * @param {Number} totalLength The total length of buffers in the list
269
- * @return {Buffer} The resulting buffer
270
- * @public
271
- */
272
- function concat(list, totalLength) {
273
- if (list.length === 0) return EMPTY_BUFFER;
274
- if (list.length === 1) return list[0];
275
- const target = Buffer.allocUnsafe(totalLength);
276
- let offset = 0;
277
- for (let i = 0; i < list.length; i++) {
278
- const buf = list[i];
279
- target.set(buf, offset);
280
- offset += buf.length;
281
- }
282
- if (offset < totalLength) return new FastBuffer(target.buffer, target.byteOffset, offset);
283
- return target;
284
- }
285
- /**
286
- * Masks a buffer using the given mask.
287
- *
288
- * @param {Buffer} source The buffer to mask
289
- * @param {Buffer} mask The mask to use
290
- * @param {Buffer} output The buffer where to store the result
291
- * @param {Number} offset The offset at which to start writing
292
- * @param {Number} length The number of bytes to mask.
293
- * @public
294
- */
295
- function _mask(source, mask, output, offset, length) {
296
- for (let i = 0; i < length; i++) output[offset + i] = source[i] ^ mask[i & 3];
297
- }
298
- /**
299
- * Unmasks a buffer using the given mask.
300
- *
301
- * @param {Buffer} buffer The buffer to unmask
302
- * @param {Buffer} mask The mask to use
303
- * @public
304
- */
305
- function _unmask(buffer, mask) {
306
- for (let i = 0; i < buffer.length; i++) buffer[i] ^= mask[i & 3];
307
- }
308
- /**
309
- * Converts a buffer to an `ArrayBuffer`.
310
- *
311
- * @param {Buffer} buf The buffer to convert
312
- * @return {ArrayBuffer} Converted buffer
313
- * @public
314
- */
315
- function toArrayBuffer(buf) {
316
- if (buf.length === buf.buffer.byteLength) return buf.buffer;
317
- return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
318
- }
319
- /**
320
- * Converts `data` to a `Buffer`.
321
- *
322
- * @param {*} data The data to convert
323
- * @return {Buffer} The buffer
324
- * @throws {TypeError}
325
- * @public
326
- */
327
- function toBuffer(data) {
328
- toBuffer.readOnly = true;
329
- if (Buffer.isBuffer(data)) return data;
330
- let buf;
331
- if (data instanceof ArrayBuffer) buf = new FastBuffer(data);
332
- else if (ArrayBuffer.isView(data)) buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);
333
- else {
334
- buf = Buffer.from(data);
335
- toBuffer.readOnly = false;
336
- }
337
- return buf;
338
- }
339
- module.exports = {
340
- concat,
341
- mask: _mask,
342
- toArrayBuffer,
343
- toBuffer,
344
- unmask: _unmask
345
- };
346
- /* istanbul ignore else */
347
- if (!process.env.WS_NO_BUFFER_UTIL) try {
348
- const bufferUtil = __require("bufferutil");
349
- module.exports.mask = function(source, mask, output, offset, length) {
350
- if (length < 48) _mask(source, mask, output, offset, length);
351
- else bufferUtil.mask(source, mask, output, offset, length);
352
- };
353
- module.exports.unmask = function(buffer, mask) {
354
- if (buffer.length < 32) _unmask(buffer, mask);
355
- else bufferUtil.unmask(buffer, mask);
356
- };
357
- } catch (e) {}
358
- }));
359
- //#endregion
360
- //#region ../../node_modules/ws/lib/limiter.js
361
- var require_limiter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
362
- const kDone = Symbol("kDone");
363
- const kRun = Symbol("kRun");
364
- /**
365
- * A very simple job queue with adjustable concurrency. Adapted from
366
- * https://github.com/STRML/async-limiter
367
- */
368
- var Limiter = class {
369
- /**
370
- * Creates a new `Limiter`.
371
- *
372
- * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
373
- * to run concurrently
374
- */
375
- constructor(concurrency) {
376
- this[kDone] = () => {
377
- this.pending--;
378
- this[kRun]();
379
- };
380
- this.concurrency = concurrency || Infinity;
381
- this.jobs = [];
382
- this.pending = 0;
383
- }
384
- /**
385
- * Adds a job to the queue.
386
- *
387
- * @param {Function} job The job to run
388
- * @public
389
- */
390
- add(job) {
391
- this.jobs.push(job);
392
- this[kRun]();
393
- }
394
- /**
395
- * Removes a job from the queue and runs it if possible.
396
- *
397
- * @private
398
- */
399
- [kRun]() {
400
- if (this.pending === this.concurrency) return;
401
- if (this.jobs.length) {
402
- const job = this.jobs.shift();
403
- this.pending++;
404
- job(this[kDone]);
405
- }
406
- }
407
- };
408
- module.exports = Limiter;
409
- }));
410
- //#endregion
411
- //#region ../../node_modules/ws/lib/permessage-deflate.js
412
- var require_permessage_deflate = /* @__PURE__ */ __commonJSMin(((exports, module) => {
413
- const zlib = __require("zlib");
414
- const bufferUtil = require_buffer_util();
415
- const Limiter = require_limiter();
416
- const { kStatusCode } = require_constants();
417
- const FastBuffer = Buffer[Symbol.species];
418
- const TRAILER = Buffer.from([
419
- 0,
420
- 0,
421
- 255,
422
- 255
423
- ]);
424
- const kPerMessageDeflate = Symbol("permessage-deflate");
425
- const kTotalLength = Symbol("total-length");
426
- const kCallback = Symbol("callback");
427
- const kBuffers = Symbol("buffers");
428
- const kError = Symbol("error");
429
- let zlibLimiter;
430
- /**
431
- * permessage-deflate implementation.
432
- */
433
- var PerMessageDeflate = class {
434
- /**
435
- * Creates a PerMessageDeflate instance.
436
- *
437
- * @param {Object} [options] Configuration options
438
- * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
439
- * for, or request, a custom client window size
440
- * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
441
- * acknowledge disabling of client context takeover
442
- * @param {Number} [options.concurrencyLimit=10] The number of concurrent
443
- * calls to zlib
444
- * @param {Boolean} [options.isServer=false] Create the instance in either
445
- * server or client mode
446
- * @param {Number} [options.maxPayload=0] The maximum allowed message length
447
- * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
448
- * use of a custom server window size
449
- * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
450
- * disabling of server context takeover
451
- * @param {Number} [options.threshold=1024] Size (in bytes) below which
452
- * messages should not be compressed if context takeover is disabled
453
- * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
454
- * deflate
455
- * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
456
- * inflate
457
- */
458
- constructor(options) {
459
- this._options = options || {};
460
- this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024;
461
- this._maxPayload = this._options.maxPayload | 0;
462
- this._isServer = !!this._options.isServer;
463
- this._deflate = null;
464
- this._inflate = null;
465
- this.params = null;
466
- if (!zlibLimiter) zlibLimiter = new Limiter(this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10);
467
- }
468
- /**
469
- * @type {String}
470
- */
471
- static get extensionName() {
472
- return "permessage-deflate";
473
- }
474
- /**
475
- * Create an extension negotiation offer.
476
- *
477
- * @return {Object} Extension parameters
478
- * @public
479
- */
480
- offer() {
481
- const params = {};
482
- if (this._options.serverNoContextTakeover) params.server_no_context_takeover = true;
483
- if (this._options.clientNoContextTakeover) params.client_no_context_takeover = true;
484
- if (this._options.serverMaxWindowBits) params.server_max_window_bits = this._options.serverMaxWindowBits;
485
- if (this._options.clientMaxWindowBits) params.client_max_window_bits = this._options.clientMaxWindowBits;
486
- else if (this._options.clientMaxWindowBits == null) params.client_max_window_bits = true;
487
- return params;
488
- }
489
- /**
490
- * Accept an extension negotiation offer/response.
491
- *
492
- * @param {Array} configurations The extension negotiation offers/reponse
493
- * @return {Object} Accepted configuration
494
- * @public
495
- */
496
- accept(configurations) {
497
- configurations = this.normalizeParams(configurations);
498
- this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations);
499
- return this.params;
500
- }
501
- /**
502
- * Releases all resources used by the extension.
503
- *
504
- * @public
505
- */
506
- cleanup() {
507
- if (this._inflate) {
508
- this._inflate.close();
509
- this._inflate = null;
510
- }
511
- if (this._deflate) {
512
- const callback = this._deflate[kCallback];
513
- this._deflate.close();
514
- this._deflate = null;
515
- if (callback) callback(/* @__PURE__ */ new Error("The deflate stream was closed while data was being processed"));
516
- }
517
- }
518
- /**
519
- * Accept an extension negotiation offer.
520
- *
521
- * @param {Array} offers The extension negotiation offers
522
- * @return {Object} Accepted configuration
523
- * @private
524
- */
525
- acceptAsServer(offers) {
526
- const opts = this._options;
527
- const accepted = offers.find((params) => {
528
- if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) return false;
529
- return true;
530
- });
531
- if (!accepted) throw new Error("None of the extension offers can be accepted");
532
- if (opts.serverNoContextTakeover) accepted.server_no_context_takeover = true;
533
- if (opts.clientNoContextTakeover) accepted.client_no_context_takeover = true;
534
- if (typeof opts.serverMaxWindowBits === "number") accepted.server_max_window_bits = opts.serverMaxWindowBits;
535
- if (typeof opts.clientMaxWindowBits === "number") accepted.client_max_window_bits = opts.clientMaxWindowBits;
536
- else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) delete accepted.client_max_window_bits;
537
- return accepted;
538
- }
539
- /**
540
- * Accept the extension negotiation response.
541
- *
542
- * @param {Array} response The extension negotiation response
543
- * @return {Object} Accepted configuration
544
- * @private
545
- */
546
- acceptAsClient(response) {
547
- const params = response[0];
548
- if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) throw new Error("Unexpected parameter \"client_no_context_takeover\"");
549
- if (!params.client_max_window_bits) {
550
- if (typeof this._options.clientMaxWindowBits === "number") params.client_max_window_bits = this._options.clientMaxWindowBits;
551
- } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) throw new Error("Unexpected or invalid parameter \"client_max_window_bits\"");
552
- return params;
553
- }
554
- /**
555
- * Normalize parameters.
556
- *
557
- * @param {Array} configurations The extension negotiation offers/reponse
558
- * @return {Array} The offers/response with normalized parameters
559
- * @private
560
- */
561
- normalizeParams(configurations) {
562
- configurations.forEach((params) => {
563
- Object.keys(params).forEach((key) => {
564
- let value = params[key];
565
- if (value.length > 1) throw new Error(`Parameter "${key}" must have only a single value`);
566
- value = value[0];
567
- if (key === "client_max_window_bits") {
568
- if (value !== true) {
569
- const num = +value;
570
- if (!Number.isInteger(num) || num < 8 || num > 15) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
571
- value = num;
572
- } else if (!this._isServer) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
573
- } else if (key === "server_max_window_bits") {
574
- const num = +value;
575
- if (!Number.isInteger(num) || num < 8 || num > 15) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
576
- value = num;
577
- } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") {
578
- if (value !== true) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
579
- } else throw new Error(`Unknown parameter "${key}"`);
580
- params[key] = value;
581
- });
582
- });
583
- return configurations;
584
- }
585
- /**
586
- * Decompress data. Concurrency limited.
587
- *
588
- * @param {Buffer} data Compressed data
589
- * @param {Boolean} fin Specifies whether or not this is the last fragment
590
- * @param {Function} callback Callback
591
- * @public
592
- */
593
- decompress(data, fin, callback) {
594
- zlibLimiter.add((done) => {
595
- this._decompress(data, fin, (err, result) => {
596
- done();
597
- callback(err, result);
598
- });
599
- });
600
- }
601
- /**
602
- * Compress data. Concurrency limited.
603
- *
604
- * @param {(Buffer|String)} data Data to compress
605
- * @param {Boolean} fin Specifies whether or not this is the last fragment
606
- * @param {Function} callback Callback
607
- * @public
608
- */
609
- compress(data, fin, callback) {
610
- zlibLimiter.add((done) => {
611
- this._compress(data, fin, (err, result) => {
612
- done();
613
- callback(err, result);
614
- });
615
- });
616
- }
617
- /**
618
- * Decompress data.
619
- *
620
- * @param {Buffer} data Compressed data
621
- * @param {Boolean} fin Specifies whether or not this is the last fragment
622
- * @param {Function} callback Callback
623
- * @private
624
- */
625
- _decompress(data, fin, callback) {
626
- const endpoint = this._isServer ? "client" : "server";
627
- if (!this._inflate) {
628
- const key = `${endpoint}_max_window_bits`;
629
- const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key];
630
- this._inflate = zlib.createInflateRaw({
631
- ...this._options.zlibInflateOptions,
632
- windowBits
633
- });
634
- this._inflate[kPerMessageDeflate] = this;
635
- this._inflate[kTotalLength] = 0;
636
- this._inflate[kBuffers] = [];
637
- this._inflate.on("error", inflateOnError);
638
- this._inflate.on("data", inflateOnData);
639
- }
640
- this._inflate[kCallback] = callback;
641
- this._inflate.write(data);
642
- if (fin) this._inflate.write(TRAILER);
643
- this._inflate.flush(() => {
644
- const err = this._inflate[kError];
645
- if (err) {
646
- this._inflate.close();
647
- this._inflate = null;
648
- callback(err);
649
- return;
650
- }
651
- const data = bufferUtil.concat(this._inflate[kBuffers], this._inflate[kTotalLength]);
652
- if (this._inflate._readableState.endEmitted) {
653
- this._inflate.close();
654
- this._inflate = null;
655
- } else {
656
- this._inflate[kTotalLength] = 0;
657
- this._inflate[kBuffers] = [];
658
- if (fin && this.params[`${endpoint}_no_context_takeover`]) this._inflate.reset();
659
- }
660
- callback(null, data);
661
- });
662
- }
663
- /**
664
- * Compress data.
665
- *
666
- * @param {(Buffer|String)} data Data to compress
667
- * @param {Boolean} fin Specifies whether or not this is the last fragment
668
- * @param {Function} callback Callback
669
- * @private
670
- */
671
- _compress(data, fin, callback) {
672
- const endpoint = this._isServer ? "server" : "client";
673
- if (!this._deflate) {
674
- const key = `${endpoint}_max_window_bits`;
675
- const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key];
676
- this._deflate = zlib.createDeflateRaw({
677
- ...this._options.zlibDeflateOptions,
678
- windowBits
679
- });
680
- this._deflate[kTotalLength] = 0;
681
- this._deflate[kBuffers] = [];
682
- this._deflate.on("data", deflateOnData);
683
- }
684
- this._deflate[kCallback] = callback;
685
- this._deflate.write(data);
686
- this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
687
- if (!this._deflate) return;
688
- let data = bufferUtil.concat(this._deflate[kBuffers], this._deflate[kTotalLength]);
689
- if (fin) data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
690
- this._deflate[kCallback] = null;
691
- this._deflate[kTotalLength] = 0;
692
- this._deflate[kBuffers] = [];
693
- if (fin && this.params[`${endpoint}_no_context_takeover`]) this._deflate.reset();
694
- callback(null, data);
695
- });
696
- }
697
- };
698
- module.exports = PerMessageDeflate;
699
- /**
700
- * The listener of the `zlib.DeflateRaw` stream `'data'` event.
701
- *
702
- * @param {Buffer} chunk A chunk of data
703
- * @private
704
- */
705
- function deflateOnData(chunk) {
706
- this[kBuffers].push(chunk);
707
- this[kTotalLength] += chunk.length;
708
- }
709
- /**
710
- * The listener of the `zlib.InflateRaw` stream `'data'` event.
711
- *
712
- * @param {Buffer} chunk A chunk of data
713
- * @private
714
- */
715
- function inflateOnData(chunk) {
716
- this[kTotalLength] += chunk.length;
717
- if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) {
718
- this[kBuffers].push(chunk);
719
- return;
720
- }
721
- this[kError] = /* @__PURE__ */ new RangeError("Max payload size exceeded");
722
- this[kError].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH";
723
- this[kError][kStatusCode] = 1009;
724
- this.removeListener("data", inflateOnData);
725
- this.reset();
726
- }
727
- /**
728
- * The listener of the `zlib.InflateRaw` stream `'error'` event.
729
- *
730
- * @param {Error} err The emitted error
731
- * @private
732
- */
733
- function inflateOnError(err) {
734
- this[kPerMessageDeflate]._inflate = null;
735
- if (this[kError]) {
736
- this[kCallback](this[kError]);
737
- return;
738
- }
739
- err[kStatusCode] = 1007;
740
- this[kCallback](err);
741
- }
742
- }));
743
- //#endregion
744
- //#region ../../node_modules/ws/lib/validation.js
745
- var require_validation = /* @__PURE__ */ __commonJSMin(((exports, module) => {
746
- const { isUtf8 } = __require("buffer");
747
- const { hasBlob } = require_constants();
748
- const tokenChars = [
749
- 0,
750
- 0,
751
- 0,
752
- 0,
753
- 0,
754
- 0,
755
- 0,
756
- 0,
757
- 0,
758
- 0,
759
- 0,
760
- 0,
761
- 0,
762
- 0,
763
- 0,
764
- 0,
765
- 0,
766
- 0,
767
- 0,
768
- 0,
769
- 0,
770
- 0,
771
- 0,
772
- 0,
773
- 0,
774
- 0,
775
- 0,
776
- 0,
777
- 0,
778
- 0,
779
- 0,
780
- 0,
781
- 0,
782
- 1,
783
- 0,
784
- 1,
785
- 1,
786
- 1,
787
- 1,
788
- 1,
789
- 0,
790
- 0,
791
- 1,
792
- 1,
793
- 0,
794
- 1,
795
- 1,
796
- 0,
797
- 1,
798
- 1,
799
- 1,
800
- 1,
801
- 1,
802
- 1,
803
- 1,
804
- 1,
805
- 1,
806
- 1,
807
- 0,
808
- 0,
809
- 0,
810
- 0,
811
- 0,
812
- 0,
813
- 0,
814
- 1,
815
- 1,
816
- 1,
817
- 1,
818
- 1,
819
- 1,
820
- 1,
821
- 1,
822
- 1,
823
- 1,
824
- 1,
825
- 1,
826
- 1,
827
- 1,
828
- 1,
829
- 1,
830
- 1,
831
- 1,
832
- 1,
833
- 1,
834
- 1,
835
- 1,
836
- 1,
837
- 1,
838
- 1,
839
- 1,
840
- 0,
841
- 0,
842
- 0,
843
- 1,
844
- 1,
845
- 1,
846
- 1,
847
- 1,
848
- 1,
849
- 1,
850
- 1,
851
- 1,
852
- 1,
853
- 1,
854
- 1,
855
- 1,
856
- 1,
857
- 1,
858
- 1,
859
- 1,
860
- 1,
861
- 1,
862
- 1,
863
- 1,
864
- 1,
865
- 1,
866
- 1,
867
- 1,
868
- 1,
869
- 1,
870
- 1,
871
- 1,
872
- 0,
873
- 1,
874
- 0,
875
- 1,
876
- 0
877
- ];
878
- /**
879
- * Checks if a status code is allowed in a close frame.
880
- *
881
- * @param {Number} code The status code
882
- * @return {Boolean} `true` if the status code is valid, else `false`
883
- * @public
884
- */
885
- function isValidStatusCode(code) {
886
- return code >= 1e3 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006 || code >= 3e3 && code <= 4999;
887
- }
888
- /**
889
- * Checks if a given buffer contains only correct UTF-8.
890
- * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
891
- * Markus Kuhn.
892
- *
893
- * @param {Buffer} buf The buffer to check
894
- * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
895
- * @public
896
- */
897
- function _isValidUTF8(buf) {
898
- const len = buf.length;
899
- let i = 0;
900
- while (i < len) if ((buf[i] & 128) === 0) i++;
901
- else if ((buf[i] & 224) === 192) {
902
- if (i + 1 === len || (buf[i + 1] & 192) !== 128 || (buf[i] & 254) === 192) return false;
903
- i += 2;
904
- } else if ((buf[i] & 240) === 224) {
905
- if (i + 2 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || buf[i] === 224 && (buf[i + 1] & 224) === 128 || buf[i] === 237 && (buf[i + 1] & 224) === 160) return false;
906
- i += 3;
907
- } else if ((buf[i] & 248) === 240) {
908
- if (i + 3 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || (buf[i + 3] & 192) !== 128 || buf[i] === 240 && (buf[i + 1] & 240) === 128 || buf[i] === 244 && buf[i + 1] > 143 || buf[i] > 244) return false;
909
- i += 4;
910
- } else return false;
911
- return true;
912
- }
913
- /**
914
- * Determines whether a value is a `Blob`.
915
- *
916
- * @param {*} value The value to be tested
917
- * @return {Boolean} `true` if `value` is a `Blob`, else `false`
918
- * @private
919
- */
920
- function isBlob(value) {
921
- return hasBlob && typeof value === "object" && typeof value.arrayBuffer === "function" && typeof value.type === "string" && typeof value.stream === "function" && (value[Symbol.toStringTag] === "Blob" || value[Symbol.toStringTag] === "File");
922
- }
923
- module.exports = {
924
- isBlob,
925
- isValidStatusCode,
926
- isValidUTF8: _isValidUTF8,
927
- tokenChars
928
- };
929
- if (isUtf8) module.exports.isValidUTF8 = function(buf) {
930
- return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);
931
- };
932
- else if (!process.env.WS_NO_UTF_8_VALIDATE) try {
933
- const isValidUTF8 = __require("utf-8-validate");
934
- module.exports.isValidUTF8 = function(buf) {
935
- return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
936
- };
937
- } catch (e) {}
938
- }));
939
- //#endregion
940
- //#region ../../node_modules/ws/lib/receiver.js
941
- var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
942
- const { Writable } = __require("stream");
943
- const PerMessageDeflate = require_permessage_deflate();
944
- const { BINARY_TYPES, EMPTY_BUFFER, kStatusCode, kWebSocket } = require_constants();
945
- const { concat, toArrayBuffer, unmask } = require_buffer_util();
946
- const { isValidStatusCode, isValidUTF8 } = require_validation();
947
- const FastBuffer = Buffer[Symbol.species];
948
- const GET_INFO = 0;
949
- const GET_PAYLOAD_LENGTH_16 = 1;
950
- const GET_PAYLOAD_LENGTH_64 = 2;
951
- const GET_MASK = 3;
952
- const GET_DATA = 4;
953
- const INFLATING = 5;
954
- const DEFER_EVENT = 6;
955
- /**
956
- * HyBi Receiver implementation.
957
- *
958
- * @extends Writable
959
- */
960
- var Receiver = class extends Writable {
961
- /**
962
- * Creates a Receiver instance.
963
- *
964
- * @param {Object} [options] Options object
965
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
966
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
967
- * multiple times in the same tick
968
- * @param {String} [options.binaryType=nodebuffer] The type for binary data
969
- * @param {Object} [options.extensions] An object containing the negotiated
970
- * extensions
971
- * @param {Boolean} [options.isServer=false] Specifies whether to operate in
972
- * client or server mode
973
- * @param {Number} [options.maxPayload=0] The maximum allowed message length
974
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
975
- * not to skip UTF-8 validation for text and close messages
976
- */
977
- constructor(options = {}) {
978
- super();
979
- this._allowSynchronousEvents = options.allowSynchronousEvents !== void 0 ? options.allowSynchronousEvents : true;
980
- this._binaryType = options.binaryType || BINARY_TYPES[0];
981
- this._extensions = options.extensions || {};
982
- this._isServer = !!options.isServer;
983
- this._maxPayload = options.maxPayload | 0;
984
- this._skipUTF8Validation = !!options.skipUTF8Validation;
985
- this[kWebSocket] = void 0;
986
- this._bufferedBytes = 0;
987
- this._buffers = [];
988
- this._compressed = false;
989
- this._payloadLength = 0;
990
- this._mask = void 0;
991
- this._fragmented = 0;
992
- this._masked = false;
993
- this._fin = false;
994
- this._opcode = 0;
995
- this._totalPayloadLength = 0;
996
- this._messageLength = 0;
997
- this._fragments = [];
998
- this._errored = false;
999
- this._loop = false;
1000
- this._state = GET_INFO;
1001
- }
1002
- /**
1003
- * Implements `Writable.prototype._write()`.
1004
- *
1005
- * @param {Buffer} chunk The chunk of data to write
1006
- * @param {String} encoding The character encoding of `chunk`
1007
- * @param {Function} cb Callback
1008
- * @private
1009
- */
1010
- _write(chunk, encoding, cb) {
1011
- if (this._opcode === 8 && this._state == GET_INFO) return cb();
1012
- this._bufferedBytes += chunk.length;
1013
- this._buffers.push(chunk);
1014
- this.startLoop(cb);
1015
- }
1016
- /**
1017
- * Consumes `n` bytes from the buffered data.
1018
- *
1019
- * @param {Number} n The number of bytes to consume
1020
- * @return {Buffer} The consumed bytes
1021
- * @private
1022
- */
1023
- consume(n) {
1024
- this._bufferedBytes -= n;
1025
- if (n === this._buffers[0].length) return this._buffers.shift();
1026
- if (n < this._buffers[0].length) {
1027
- const buf = this._buffers[0];
1028
- this._buffers[0] = new FastBuffer(buf.buffer, buf.byteOffset + n, buf.length - n);
1029
- return new FastBuffer(buf.buffer, buf.byteOffset, n);
1030
- }
1031
- const dst = Buffer.allocUnsafe(n);
1032
- do {
1033
- const buf = this._buffers[0];
1034
- const offset = dst.length - n;
1035
- if (n >= buf.length) dst.set(this._buffers.shift(), offset);
1036
- else {
1037
- dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
1038
- this._buffers[0] = new FastBuffer(buf.buffer, buf.byteOffset + n, buf.length - n);
1039
- }
1040
- n -= buf.length;
1041
- } while (n > 0);
1042
- return dst;
1043
- }
1044
- /**
1045
- * Starts the parsing loop.
1046
- *
1047
- * @param {Function} cb Callback
1048
- * @private
1049
- */
1050
- startLoop(cb) {
1051
- this._loop = true;
1052
- do
1053
- switch (this._state) {
1054
- case GET_INFO:
1055
- this.getInfo(cb);
1056
- break;
1057
- case GET_PAYLOAD_LENGTH_16:
1058
- this.getPayloadLength16(cb);
1059
- break;
1060
- case GET_PAYLOAD_LENGTH_64:
1061
- this.getPayloadLength64(cb);
1062
- break;
1063
- case GET_MASK:
1064
- this.getMask();
1065
- break;
1066
- case GET_DATA:
1067
- this.getData(cb);
1068
- break;
1069
- case INFLATING:
1070
- case DEFER_EVENT:
1071
- this._loop = false;
1072
- return;
1073
- }
1074
- while (this._loop);
1075
- if (!this._errored) cb();
1076
- }
1077
- /**
1078
- * Reads the first two bytes of a frame.
1079
- *
1080
- * @param {Function} cb Callback
1081
- * @private
1082
- */
1083
- getInfo(cb) {
1084
- if (this._bufferedBytes < 2) {
1085
- this._loop = false;
1086
- return;
1087
- }
1088
- const buf = this.consume(2);
1089
- if ((buf[0] & 48) !== 0) {
1090
- cb(this.createError(RangeError, "RSV2 and RSV3 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_2_3"));
1091
- return;
1092
- }
1093
- const compressed = (buf[0] & 64) === 64;
1094
- if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
1095
- cb(this.createError(RangeError, "RSV1 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_1"));
1096
- return;
1097
- }
1098
- this._fin = (buf[0] & 128) === 128;
1099
- this._opcode = buf[0] & 15;
1100
- this._payloadLength = buf[1] & 127;
1101
- if (this._opcode === 0) {
1102
- if (compressed) {
1103
- cb(this.createError(RangeError, "RSV1 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_1"));
1104
- return;
1105
- }
1106
- if (!this._fragmented) {
1107
- cb(this.createError(RangeError, "invalid opcode 0", true, 1002, "WS_ERR_INVALID_OPCODE"));
1108
- return;
1109
- }
1110
- this._opcode = this._fragmented;
1111
- } else if (this._opcode === 1 || this._opcode === 2) {
1112
- if (this._fragmented) {
1113
- cb(this.createError(RangeError, `invalid opcode ${this._opcode}`, true, 1002, "WS_ERR_INVALID_OPCODE"));
1114
- return;
1115
- }
1116
- this._compressed = compressed;
1117
- } else if (this._opcode > 7 && this._opcode < 11) {
1118
- if (!this._fin) {
1119
- cb(this.createError(RangeError, "FIN must be set", true, 1002, "WS_ERR_EXPECTED_FIN"));
1120
- return;
1121
- }
1122
- if (compressed) {
1123
- cb(this.createError(RangeError, "RSV1 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_1"));
1124
- return;
1125
- }
1126
- if (this._payloadLength > 125 || this._opcode === 8 && this._payloadLength === 1) {
1127
- cb(this.createError(RangeError, `invalid payload length ${this._payloadLength}`, true, 1002, "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH"));
1128
- return;
1129
- }
1130
- } else {
1131
- cb(this.createError(RangeError, `invalid opcode ${this._opcode}`, true, 1002, "WS_ERR_INVALID_OPCODE"));
1132
- return;
1133
- }
1134
- if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
1135
- this._masked = (buf[1] & 128) === 128;
1136
- if (this._isServer) {
1137
- if (!this._masked) {
1138
- cb(this.createError(RangeError, "MASK must be set", true, 1002, "WS_ERR_EXPECTED_MASK"));
1139
- return;
1140
- }
1141
- } else if (this._masked) {
1142
- cb(this.createError(RangeError, "MASK must be clear", true, 1002, "WS_ERR_UNEXPECTED_MASK"));
1143
- return;
1144
- }
1145
- if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
1146
- else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
1147
- else this.haveLength(cb);
1148
- }
1149
- /**
1150
- * Gets extended payload length (7+16).
1151
- *
1152
- * @param {Function} cb Callback
1153
- * @private
1154
- */
1155
- getPayloadLength16(cb) {
1156
- if (this._bufferedBytes < 2) {
1157
- this._loop = false;
1158
- return;
1159
- }
1160
- this._payloadLength = this.consume(2).readUInt16BE(0);
1161
- this.haveLength(cb);
1162
- }
1163
- /**
1164
- * Gets extended payload length (7+64).
1165
- *
1166
- * @param {Function} cb Callback
1167
- * @private
1168
- */
1169
- getPayloadLength64(cb) {
1170
- if (this._bufferedBytes < 8) {
1171
- this._loop = false;
1172
- return;
1173
- }
1174
- const buf = this.consume(8);
1175
- const num = buf.readUInt32BE(0);
1176
- if (num > Math.pow(2, 21) - 1) {
1177
- cb(this.createError(RangeError, "Unsupported WebSocket frame: payload length > 2^53 - 1", false, 1009, "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH"));
1178
- return;
1179
- }
1180
- this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
1181
- this.haveLength(cb);
1182
- }
1183
- /**
1184
- * Payload length has been read.
1185
- *
1186
- * @param {Function} cb Callback
1187
- * @private
1188
- */
1189
- haveLength(cb) {
1190
- if (this._payloadLength && this._opcode < 8) {
1191
- this._totalPayloadLength += this._payloadLength;
1192
- if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
1193
- cb(this.createError(RangeError, "Max payload size exceeded", false, 1009, "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"));
1194
- return;
1195
- }
1196
- }
1197
- if (this._masked) this._state = GET_MASK;
1198
- else this._state = GET_DATA;
1199
- }
1200
- /**
1201
- * Reads mask bytes.
1202
- *
1203
- * @private
1204
- */
1205
- getMask() {
1206
- if (this._bufferedBytes < 4) {
1207
- this._loop = false;
1208
- return;
1209
- }
1210
- this._mask = this.consume(4);
1211
- this._state = GET_DATA;
1212
- }
1213
- /**
1214
- * Reads data bytes.
1215
- *
1216
- * @param {Function} cb Callback
1217
- * @private
1218
- */
1219
- getData(cb) {
1220
- let data = EMPTY_BUFFER;
1221
- if (this._payloadLength) {
1222
- if (this._bufferedBytes < this._payloadLength) {
1223
- this._loop = false;
1224
- return;
1225
- }
1226
- data = this.consume(this._payloadLength);
1227
- if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) unmask(data, this._mask);
1228
- }
1229
- if (this._opcode > 7) {
1230
- this.controlMessage(data, cb);
1231
- return;
1232
- }
1233
- if (this._compressed) {
1234
- this._state = INFLATING;
1235
- this.decompress(data, cb);
1236
- return;
1237
- }
1238
- if (data.length) {
1239
- this._messageLength = this._totalPayloadLength;
1240
- this._fragments.push(data);
1241
- }
1242
- this.dataMessage(cb);
1243
- }
1244
- /**
1245
- * Decompresses data.
1246
- *
1247
- * @param {Buffer} data Compressed data
1248
- * @param {Function} cb Callback
1249
- * @private
1250
- */
1251
- decompress(data, cb) {
1252
- this._extensions[PerMessageDeflate.extensionName].decompress(data, this._fin, (err, buf) => {
1253
- if (err) return cb(err);
1254
- if (buf.length) {
1255
- this._messageLength += buf.length;
1256
- if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
1257
- cb(this.createError(RangeError, "Max payload size exceeded", false, 1009, "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"));
1258
- return;
1259
- }
1260
- this._fragments.push(buf);
1261
- }
1262
- this.dataMessage(cb);
1263
- if (this._state === GET_INFO) this.startLoop(cb);
1264
- });
1265
- }
1266
- /**
1267
- * Handles a data message.
1268
- *
1269
- * @param {Function} cb Callback
1270
- * @private
1271
- */
1272
- dataMessage(cb) {
1273
- if (!this._fin) {
1274
- this._state = GET_INFO;
1275
- return;
1276
- }
1277
- const messageLength = this._messageLength;
1278
- const fragments = this._fragments;
1279
- this._totalPayloadLength = 0;
1280
- this._messageLength = 0;
1281
- this._fragmented = 0;
1282
- this._fragments = [];
1283
- if (this._opcode === 2) {
1284
- let data;
1285
- if (this._binaryType === "nodebuffer") data = concat(fragments, messageLength);
1286
- else if (this._binaryType === "arraybuffer") data = toArrayBuffer(concat(fragments, messageLength));
1287
- else if (this._binaryType === "blob") data = new Blob(fragments);
1288
- else data = fragments;
1289
- if (this._allowSynchronousEvents) {
1290
- this.emit("message", data, true);
1291
- this._state = GET_INFO;
1292
- } else {
1293
- this._state = DEFER_EVENT;
1294
- setImmediate(() => {
1295
- this.emit("message", data, true);
1296
- this._state = GET_INFO;
1297
- this.startLoop(cb);
1298
- });
1299
- }
1300
- } else {
1301
- const buf = concat(fragments, messageLength);
1302
- if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
1303
- cb(this.createError(Error, "invalid UTF-8 sequence", true, 1007, "WS_ERR_INVALID_UTF8"));
1304
- return;
1305
- }
1306
- if (this._state === INFLATING || this._allowSynchronousEvents) {
1307
- this.emit("message", buf, false);
1308
- this._state = GET_INFO;
1309
- } else {
1310
- this._state = DEFER_EVENT;
1311
- setImmediate(() => {
1312
- this.emit("message", buf, false);
1313
- this._state = GET_INFO;
1314
- this.startLoop(cb);
1315
- });
1316
- }
1317
- }
1318
- }
1319
- /**
1320
- * Handles a control message.
1321
- *
1322
- * @param {Buffer} data Data to handle
1323
- * @return {(Error|RangeError|undefined)} A possible error
1324
- * @private
1325
- */
1326
- controlMessage(data, cb) {
1327
- if (this._opcode === 8) {
1328
- if (data.length === 0) {
1329
- this._loop = false;
1330
- this.emit("conclude", 1005, EMPTY_BUFFER);
1331
- this.end();
1332
- } else {
1333
- const code = data.readUInt16BE(0);
1334
- if (!isValidStatusCode(code)) {
1335
- cb(this.createError(RangeError, `invalid status code ${code}`, true, 1002, "WS_ERR_INVALID_CLOSE_CODE"));
1336
- return;
1337
- }
1338
- const buf = new FastBuffer(data.buffer, data.byteOffset + 2, data.length - 2);
1339
- if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
1340
- cb(this.createError(Error, "invalid UTF-8 sequence", true, 1007, "WS_ERR_INVALID_UTF8"));
1341
- return;
1342
- }
1343
- this._loop = false;
1344
- this.emit("conclude", code, buf);
1345
- this.end();
1346
- }
1347
- this._state = GET_INFO;
1348
- return;
1349
- }
1350
- if (this._allowSynchronousEvents) {
1351
- this.emit(this._opcode === 9 ? "ping" : "pong", data);
1352
- this._state = GET_INFO;
1353
- } else {
1354
- this._state = DEFER_EVENT;
1355
- setImmediate(() => {
1356
- this.emit(this._opcode === 9 ? "ping" : "pong", data);
1357
- this._state = GET_INFO;
1358
- this.startLoop(cb);
1359
- });
1360
- }
1361
- }
1362
- /**
1363
- * Builds an error object.
1364
- *
1365
- * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
1366
- * @param {String} message The error message
1367
- * @param {Boolean} prefix Specifies whether or not to add a default prefix to
1368
- * `message`
1369
- * @param {Number} statusCode The status code
1370
- * @param {String} errorCode The exposed error code
1371
- * @return {(Error|RangeError)} The error
1372
- * @private
1373
- */
1374
- createError(ErrorCtor, message, prefix, statusCode, errorCode) {
1375
- this._loop = false;
1376
- this._errored = true;
1377
- const err = new ErrorCtor(prefix ? `Invalid WebSocket frame: ${message}` : message);
1378
- Error.captureStackTrace(err, this.createError);
1379
- err.code = errorCode;
1380
- err[kStatusCode] = statusCode;
1381
- return err;
1382
- }
1383
- };
1384
- module.exports = Receiver;
1385
- }));
1386
- //#endregion
1387
- //#region ../../node_modules/ws/lib/sender.js
1388
- var require_sender = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1389
- const { Duplex: Duplex$3 } = __require("stream");
1390
- const { randomFillSync } = __require("crypto");
1391
- const { types: { isUint8Array } } = __require("util");
1392
- const PerMessageDeflate = require_permessage_deflate();
1393
- const { EMPTY_BUFFER, kWebSocket, NOOP } = require_constants();
1394
- const { isBlob, isValidStatusCode } = require_validation();
1395
- const { mask: applyMask, toBuffer } = require_buffer_util();
1396
- const kByteLength = Symbol("kByteLength");
1397
- const maskBuffer = Buffer.alloc(4);
1398
- const RANDOM_POOL_SIZE = 8 * 1024;
1399
- let randomPool;
1400
- let randomPoolPointer = RANDOM_POOL_SIZE;
1401
- const DEFAULT = 0;
1402
- const DEFLATING = 1;
1403
- const GET_BLOB_DATA = 2;
1404
- module.exports = class Sender {
1405
- /**
1406
- * Creates a Sender instance.
1407
- *
1408
- * @param {Duplex} socket The connection socket
1409
- * @param {Object} [extensions] An object containing the negotiated extensions
1410
- * @param {Function} [generateMask] The function used to generate the masking
1411
- * key
1412
- */
1413
- constructor(socket, extensions, generateMask) {
1414
- this._extensions = extensions || {};
1415
- if (generateMask) {
1416
- this._generateMask = generateMask;
1417
- this._maskBuffer = Buffer.alloc(4);
1418
- }
1419
- this._socket = socket;
1420
- this._firstFragment = true;
1421
- this._compress = false;
1422
- this._bufferedBytes = 0;
1423
- this._queue = [];
1424
- this._state = DEFAULT;
1425
- this.onerror = NOOP;
1426
- this[kWebSocket] = void 0;
1427
- }
1428
- /**
1429
- * Frames a piece of data according to the HyBi WebSocket protocol.
1430
- *
1431
- * @param {(Buffer|String)} data The data to frame
1432
- * @param {Object} options Options object
1433
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1434
- * FIN bit
1435
- * @param {Function} [options.generateMask] The function used to generate the
1436
- * masking key
1437
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1438
- * `data`
1439
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1440
- * key
1441
- * @param {Number} options.opcode The opcode
1442
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1443
- * modified
1444
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1445
- * RSV1 bit
1446
- * @return {(Buffer|String)[]} The framed data
1447
- * @public
1448
- */
1449
- static frame(data, options) {
1450
- let mask;
1451
- let merge = false;
1452
- let offset = 2;
1453
- let skipMasking = false;
1454
- if (options.mask) {
1455
- mask = options.maskBuffer || maskBuffer;
1456
- if (options.generateMask) options.generateMask(mask);
1457
- else {
1458
- if (randomPoolPointer === RANDOM_POOL_SIZE) {
1459
- /* istanbul ignore else */
1460
- if (randomPool === void 0) randomPool = Buffer.alloc(RANDOM_POOL_SIZE);
1461
- randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
1462
- randomPoolPointer = 0;
1463
- }
1464
- mask[0] = randomPool[randomPoolPointer++];
1465
- mask[1] = randomPool[randomPoolPointer++];
1466
- mask[2] = randomPool[randomPoolPointer++];
1467
- mask[3] = randomPool[randomPoolPointer++];
1468
- }
1469
- skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
1470
- offset = 6;
1471
- }
1472
- let dataLength;
1473
- if (typeof data === "string") if ((!options.mask || skipMasking) && options[kByteLength] !== void 0) dataLength = options[kByteLength];
1474
- else {
1475
- data = Buffer.from(data);
1476
- dataLength = data.length;
1477
- }
1478
- else {
1479
- dataLength = data.length;
1480
- merge = options.mask && options.readOnly && !skipMasking;
1481
- }
1482
- let payloadLength = dataLength;
1483
- if (dataLength >= 65536) {
1484
- offset += 8;
1485
- payloadLength = 127;
1486
- } else if (dataLength > 125) {
1487
- offset += 2;
1488
- payloadLength = 126;
1489
- }
1490
- const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);
1491
- target[0] = options.fin ? options.opcode | 128 : options.opcode;
1492
- if (options.rsv1) target[0] |= 64;
1493
- target[1] = payloadLength;
1494
- if (payloadLength === 126) target.writeUInt16BE(dataLength, 2);
1495
- else if (payloadLength === 127) {
1496
- target[2] = target[3] = 0;
1497
- target.writeUIntBE(dataLength, 4, 6);
1498
- }
1499
- if (!options.mask) return [target, data];
1500
- target[1] |= 128;
1501
- target[offset - 4] = mask[0];
1502
- target[offset - 3] = mask[1];
1503
- target[offset - 2] = mask[2];
1504
- target[offset - 1] = mask[3];
1505
- if (skipMasking) return [target, data];
1506
- if (merge) {
1507
- applyMask(data, mask, target, offset, dataLength);
1508
- return [target];
1509
- }
1510
- applyMask(data, mask, data, 0, dataLength);
1511
- return [target, data];
1512
- }
1513
- /**
1514
- * Sends a close message to the other peer.
1515
- *
1516
- * @param {Number} [code] The status code component of the body
1517
- * @param {(String|Buffer)} [data] The message component of the body
1518
- * @param {Boolean} [mask=false] Specifies whether or not to mask the message
1519
- * @param {Function} [cb] Callback
1520
- * @public
1521
- */
1522
- close(code, data, mask, cb) {
1523
- let buf;
1524
- if (code === void 0) buf = EMPTY_BUFFER;
1525
- else if (typeof code !== "number" || !isValidStatusCode(code)) throw new TypeError("First argument must be a valid error code number");
1526
- else if (data === void 0 || !data.length) {
1527
- buf = Buffer.allocUnsafe(2);
1528
- buf.writeUInt16BE(code, 0);
1529
- } else {
1530
- const length = Buffer.byteLength(data);
1531
- if (length > 123) throw new RangeError("The message must not be greater than 123 bytes");
1532
- buf = Buffer.allocUnsafe(2 + length);
1533
- buf.writeUInt16BE(code, 0);
1534
- if (typeof data === "string") buf.write(data, 2);
1535
- else if (isUint8Array(data)) buf.set(data, 2);
1536
- else throw new TypeError("Second argument must be a string or a Uint8Array");
1537
- }
1538
- const options = {
1539
- [kByteLength]: buf.length,
1540
- fin: true,
1541
- generateMask: this._generateMask,
1542
- mask,
1543
- maskBuffer: this._maskBuffer,
1544
- opcode: 8,
1545
- readOnly: false,
1546
- rsv1: false
1547
- };
1548
- if (this._state !== DEFAULT) this.enqueue([
1549
- this.dispatch,
1550
- buf,
1551
- false,
1552
- options,
1553
- cb
1554
- ]);
1555
- else this.sendFrame(Sender.frame(buf, options), cb);
1556
- }
1557
- /**
1558
- * Sends a ping message to the other peer.
1559
- *
1560
- * @param {*} data The message to send
1561
- * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1562
- * @param {Function} [cb] Callback
1563
- * @public
1564
- */
1565
- ping(data, mask, cb) {
1566
- let byteLength;
1567
- let readOnly;
1568
- if (typeof data === "string") {
1569
- byteLength = Buffer.byteLength(data);
1570
- readOnly = false;
1571
- } else if (isBlob(data)) {
1572
- byteLength = data.size;
1573
- readOnly = false;
1574
- } else {
1575
- data = toBuffer(data);
1576
- byteLength = data.length;
1577
- readOnly = toBuffer.readOnly;
1578
- }
1579
- if (byteLength > 125) throw new RangeError("The data size must not be greater than 125 bytes");
1580
- const options = {
1581
- [kByteLength]: byteLength,
1582
- fin: true,
1583
- generateMask: this._generateMask,
1584
- mask,
1585
- maskBuffer: this._maskBuffer,
1586
- opcode: 9,
1587
- readOnly,
1588
- rsv1: false
1589
- };
1590
- if (isBlob(data)) if (this._state !== DEFAULT) this.enqueue([
1591
- this.getBlobData,
1592
- data,
1593
- false,
1594
- options,
1595
- cb
1596
- ]);
1597
- else this.getBlobData(data, false, options, cb);
1598
- else if (this._state !== DEFAULT) this.enqueue([
1599
- this.dispatch,
1600
- data,
1601
- false,
1602
- options,
1603
- cb
1604
- ]);
1605
- else this.sendFrame(Sender.frame(data, options), cb);
1606
- }
1607
- /**
1608
- * Sends a pong message to the other peer.
1609
- *
1610
- * @param {*} data The message to send
1611
- * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1612
- * @param {Function} [cb] Callback
1613
- * @public
1614
- */
1615
- pong(data, mask, cb) {
1616
- let byteLength;
1617
- let readOnly;
1618
- if (typeof data === "string") {
1619
- byteLength = Buffer.byteLength(data);
1620
- readOnly = false;
1621
- } else if (isBlob(data)) {
1622
- byteLength = data.size;
1623
- readOnly = false;
1624
- } else {
1625
- data = toBuffer(data);
1626
- byteLength = data.length;
1627
- readOnly = toBuffer.readOnly;
1628
- }
1629
- if (byteLength > 125) throw new RangeError("The data size must not be greater than 125 bytes");
1630
- const options = {
1631
- [kByteLength]: byteLength,
1632
- fin: true,
1633
- generateMask: this._generateMask,
1634
- mask,
1635
- maskBuffer: this._maskBuffer,
1636
- opcode: 10,
1637
- readOnly,
1638
- rsv1: false
1639
- };
1640
- if (isBlob(data)) if (this._state !== DEFAULT) this.enqueue([
1641
- this.getBlobData,
1642
- data,
1643
- false,
1644
- options,
1645
- cb
1646
- ]);
1647
- else this.getBlobData(data, false, options, cb);
1648
- else if (this._state !== DEFAULT) this.enqueue([
1649
- this.dispatch,
1650
- data,
1651
- false,
1652
- options,
1653
- cb
1654
- ]);
1655
- else this.sendFrame(Sender.frame(data, options), cb);
1656
- }
1657
- /**
1658
- * Sends a data message to the other peer.
1659
- *
1660
- * @param {*} data The message to send
1661
- * @param {Object} options Options object
1662
- * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
1663
- * or text
1664
- * @param {Boolean} [options.compress=false] Specifies whether or not to
1665
- * compress `data`
1666
- * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
1667
- * last one
1668
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1669
- * `data`
1670
- * @param {Function} [cb] Callback
1671
- * @public
1672
- */
1673
- send(data, options, cb) {
1674
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
1675
- let opcode = options.binary ? 2 : 1;
1676
- let rsv1 = options.compress;
1677
- let byteLength;
1678
- let readOnly;
1679
- if (typeof data === "string") {
1680
- byteLength = Buffer.byteLength(data);
1681
- readOnly = false;
1682
- } else if (isBlob(data)) {
1683
- byteLength = data.size;
1684
- readOnly = false;
1685
- } else {
1686
- data = toBuffer(data);
1687
- byteLength = data.length;
1688
- readOnly = toBuffer.readOnly;
1689
- }
1690
- if (this._firstFragment) {
1691
- this._firstFragment = false;
1692
- if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) rsv1 = byteLength >= perMessageDeflate._threshold;
1693
- this._compress = rsv1;
1694
- } else {
1695
- rsv1 = false;
1696
- opcode = 0;
1697
- }
1698
- if (options.fin) this._firstFragment = true;
1699
- const opts = {
1700
- [kByteLength]: byteLength,
1701
- fin: options.fin,
1702
- generateMask: this._generateMask,
1703
- mask: options.mask,
1704
- maskBuffer: this._maskBuffer,
1705
- opcode,
1706
- readOnly,
1707
- rsv1
1708
- };
1709
- if (isBlob(data)) if (this._state !== DEFAULT) this.enqueue([
1710
- this.getBlobData,
1711
- data,
1712
- this._compress,
1713
- opts,
1714
- cb
1715
- ]);
1716
- else this.getBlobData(data, this._compress, opts, cb);
1717
- else if (this._state !== DEFAULT) this.enqueue([
1718
- this.dispatch,
1719
- data,
1720
- this._compress,
1721
- opts,
1722
- cb
1723
- ]);
1724
- else this.dispatch(data, this._compress, opts, cb);
1725
- }
1726
- /**
1727
- * Gets the contents of a blob as binary data.
1728
- *
1729
- * @param {Blob} blob The blob
1730
- * @param {Boolean} [compress=false] Specifies whether or not to compress
1731
- * the data
1732
- * @param {Object} options Options object
1733
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1734
- * FIN bit
1735
- * @param {Function} [options.generateMask] The function used to generate the
1736
- * masking key
1737
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1738
- * `data`
1739
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1740
- * key
1741
- * @param {Number} options.opcode The opcode
1742
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1743
- * modified
1744
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1745
- * RSV1 bit
1746
- * @param {Function} [cb] Callback
1747
- * @private
1748
- */
1749
- getBlobData(blob, compress, options, cb) {
1750
- this._bufferedBytes += options[kByteLength];
1751
- this._state = GET_BLOB_DATA;
1752
- blob.arrayBuffer().then((arrayBuffer) => {
1753
- if (this._socket.destroyed) {
1754
- const err = /* @__PURE__ */ new Error("The socket was closed while the blob was being read");
1755
- process.nextTick(callCallbacks, this, err, cb);
1756
- return;
1757
- }
1758
- this._bufferedBytes -= options[kByteLength];
1759
- const data = toBuffer(arrayBuffer);
1760
- if (!compress) {
1761
- this._state = DEFAULT;
1762
- this.sendFrame(Sender.frame(data, options), cb);
1763
- this.dequeue();
1764
- } else this.dispatch(data, compress, options, cb);
1765
- }).catch((err) => {
1766
- process.nextTick(onError, this, err, cb);
1767
- });
1768
- }
1769
- /**
1770
- * Dispatches a message.
1771
- *
1772
- * @param {(Buffer|String)} data The message to send
1773
- * @param {Boolean} [compress=false] Specifies whether or not to compress
1774
- * `data`
1775
- * @param {Object} options Options object
1776
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1777
- * FIN bit
1778
- * @param {Function} [options.generateMask] The function used to generate the
1779
- * masking key
1780
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1781
- * `data`
1782
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1783
- * key
1784
- * @param {Number} options.opcode The opcode
1785
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1786
- * modified
1787
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1788
- * RSV1 bit
1789
- * @param {Function} [cb] Callback
1790
- * @private
1791
- */
1792
- dispatch(data, compress, options, cb) {
1793
- if (!compress) {
1794
- this.sendFrame(Sender.frame(data, options), cb);
1795
- return;
1796
- }
1797
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
1798
- this._bufferedBytes += options[kByteLength];
1799
- this._state = DEFLATING;
1800
- perMessageDeflate.compress(data, options.fin, (_, buf) => {
1801
- if (this._socket.destroyed) {
1802
- const err = /* @__PURE__ */ new Error("The socket was closed while data was being compressed");
1803
- callCallbacks(this, err, cb);
1804
- return;
1805
- }
1806
- this._bufferedBytes -= options[kByteLength];
1807
- this._state = DEFAULT;
1808
- options.readOnly = false;
1809
- this.sendFrame(Sender.frame(buf, options), cb);
1810
- this.dequeue();
1811
- });
1812
- }
1813
- /**
1814
- * Executes queued send operations.
1815
- *
1816
- * @private
1817
- */
1818
- dequeue() {
1819
- while (this._state === DEFAULT && this._queue.length) {
1820
- const params = this._queue.shift();
1821
- this._bufferedBytes -= params[3][kByteLength];
1822
- Reflect.apply(params[0], this, params.slice(1));
1823
- }
1824
- }
1825
- /**
1826
- * Enqueues a send operation.
1827
- *
1828
- * @param {Array} params Send operation parameters.
1829
- * @private
1830
- */
1831
- enqueue(params) {
1832
- this._bufferedBytes += params[3][kByteLength];
1833
- this._queue.push(params);
1834
- }
1835
- /**
1836
- * Sends a frame.
1837
- *
1838
- * @param {(Buffer | String)[]} list The frame to send
1839
- * @param {Function} [cb] Callback
1840
- * @private
1841
- */
1842
- sendFrame(list, cb) {
1843
- if (list.length === 2) {
1844
- this._socket.cork();
1845
- this._socket.write(list[0]);
1846
- this._socket.write(list[1], cb);
1847
- this._socket.uncork();
1848
- } else this._socket.write(list[0], cb);
1849
- }
1850
- };
1851
- /**
1852
- * Calls queued callbacks with an error.
1853
- *
1854
- * @param {Sender} sender The `Sender` instance
1855
- * @param {Error} err The error to call the callbacks with
1856
- * @param {Function} [cb] The first callback
1857
- * @private
1858
- */
1859
- function callCallbacks(sender, err, cb) {
1860
- if (typeof cb === "function") cb(err);
1861
- for (let i = 0; i < sender._queue.length; i++) {
1862
- const params = sender._queue[i];
1863
- const callback = params[params.length - 1];
1864
- if (typeof callback === "function") callback(err);
1865
- }
1866
- }
1867
- /**
1868
- * Handles a `Sender` error.
1869
- *
1870
- * @param {Sender} sender The `Sender` instance
1871
- * @param {Error} err The error
1872
- * @param {Function} [cb] The first pending callback
1873
- * @private
1874
- */
1875
- function onError(sender, err, cb) {
1876
- callCallbacks(sender, err, cb);
1877
- sender.onerror(err);
1878
- }
1879
- }));
1880
- //#endregion
1881
- //#region ../../node_modules/ws/lib/event-target.js
1882
- var require_event_target = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1883
- const { kForOnEventAttribute, kListener } = require_constants();
1884
- const kCode = Symbol("kCode");
1885
- const kData = Symbol("kData");
1886
- const kError = Symbol("kError");
1887
- const kMessage = Symbol("kMessage");
1888
- const kReason = Symbol("kReason");
1889
- const kTarget = Symbol("kTarget");
1890
- const kType = Symbol("kType");
1891
- const kWasClean = Symbol("kWasClean");
1892
- /**
1893
- * Class representing an event.
1894
- */
1895
- var Event = class {
1896
- /**
1897
- * Create a new `Event`.
1898
- *
1899
- * @param {String} type The name of the event
1900
- * @throws {TypeError} If the `type` argument is not specified
1901
- */
1902
- constructor(type) {
1903
- this[kTarget] = null;
1904
- this[kType] = type;
1905
- }
1906
- /**
1907
- * @type {*}
1908
- */
1909
- get target() {
1910
- return this[kTarget];
1911
- }
1912
- /**
1913
- * @type {String}
1914
- */
1915
- get type() {
1916
- return this[kType];
1917
- }
1918
- };
1919
- Object.defineProperty(Event.prototype, "target", { enumerable: true });
1920
- Object.defineProperty(Event.prototype, "type", { enumerable: true });
1921
- /**
1922
- * Class representing a close event.
1923
- *
1924
- * @extends Event
1925
- */
1926
- var CloseEvent = class extends Event {
1927
- /**
1928
- * Create a new `CloseEvent`.
1929
- *
1930
- * @param {String} type The name of the event
1931
- * @param {Object} [options] A dictionary object that allows for setting
1932
- * attributes via object members of the same name
1933
- * @param {Number} [options.code=0] The status code explaining why the
1934
- * connection was closed
1935
- * @param {String} [options.reason=''] A human-readable string explaining why
1936
- * the connection was closed
1937
- * @param {Boolean} [options.wasClean=false] Indicates whether or not the
1938
- * connection was cleanly closed
1939
- */
1940
- constructor(type, options = {}) {
1941
- super(type);
1942
- this[kCode] = options.code === void 0 ? 0 : options.code;
1943
- this[kReason] = options.reason === void 0 ? "" : options.reason;
1944
- this[kWasClean] = options.wasClean === void 0 ? false : options.wasClean;
1945
- }
1946
- /**
1947
- * @type {Number}
1948
- */
1949
- get code() {
1950
- return this[kCode];
1951
- }
1952
- /**
1953
- * @type {String}
1954
- */
1955
- get reason() {
1956
- return this[kReason];
1957
- }
1958
- /**
1959
- * @type {Boolean}
1960
- */
1961
- get wasClean() {
1962
- return this[kWasClean];
1963
- }
1964
- };
1965
- Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true });
1966
- Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true });
1967
- Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true });
1968
- /**
1969
- * Class representing an error event.
1970
- *
1971
- * @extends Event
1972
- */
1973
- var ErrorEvent = class extends Event {
1974
- /**
1975
- * Create a new `ErrorEvent`.
1976
- *
1977
- * @param {String} type The name of the event
1978
- * @param {Object} [options] A dictionary object that allows for setting
1979
- * attributes via object members of the same name
1980
- * @param {*} [options.error=null] The error that generated this event
1981
- * @param {String} [options.message=''] The error message
1982
- */
1983
- constructor(type, options = {}) {
1984
- super(type);
1985
- this[kError] = options.error === void 0 ? null : options.error;
1986
- this[kMessage] = options.message === void 0 ? "" : options.message;
1987
- }
1988
- /**
1989
- * @type {*}
1990
- */
1991
- get error() {
1992
- return this[kError];
1993
- }
1994
- /**
1995
- * @type {String}
1996
- */
1997
- get message() {
1998
- return this[kMessage];
1999
- }
2000
- };
2001
- Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true });
2002
- Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true });
2003
- /**
2004
- * Class representing a message event.
2005
- *
2006
- * @extends Event
2007
- */
2008
- var MessageEvent = class extends Event {
2009
- /**
2010
- * Create a new `MessageEvent`.
2011
- *
2012
- * @param {String} type The name of the event
2013
- * @param {Object} [options] A dictionary object that allows for setting
2014
- * attributes via object members of the same name
2015
- * @param {*} [options.data=null] The message content
2016
- */
2017
- constructor(type, options = {}) {
2018
- super(type);
2019
- this[kData] = options.data === void 0 ? null : options.data;
2020
- }
2021
- /**
2022
- * @type {*}
2023
- */
2024
- get data() {
2025
- return this[kData];
2026
- }
2027
- };
2028
- Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true });
2029
- module.exports = {
2030
- CloseEvent,
2031
- ErrorEvent,
2032
- Event,
2033
- EventTarget: {
2034
- /**
2035
- * Register an event listener.
2036
- *
2037
- * @param {String} type A string representing the event type to listen for
2038
- * @param {(Function|Object)} handler The listener to add
2039
- * @param {Object} [options] An options object specifies characteristics about
2040
- * the event listener
2041
- * @param {Boolean} [options.once=false] A `Boolean` indicating that the
2042
- * listener should be invoked at most once after being added. If `true`,
2043
- * the listener would be automatically removed when invoked.
2044
- * @public
2045
- */
2046
- addEventListener(type, handler, options = {}) {
2047
- for (const listener of this.listeners(type)) if (!options[kForOnEventAttribute] && listener[kListener] === handler && !listener[kForOnEventAttribute]) return;
2048
- let wrapper;
2049
- if (type === "message") wrapper = function onMessage(data, isBinary) {
2050
- const event = new MessageEvent("message", { data: isBinary ? data : data.toString() });
2051
- event[kTarget] = this;
2052
- callListener(handler, this, event);
2053
- };
2054
- else if (type === "close") wrapper = function onClose(code, message) {
2055
- const event = new CloseEvent("close", {
2056
- code,
2057
- reason: message.toString(),
2058
- wasClean: this._closeFrameReceived && this._closeFrameSent
2059
- });
2060
- event[kTarget] = this;
2061
- callListener(handler, this, event);
2062
- };
2063
- else if (type === "error") wrapper = function onError(error) {
2064
- const event = new ErrorEvent("error", {
2065
- error,
2066
- message: error.message
2067
- });
2068
- event[kTarget] = this;
2069
- callListener(handler, this, event);
2070
- };
2071
- else if (type === "open") wrapper = function onOpen() {
2072
- const event = new Event("open");
2073
- event[kTarget] = this;
2074
- callListener(handler, this, event);
2075
- };
2076
- else return;
2077
- wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
2078
- wrapper[kListener] = handler;
2079
- if (options.once) this.once(type, wrapper);
2080
- else this.on(type, wrapper);
2081
- },
2082
- /**
2083
- * Remove an event listener.
2084
- *
2085
- * @param {String} type A string representing the event type to remove
2086
- * @param {(Function|Object)} handler The listener to remove
2087
- * @public
2088
- */
2089
- removeEventListener(type, handler) {
2090
- for (const listener of this.listeners(type)) if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
2091
- this.removeListener(type, listener);
2092
- break;
2093
- }
2094
- }
2095
- },
2096
- MessageEvent
2097
- };
2098
- /**
2099
- * Call an event listener
2100
- *
2101
- * @param {(Function|Object)} listener The listener to call
2102
- * @param {*} thisArg The value to use as `this`` when calling the listener
2103
- * @param {Event} event The event to pass to the listener
2104
- * @private
2105
- */
2106
- function callListener(listener, thisArg, event) {
2107
- if (typeof listener === "object" && listener.handleEvent) listener.handleEvent.call(listener, event);
2108
- else listener.call(thisArg, event);
2109
- }
2110
- }));
2111
- //#endregion
2112
- //#region ../../node_modules/ws/lib/extension.js
2113
- var require_extension = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2114
- const { tokenChars } = require_validation();
2115
- /**
2116
- * Adds an offer to the map of extension offers or a parameter to the map of
2117
- * parameters.
2118
- *
2119
- * @param {Object} dest The map of extension offers or parameters
2120
- * @param {String} name The extension or parameter name
2121
- * @param {(Object|Boolean|String)} elem The extension parameters or the
2122
- * parameter value
2123
- * @private
2124
- */
2125
- function push(dest, name, elem) {
2126
- if (dest[name] === void 0) dest[name] = [elem];
2127
- else dest[name].push(elem);
2128
- }
2129
- /**
2130
- * Parses the `Sec-WebSocket-Extensions` header into an object.
2131
- *
2132
- * @param {String} header The field value of the header
2133
- * @return {Object} The parsed object
2134
- * @public
2135
- */
2136
- function parse(header) {
2137
- const offers = Object.create(null);
2138
- let params = Object.create(null);
2139
- let mustUnescape = false;
2140
- let isEscaping = false;
2141
- let inQuotes = false;
2142
- let extensionName;
2143
- let paramName;
2144
- let start = -1;
2145
- let code = -1;
2146
- let end = -1;
2147
- let i = 0;
2148
- for (; i < header.length; i++) {
2149
- code = header.charCodeAt(i);
2150
- if (extensionName === void 0) if (end === -1 && tokenChars[code] === 1) {
2151
- if (start === -1) start = i;
2152
- } else if (i !== 0 && (code === 32 || code === 9)) {
2153
- if (end === -1 && start !== -1) end = i;
2154
- } else if (code === 59 || code === 44) {
2155
- if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
2156
- if (end === -1) end = i;
2157
- const name = header.slice(start, end);
2158
- if (code === 44) {
2159
- push(offers, name, params);
2160
- params = Object.create(null);
2161
- } else extensionName = name;
2162
- start = end = -1;
2163
- } else throw new SyntaxError(`Unexpected character at index ${i}`);
2164
- else if (paramName === void 0) if (end === -1 && tokenChars[code] === 1) {
2165
- if (start === -1) start = i;
2166
- } else if (code === 32 || code === 9) {
2167
- if (end === -1 && start !== -1) end = i;
2168
- } else if (code === 59 || code === 44) {
2169
- if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
2170
- if (end === -1) end = i;
2171
- push(params, header.slice(start, end), true);
2172
- if (code === 44) {
2173
- push(offers, extensionName, params);
2174
- params = Object.create(null);
2175
- extensionName = void 0;
2176
- }
2177
- start = end = -1;
2178
- } else if (code === 61 && start !== -1 && end === -1) {
2179
- paramName = header.slice(start, i);
2180
- start = end = -1;
2181
- } else throw new SyntaxError(`Unexpected character at index ${i}`);
2182
- else if (isEscaping) {
2183
- if (tokenChars[code] !== 1) throw new SyntaxError(`Unexpected character at index ${i}`);
2184
- if (start === -1) start = i;
2185
- else if (!mustUnescape) mustUnescape = true;
2186
- isEscaping = false;
2187
- } else if (inQuotes) if (tokenChars[code] === 1) {
2188
- if (start === -1) start = i;
2189
- } else if (code === 34 && start !== -1) {
2190
- inQuotes = false;
2191
- end = i;
2192
- } else if (code === 92) isEscaping = true;
2193
- else throw new SyntaxError(`Unexpected character at index ${i}`);
2194
- else if (code === 34 && header.charCodeAt(i - 1) === 61) inQuotes = true;
2195
- else if (end === -1 && tokenChars[code] === 1) {
2196
- if (start === -1) start = i;
2197
- } else if (start !== -1 && (code === 32 || code === 9)) {
2198
- if (end === -1) end = i;
2199
- } else if (code === 59 || code === 44) {
2200
- if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
2201
- if (end === -1) end = i;
2202
- let value = header.slice(start, end);
2203
- if (mustUnescape) {
2204
- value = value.replace(/\\/g, "");
2205
- mustUnescape = false;
2206
- }
2207
- push(params, paramName, value);
2208
- if (code === 44) {
2209
- push(offers, extensionName, params);
2210
- params = Object.create(null);
2211
- extensionName = void 0;
2212
- }
2213
- paramName = void 0;
2214
- start = end = -1;
2215
- } else throw new SyntaxError(`Unexpected character at index ${i}`);
2216
- }
2217
- if (start === -1 || inQuotes || code === 32 || code === 9) throw new SyntaxError("Unexpected end of input");
2218
- if (end === -1) end = i;
2219
- const token = header.slice(start, end);
2220
- if (extensionName === void 0) push(offers, token, params);
2221
- else {
2222
- if (paramName === void 0) push(params, token, true);
2223
- else if (mustUnescape) push(params, paramName, token.replace(/\\/g, ""));
2224
- else push(params, paramName, token);
2225
- push(offers, extensionName, params);
2226
- }
2227
- return offers;
2228
- }
2229
- /**
2230
- * Builds the `Sec-WebSocket-Extensions` header field value.
2231
- *
2232
- * @param {Object} extensions The map of extensions and parameters to format
2233
- * @return {String} A string representing the given object
2234
- * @public
2235
- */
2236
- function format(extensions) {
2237
- return Object.keys(extensions).map((extension) => {
2238
- let configurations = extensions[extension];
2239
- if (!Array.isArray(configurations)) configurations = [configurations];
2240
- return configurations.map((params) => {
2241
- return [extension].concat(Object.keys(params).map((k) => {
2242
- let values = params[k];
2243
- if (!Array.isArray(values)) values = [values];
2244
- return values.map((v) => v === true ? k : `${k}=${v}`).join("; ");
2245
- })).join("; ");
2246
- }).join(", ");
2247
- }).join(", ");
2248
- }
2249
- module.exports = {
2250
- format,
2251
- parse
2252
- };
2253
- }));
2254
- //#endregion
2255
- //#region ../../node_modules/ws/lib/websocket.js
2256
- var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2257
- const EventEmitter$1 = __require("events");
2258
- const https = __require("https");
2259
- const http$1 = __require("http");
2260
- const net = __require("net");
2261
- const tls = __require("tls");
2262
- const { randomBytes, createHash: createHash$1 } = __require("crypto");
2263
- const { Duplex: Duplex$2, Readable } = __require("stream");
2264
- const { URL: URL$1 } = __require("url");
2265
- const PerMessageDeflate = require_permessage_deflate();
2266
- const Receiver = require_receiver();
2267
- const Sender = require_sender();
2268
- const { isBlob } = require_validation();
2269
- const { BINARY_TYPES, CLOSE_TIMEOUT, EMPTY_BUFFER, GUID, kForOnEventAttribute, kListener, kStatusCode, kWebSocket, NOOP } = require_constants();
2270
- const { EventTarget: { addEventListener, removeEventListener } } = require_event_target();
2271
- const { format, parse } = require_extension();
2272
- const { toBuffer } = require_buffer_util();
2273
- const kAborted = Symbol("kAborted");
2274
- const protocolVersions = [8, 13];
2275
- const readyStates = [
2276
- "CONNECTING",
2277
- "OPEN",
2278
- "CLOSING",
2279
- "CLOSED"
2280
- ];
2281
- const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
2282
- /**
2283
- * Class representing a WebSocket.
2284
- *
2285
- * @extends EventEmitter
2286
- */
2287
- var WebSocket = class WebSocket extends EventEmitter$1 {
2288
- /**
2289
- * Create a new `WebSocket`.
2290
- *
2291
- * @param {(String|URL)} address The URL to which to connect
2292
- * @param {(String|String[])} [protocols] The subprotocols
2293
- * @param {Object} [options] Connection options
2294
- */
2295
- constructor(address, protocols, options) {
2296
- super();
2297
- this._binaryType = BINARY_TYPES[0];
2298
- this._closeCode = 1006;
2299
- this._closeFrameReceived = false;
2300
- this._closeFrameSent = false;
2301
- this._closeMessage = EMPTY_BUFFER;
2302
- this._closeTimer = null;
2303
- this._errorEmitted = false;
2304
- this._extensions = {};
2305
- this._paused = false;
2306
- this._protocol = "";
2307
- this._readyState = WebSocket.CONNECTING;
2308
- this._receiver = null;
2309
- this._sender = null;
2310
- this._socket = null;
2311
- if (address !== null) {
2312
- this._bufferedAmount = 0;
2313
- this._isServer = false;
2314
- this._redirects = 0;
2315
- if (protocols === void 0) protocols = [];
2316
- else if (!Array.isArray(protocols)) if (typeof protocols === "object" && protocols !== null) {
2317
- options = protocols;
2318
- protocols = [];
2319
- } else protocols = [protocols];
2320
- initAsClient(this, address, protocols, options);
2321
- } else {
2322
- this._autoPong = options.autoPong;
2323
- this._closeTimeout = options.closeTimeout;
2324
- this._isServer = true;
2325
- }
2326
- }
2327
- /**
2328
- * For historical reasons, the custom "nodebuffer" type is used by the default
2329
- * instead of "blob".
2330
- *
2331
- * @type {String}
2332
- */
2333
- get binaryType() {
2334
- return this._binaryType;
2335
- }
2336
- set binaryType(type) {
2337
- if (!BINARY_TYPES.includes(type)) return;
2338
- this._binaryType = type;
2339
- if (this._receiver) this._receiver._binaryType = type;
2340
- }
2341
- /**
2342
- * @type {Number}
2343
- */
2344
- get bufferedAmount() {
2345
- if (!this._socket) return this._bufferedAmount;
2346
- return this._socket._writableState.length + this._sender._bufferedBytes;
2347
- }
2348
- /**
2349
- * @type {String}
2350
- */
2351
- get extensions() {
2352
- return Object.keys(this._extensions).join();
2353
- }
2354
- /**
2355
- * @type {Boolean}
2356
- */
2357
- get isPaused() {
2358
- return this._paused;
2359
- }
2360
- /**
2361
- * @type {Function}
2362
- */
2363
- /* istanbul ignore next */
2364
- get onclose() {
2365
- return null;
2366
- }
2367
- /**
2368
- * @type {Function}
2369
- */
2370
- /* istanbul ignore next */
2371
- get onerror() {
2372
- return null;
2373
- }
2374
- /**
2375
- * @type {Function}
2376
- */
2377
- /* istanbul ignore next */
2378
- get onopen() {
2379
- return null;
2380
- }
2381
- /**
2382
- * @type {Function}
2383
- */
2384
- /* istanbul ignore next */
2385
- get onmessage() {
2386
- return null;
2387
- }
2388
- /**
2389
- * @type {String}
2390
- */
2391
- get protocol() {
2392
- return this._protocol;
2393
- }
2394
- /**
2395
- * @type {Number}
2396
- */
2397
- get readyState() {
2398
- return this._readyState;
2399
- }
2400
- /**
2401
- * @type {String}
2402
- */
2403
- get url() {
2404
- return this._url;
2405
- }
2406
- /**
2407
- * Set up the socket and the internal resources.
2408
- *
2409
- * @param {Duplex} socket The network socket between the server and client
2410
- * @param {Buffer} head The first packet of the upgraded stream
2411
- * @param {Object} options Options object
2412
- * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
2413
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
2414
- * multiple times in the same tick
2415
- * @param {Function} [options.generateMask] The function used to generate the
2416
- * masking key
2417
- * @param {Number} [options.maxPayload=0] The maximum allowed message size
2418
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
2419
- * not to skip UTF-8 validation for text and close messages
2420
- * @private
2421
- */
2422
- setSocket(socket, head, options) {
2423
- const receiver = new Receiver({
2424
- allowSynchronousEvents: options.allowSynchronousEvents,
2425
- binaryType: this.binaryType,
2426
- extensions: this._extensions,
2427
- isServer: this._isServer,
2428
- maxPayload: options.maxPayload,
2429
- skipUTF8Validation: options.skipUTF8Validation
2430
- });
2431
- const sender = new Sender(socket, this._extensions, options.generateMask);
2432
- this._receiver = receiver;
2433
- this._sender = sender;
2434
- this._socket = socket;
2435
- receiver[kWebSocket] = this;
2436
- sender[kWebSocket] = this;
2437
- socket[kWebSocket] = this;
2438
- receiver.on("conclude", receiverOnConclude);
2439
- receiver.on("drain", receiverOnDrain);
2440
- receiver.on("error", receiverOnError);
2441
- receiver.on("message", receiverOnMessage);
2442
- receiver.on("ping", receiverOnPing);
2443
- receiver.on("pong", receiverOnPong);
2444
- sender.onerror = senderOnError;
2445
- if (socket.setTimeout) socket.setTimeout(0);
2446
- if (socket.setNoDelay) socket.setNoDelay();
2447
- if (head.length > 0) socket.unshift(head);
2448
- socket.on("close", socketOnClose);
2449
- socket.on("data", socketOnData);
2450
- socket.on("end", socketOnEnd);
2451
- socket.on("error", socketOnError);
2452
- this._readyState = WebSocket.OPEN;
2453
- this.emit("open");
2454
- }
2455
- /**
2456
- * Emit the `'close'` event.
2457
- *
2458
- * @private
2459
- */
2460
- emitClose() {
2461
- if (!this._socket) {
2462
- this._readyState = WebSocket.CLOSED;
2463
- this.emit("close", this._closeCode, this._closeMessage);
2464
- return;
2465
- }
2466
- if (this._extensions[PerMessageDeflate.extensionName]) this._extensions[PerMessageDeflate.extensionName].cleanup();
2467
- this._receiver.removeAllListeners();
2468
- this._readyState = WebSocket.CLOSED;
2469
- this.emit("close", this._closeCode, this._closeMessage);
2470
- }
2471
- /**
2472
- * Start a closing handshake.
2473
- *
2474
- * +----------+ +-----------+ +----------+
2475
- * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
2476
- * | +----------+ +-----------+ +----------+ |
2477
- * +----------+ +-----------+ |
2478
- * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
2479
- * +----------+ +-----------+ |
2480
- * | | | +---+ |
2481
- * +------------------------+-->|fin| - - - -
2482
- * | +---+ | +---+
2483
- * - - - - -|fin|<---------------------+
2484
- * +---+
2485
- *
2486
- * @param {Number} [code] Status code explaining why the connection is closing
2487
- * @param {(String|Buffer)} [data] The reason why the connection is
2488
- * closing
2489
- * @public
2490
- */
2491
- close(code, data) {
2492
- if (this.readyState === WebSocket.CLOSED) return;
2493
- if (this.readyState === WebSocket.CONNECTING) {
2494
- abortHandshake(this, this._req, "WebSocket was closed before the connection was established");
2495
- return;
2496
- }
2497
- if (this.readyState === WebSocket.CLOSING) {
2498
- if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) this._socket.end();
2499
- return;
2500
- }
2501
- this._readyState = WebSocket.CLOSING;
2502
- this._sender.close(code, data, !this._isServer, (err) => {
2503
- if (err) return;
2504
- this._closeFrameSent = true;
2505
- if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) this._socket.end();
2506
- });
2507
- setCloseTimer(this);
2508
- }
2509
- /**
2510
- * Pause the socket.
2511
- *
2512
- * @public
2513
- */
2514
- pause() {
2515
- if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) return;
2516
- this._paused = true;
2517
- this._socket.pause();
2518
- }
2519
- /**
2520
- * Send a ping.
2521
- *
2522
- * @param {*} [data] The data to send
2523
- * @param {Boolean} [mask] Indicates whether or not to mask `data`
2524
- * @param {Function} [cb] Callback which is executed when the ping is sent
2525
- * @public
2526
- */
2527
- ping(data, mask, cb) {
2528
- if (this.readyState === WebSocket.CONNECTING) throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
2529
- if (typeof data === "function") {
2530
- cb = data;
2531
- data = mask = void 0;
2532
- } else if (typeof mask === "function") {
2533
- cb = mask;
2534
- mask = void 0;
2535
- }
2536
- if (typeof data === "number") data = data.toString();
2537
- if (this.readyState !== WebSocket.OPEN) {
2538
- sendAfterClose(this, data, cb);
2539
- return;
2540
- }
2541
- if (mask === void 0) mask = !this._isServer;
2542
- this._sender.ping(data || EMPTY_BUFFER, mask, cb);
2543
- }
2544
- /**
2545
- * Send a pong.
2546
- *
2547
- * @param {*} [data] The data to send
2548
- * @param {Boolean} [mask] Indicates whether or not to mask `data`
2549
- * @param {Function} [cb] Callback which is executed when the pong is sent
2550
- * @public
2551
- */
2552
- pong(data, mask, cb) {
2553
- if (this.readyState === WebSocket.CONNECTING) throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
2554
- if (typeof data === "function") {
2555
- cb = data;
2556
- data = mask = void 0;
2557
- } else if (typeof mask === "function") {
2558
- cb = mask;
2559
- mask = void 0;
2560
- }
2561
- if (typeof data === "number") data = data.toString();
2562
- if (this.readyState !== WebSocket.OPEN) {
2563
- sendAfterClose(this, data, cb);
2564
- return;
2565
- }
2566
- if (mask === void 0) mask = !this._isServer;
2567
- this._sender.pong(data || EMPTY_BUFFER, mask, cb);
2568
- }
2569
- /**
2570
- * Resume the socket.
2571
- *
2572
- * @public
2573
- */
2574
- resume() {
2575
- if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) return;
2576
- this._paused = false;
2577
- if (!this._receiver._writableState.needDrain) this._socket.resume();
2578
- }
2579
- /**
2580
- * Send a data message.
2581
- *
2582
- * @param {*} data The message to send
2583
- * @param {Object} [options] Options object
2584
- * @param {Boolean} [options.binary] Specifies whether `data` is binary or
2585
- * text
2586
- * @param {Boolean} [options.compress] Specifies whether or not to compress
2587
- * `data`
2588
- * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
2589
- * last one
2590
- * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
2591
- * @param {Function} [cb] Callback which is executed when data is written out
2592
- * @public
2593
- */
2594
- send(data, options, cb) {
2595
- if (this.readyState === WebSocket.CONNECTING) throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
2596
- if (typeof options === "function") {
2597
- cb = options;
2598
- options = {};
2599
- }
2600
- if (typeof data === "number") data = data.toString();
2601
- if (this.readyState !== WebSocket.OPEN) {
2602
- sendAfterClose(this, data, cb);
2603
- return;
2604
- }
2605
- const opts = {
2606
- binary: typeof data !== "string",
2607
- mask: !this._isServer,
2608
- compress: true,
2609
- fin: true,
2610
- ...options
2611
- };
2612
- if (!this._extensions[PerMessageDeflate.extensionName]) opts.compress = false;
2613
- this._sender.send(data || EMPTY_BUFFER, opts, cb);
2614
- }
2615
- /**
2616
- * Forcibly close the connection.
2617
- *
2618
- * @public
2619
- */
2620
- terminate() {
2621
- if (this.readyState === WebSocket.CLOSED) return;
2622
- if (this.readyState === WebSocket.CONNECTING) {
2623
- abortHandshake(this, this._req, "WebSocket was closed before the connection was established");
2624
- return;
2625
- }
2626
- if (this._socket) {
2627
- this._readyState = WebSocket.CLOSING;
2628
- this._socket.destroy();
2629
- }
2630
- }
2631
- };
2632
- /**
2633
- * @constant {Number} CONNECTING
2634
- * @memberof WebSocket
2635
- */
2636
- Object.defineProperty(WebSocket, "CONNECTING", {
2637
- enumerable: true,
2638
- value: readyStates.indexOf("CONNECTING")
2639
- });
2640
- /**
2641
- * @constant {Number} CONNECTING
2642
- * @memberof WebSocket.prototype
2643
- */
2644
- Object.defineProperty(WebSocket.prototype, "CONNECTING", {
2645
- enumerable: true,
2646
- value: readyStates.indexOf("CONNECTING")
2647
- });
2648
- /**
2649
- * @constant {Number} OPEN
2650
- * @memberof WebSocket
2651
- */
2652
- Object.defineProperty(WebSocket, "OPEN", {
2653
- enumerable: true,
2654
- value: readyStates.indexOf("OPEN")
2655
- });
2656
- /**
2657
- * @constant {Number} OPEN
2658
- * @memberof WebSocket.prototype
2659
- */
2660
- Object.defineProperty(WebSocket.prototype, "OPEN", {
2661
- enumerable: true,
2662
- value: readyStates.indexOf("OPEN")
2663
- });
2664
- /**
2665
- * @constant {Number} CLOSING
2666
- * @memberof WebSocket
2667
- */
2668
- Object.defineProperty(WebSocket, "CLOSING", {
2669
- enumerable: true,
2670
- value: readyStates.indexOf("CLOSING")
2671
- });
2672
- /**
2673
- * @constant {Number} CLOSING
2674
- * @memberof WebSocket.prototype
2675
- */
2676
- Object.defineProperty(WebSocket.prototype, "CLOSING", {
2677
- enumerable: true,
2678
- value: readyStates.indexOf("CLOSING")
2679
- });
2680
- /**
2681
- * @constant {Number} CLOSED
2682
- * @memberof WebSocket
2683
- */
2684
- Object.defineProperty(WebSocket, "CLOSED", {
2685
- enumerable: true,
2686
- value: readyStates.indexOf("CLOSED")
2687
- });
2688
- /**
2689
- * @constant {Number} CLOSED
2690
- * @memberof WebSocket.prototype
2691
- */
2692
- Object.defineProperty(WebSocket.prototype, "CLOSED", {
2693
- enumerable: true,
2694
- value: readyStates.indexOf("CLOSED")
2695
- });
2696
- [
2697
- "binaryType",
2698
- "bufferedAmount",
2699
- "extensions",
2700
- "isPaused",
2701
- "protocol",
2702
- "readyState",
2703
- "url"
2704
- ].forEach((property) => {
2705
- Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
2706
- });
2707
- [
2708
- "open",
2709
- "error",
2710
- "close",
2711
- "message"
2712
- ].forEach((method) => {
2713
- Object.defineProperty(WebSocket.prototype, `on${method}`, {
2714
- enumerable: true,
2715
- get() {
2716
- for (const listener of this.listeners(method)) if (listener[kForOnEventAttribute]) return listener[kListener];
2717
- return null;
2718
- },
2719
- set(handler) {
2720
- for (const listener of this.listeners(method)) if (listener[kForOnEventAttribute]) {
2721
- this.removeListener(method, listener);
2722
- break;
2723
- }
2724
- if (typeof handler !== "function") return;
2725
- this.addEventListener(method, handler, { [kForOnEventAttribute]: true });
2726
- }
2727
- });
2728
- });
2729
- WebSocket.prototype.addEventListener = addEventListener;
2730
- WebSocket.prototype.removeEventListener = removeEventListener;
2731
- module.exports = WebSocket;
2732
- /**
2733
- * Initialize a WebSocket client.
2734
- *
2735
- * @param {WebSocket} websocket The client to initialize
2736
- * @param {(String|URL)} address The URL to which to connect
2737
- * @param {Array} protocols The subprotocols
2738
- * @param {Object} [options] Connection options
2739
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any
2740
- * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
2741
- * times in the same tick
2742
- * @param {Boolean} [options.autoPong=true] Specifies whether or not to
2743
- * automatically send a pong in response to a ping
2744
- * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait
2745
- * for the closing handshake to finish after `websocket.close()` is called
2746
- * @param {Function} [options.finishRequest] A function which can be used to
2747
- * customize the headers of each http request before it is sent
2748
- * @param {Boolean} [options.followRedirects=false] Whether or not to follow
2749
- * redirects
2750
- * @param {Function} [options.generateMask] The function used to generate the
2751
- * masking key
2752
- * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
2753
- * handshake request
2754
- * @param {Number} [options.maxPayload=104857600] The maximum allowed message
2755
- * size
2756
- * @param {Number} [options.maxRedirects=10] The maximum number of redirects
2757
- * allowed
2758
- * @param {String} [options.origin] Value of the `Origin` or
2759
- * `Sec-WebSocket-Origin` header
2760
- * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
2761
- * permessage-deflate
2762
- * @param {Number} [options.protocolVersion=13] Value of the
2763
- * `Sec-WebSocket-Version` header
2764
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
2765
- * not to skip UTF-8 validation for text and close messages
2766
- * @private
2767
- */
2768
- function initAsClient(websocket, address, protocols, options) {
2769
- const opts = {
2770
- allowSynchronousEvents: true,
2771
- autoPong: true,
2772
- closeTimeout: CLOSE_TIMEOUT,
2773
- protocolVersion: protocolVersions[1],
2774
- maxPayload: 100 * 1024 * 1024,
2775
- skipUTF8Validation: false,
2776
- perMessageDeflate: true,
2777
- followRedirects: false,
2778
- maxRedirects: 10,
2779
- ...options,
2780
- socketPath: void 0,
2781
- hostname: void 0,
2782
- protocol: void 0,
2783
- timeout: void 0,
2784
- method: "GET",
2785
- host: void 0,
2786
- path: void 0,
2787
- port: void 0
2788
- };
2789
- websocket._autoPong = opts.autoPong;
2790
- websocket._closeTimeout = opts.closeTimeout;
2791
- if (!protocolVersions.includes(opts.protocolVersion)) throw new RangeError(`Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})`);
2792
- let parsedUrl;
2793
- if (address instanceof URL$1) parsedUrl = address;
2794
- else try {
2795
- parsedUrl = new URL$1(address);
2796
- } catch {
2797
- throw new SyntaxError(`Invalid URL: ${address}`);
2798
- }
2799
- if (parsedUrl.protocol === "http:") parsedUrl.protocol = "ws:";
2800
- else if (parsedUrl.protocol === "https:") parsedUrl.protocol = "wss:";
2801
- websocket._url = parsedUrl.href;
2802
- const isSecure = parsedUrl.protocol === "wss:";
2803
- const isIpcUrl = parsedUrl.protocol === "ws+unix:";
2804
- let invalidUrlMessage;
2805
- if (parsedUrl.protocol !== "ws:" && !isSecure && !isIpcUrl) invalidUrlMessage = "The URL's protocol must be one of \"ws:\", \"wss:\", \"http:\", \"https:\", or \"ws+unix:\"";
2806
- else if (isIpcUrl && !parsedUrl.pathname) invalidUrlMessage = "The URL's pathname is empty";
2807
- else if (parsedUrl.hash) invalidUrlMessage = "The URL contains a fragment identifier";
2808
- if (invalidUrlMessage) {
2809
- const err = new SyntaxError(invalidUrlMessage);
2810
- if (websocket._redirects === 0) throw err;
2811
- else {
2812
- emitErrorAndClose(websocket, err);
2813
- return;
2814
- }
2815
- }
2816
- const defaultPort = isSecure ? 443 : 80;
2817
- const key = randomBytes(16).toString("base64");
2818
- const request = isSecure ? https.request : http$1.request;
2819
- const protocolSet = /* @__PURE__ */ new Set();
2820
- let perMessageDeflate;
2821
- opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
2822
- opts.defaultPort = opts.defaultPort || defaultPort;
2823
- opts.port = parsedUrl.port || defaultPort;
2824
- opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname;
2825
- opts.headers = {
2826
- ...opts.headers,
2827
- "Sec-WebSocket-Version": opts.protocolVersion,
2828
- "Sec-WebSocket-Key": key,
2829
- Connection: "Upgrade",
2830
- Upgrade: "websocket"
2831
- };
2832
- opts.path = parsedUrl.pathname + parsedUrl.search;
2833
- opts.timeout = opts.handshakeTimeout;
2834
- if (opts.perMessageDeflate) {
2835
- perMessageDeflate = new PerMessageDeflate({
2836
- ...opts.perMessageDeflate,
2837
- isServer: false,
2838
- maxPayload: opts.maxPayload
2839
- });
2840
- opts.headers["Sec-WebSocket-Extensions"] = format({ [PerMessageDeflate.extensionName]: perMessageDeflate.offer() });
2841
- }
2842
- if (protocols.length) {
2843
- for (const protocol of protocols) {
2844
- if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) throw new SyntaxError("An invalid or duplicated subprotocol was specified");
2845
- protocolSet.add(protocol);
2846
- }
2847
- opts.headers["Sec-WebSocket-Protocol"] = protocols.join(",");
2848
- }
2849
- if (opts.origin) if (opts.protocolVersion < 13) opts.headers["Sec-WebSocket-Origin"] = opts.origin;
2850
- else opts.headers.Origin = opts.origin;
2851
- if (parsedUrl.username || parsedUrl.password) opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
2852
- if (isIpcUrl) {
2853
- const parts = opts.path.split(":");
2854
- opts.socketPath = parts[0];
2855
- opts.path = parts[1];
2856
- }
2857
- let req;
2858
- if (opts.followRedirects) {
2859
- if (websocket._redirects === 0) {
2860
- websocket._originalIpc = isIpcUrl;
2861
- websocket._originalSecure = isSecure;
2862
- websocket._originalHostOrSocketPath = isIpcUrl ? opts.socketPath : parsedUrl.host;
2863
- const headers = options && options.headers;
2864
- options = {
2865
- ...options,
2866
- headers: {}
2867
- };
2868
- if (headers) for (const [key, value] of Object.entries(headers)) options.headers[key.toLowerCase()] = value;
2869
- } else if (websocket.listenerCount("redirect") === 0) {
2870
- const isSameHost = isIpcUrl ? websocket._originalIpc ? opts.socketPath === websocket._originalHostOrSocketPath : false : websocket._originalIpc ? false : parsedUrl.host === websocket._originalHostOrSocketPath;
2871
- if (!isSameHost || websocket._originalSecure && !isSecure) {
2872
- delete opts.headers.authorization;
2873
- delete opts.headers.cookie;
2874
- if (!isSameHost) delete opts.headers.host;
2875
- opts.auth = void 0;
2876
- }
2877
- }
2878
- if (opts.auth && !options.headers.authorization) options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64");
2879
- req = websocket._req = request(opts);
2880
- if (websocket._redirects) websocket.emit("redirect", websocket.url, req);
2881
- } else req = websocket._req = request(opts);
2882
- if (opts.timeout) req.on("timeout", () => {
2883
- abortHandshake(websocket, req, "Opening handshake has timed out");
2884
- });
2885
- req.on("error", (err) => {
2886
- if (req === null || req[kAborted]) return;
2887
- req = websocket._req = null;
2888
- emitErrorAndClose(websocket, err);
2889
- });
2890
- req.on("response", (res) => {
2891
- const location = res.headers.location;
2892
- const statusCode = res.statusCode;
2893
- if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) {
2894
- if (++websocket._redirects > opts.maxRedirects) {
2895
- abortHandshake(websocket, req, "Maximum redirects exceeded");
2896
- return;
2897
- }
2898
- req.abort();
2899
- let addr;
2900
- try {
2901
- addr = new URL$1(location, address);
2902
- } catch (e) {
2903
- emitErrorAndClose(websocket, /* @__PURE__ */ new SyntaxError(`Invalid URL: ${location}`));
2904
- return;
2905
- }
2906
- initAsClient(websocket, addr, protocols, options);
2907
- } else if (!websocket.emit("unexpected-response", req, res)) abortHandshake(websocket, req, `Unexpected server response: ${res.statusCode}`);
2908
- });
2909
- req.on("upgrade", (res, socket, head) => {
2910
- websocket.emit("upgrade", res);
2911
- if (websocket.readyState !== WebSocket.CONNECTING) return;
2912
- req = websocket._req = null;
2913
- const upgrade = res.headers.upgrade;
2914
- if (upgrade === void 0 || upgrade.toLowerCase() !== "websocket") {
2915
- abortHandshake(websocket, socket, "Invalid Upgrade header");
2916
- return;
2917
- }
2918
- const digest = createHash$1("sha1").update(key + GUID).digest("base64");
2919
- if (res.headers["sec-websocket-accept"] !== digest) {
2920
- abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2921
- return;
2922
- }
2923
- const serverProt = res.headers["sec-websocket-protocol"];
2924
- let protError;
2925
- if (serverProt !== void 0) {
2926
- if (!protocolSet.size) protError = "Server sent a subprotocol but none was requested";
2927
- else if (!protocolSet.has(serverProt)) protError = "Server sent an invalid subprotocol";
2928
- } else if (protocolSet.size) protError = "Server sent no subprotocol";
2929
- if (protError) {
2930
- abortHandshake(websocket, socket, protError);
2931
- return;
2932
- }
2933
- if (serverProt) websocket._protocol = serverProt;
2934
- const secWebSocketExtensions = res.headers["sec-websocket-extensions"];
2935
- if (secWebSocketExtensions !== void 0) {
2936
- if (!perMessageDeflate) {
2937
- abortHandshake(websocket, socket, "Server sent a Sec-WebSocket-Extensions header but no extension was requested");
2938
- return;
2939
- }
2940
- let extensions;
2941
- try {
2942
- extensions = parse(secWebSocketExtensions);
2943
- } catch (err) {
2944
- abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Extensions header");
2945
- return;
2946
- }
2947
- const extensionNames = Object.keys(extensions);
2948
- if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) {
2949
- abortHandshake(websocket, socket, "Server indicated an extension that was not requested");
2950
- return;
2951
- }
2952
- try {
2953
- perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
2954
- } catch (err) {
2955
- abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Extensions header");
2956
- return;
2957
- }
2958
- websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
2959
- }
2960
- websocket.setSocket(socket, head, {
2961
- allowSynchronousEvents: opts.allowSynchronousEvents,
2962
- generateMask: opts.generateMask,
2963
- maxPayload: opts.maxPayload,
2964
- skipUTF8Validation: opts.skipUTF8Validation
2965
- });
2966
- });
2967
- if (opts.finishRequest) opts.finishRequest(req, websocket);
2968
- else req.end();
2969
- }
2970
- /**
2971
- * Emit the `'error'` and `'close'` events.
2972
- *
2973
- * @param {WebSocket} websocket The WebSocket instance
2974
- * @param {Error} The error to emit
2975
- * @private
2976
- */
2977
- function emitErrorAndClose(websocket, err) {
2978
- websocket._readyState = WebSocket.CLOSING;
2979
- websocket._errorEmitted = true;
2980
- websocket.emit("error", err);
2981
- websocket.emitClose();
2982
- }
2983
- /**
2984
- * Create a `net.Socket` and initiate a connection.
2985
- *
2986
- * @param {Object} options Connection options
2987
- * @return {net.Socket} The newly created socket used to start the connection
2988
- * @private
2989
- */
2990
- function netConnect(options) {
2991
- options.path = options.socketPath;
2992
- return net.connect(options);
2993
- }
2994
- /**
2995
- * Create a `tls.TLSSocket` and initiate a connection.
2996
- *
2997
- * @param {Object} options Connection options
2998
- * @return {tls.TLSSocket} The newly created socket used to start the connection
2999
- * @private
3000
- */
3001
- function tlsConnect(options) {
3002
- options.path = void 0;
3003
- if (!options.servername && options.servername !== "") options.servername = net.isIP(options.host) ? "" : options.host;
3004
- return tls.connect(options);
3005
- }
3006
- /**
3007
- * Abort the handshake and emit an error.
3008
- *
3009
- * @param {WebSocket} websocket The WebSocket instance
3010
- * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
3011
- * abort or the socket to destroy
3012
- * @param {String} message The error message
3013
- * @private
3014
- */
3015
- function abortHandshake(websocket, stream, message) {
3016
- websocket._readyState = WebSocket.CLOSING;
3017
- const err = new Error(message);
3018
- Error.captureStackTrace(err, abortHandshake);
3019
- if (stream.setHeader) {
3020
- stream[kAborted] = true;
3021
- stream.abort();
3022
- if (stream.socket && !stream.socket.destroyed) stream.socket.destroy();
3023
- process.nextTick(emitErrorAndClose, websocket, err);
3024
- } else {
3025
- stream.destroy(err);
3026
- stream.once("error", websocket.emit.bind(websocket, "error"));
3027
- stream.once("close", websocket.emitClose.bind(websocket));
3028
- }
3029
- }
3030
- /**
3031
- * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
3032
- * when the `readyState` attribute is `CLOSING` or `CLOSED`.
3033
- *
3034
- * @param {WebSocket} websocket The WebSocket instance
3035
- * @param {*} [data] The data to send
3036
- * @param {Function} [cb] Callback
3037
- * @private
3038
- */
3039
- function sendAfterClose(websocket, data, cb) {
3040
- if (data) {
3041
- const length = isBlob(data) ? data.size : toBuffer(data).length;
3042
- if (websocket._socket) websocket._sender._bufferedBytes += length;
3043
- else websocket._bufferedAmount += length;
3044
- }
3045
- if (cb) {
3046
- const err = /* @__PURE__ */ new Error(`WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})`);
3047
- process.nextTick(cb, err);
3048
- }
3049
- }
3050
- /**
3051
- * The listener of the `Receiver` `'conclude'` event.
3052
- *
3053
- * @param {Number} code The status code
3054
- * @param {Buffer} reason The reason for closing
3055
- * @private
3056
- */
3057
- function receiverOnConclude(code, reason) {
3058
- const websocket = this[kWebSocket];
3059
- websocket._closeFrameReceived = true;
3060
- websocket._closeMessage = reason;
3061
- websocket._closeCode = code;
3062
- if (websocket._socket[kWebSocket] === void 0) return;
3063
- websocket._socket.removeListener("data", socketOnData);
3064
- process.nextTick(resume, websocket._socket);
3065
- if (code === 1005) websocket.close();
3066
- else websocket.close(code, reason);
3067
- }
3068
- /**
3069
- * The listener of the `Receiver` `'drain'` event.
3070
- *
3071
- * @private
3072
- */
3073
- function receiverOnDrain() {
3074
- const websocket = this[kWebSocket];
3075
- if (!websocket.isPaused) websocket._socket.resume();
3076
- }
3077
- /**
3078
- * The listener of the `Receiver` `'error'` event.
3079
- *
3080
- * @param {(RangeError|Error)} err The emitted error
3081
- * @private
3082
- */
3083
- function receiverOnError(err) {
3084
- const websocket = this[kWebSocket];
3085
- if (websocket._socket[kWebSocket] !== void 0) {
3086
- websocket._socket.removeListener("data", socketOnData);
3087
- process.nextTick(resume, websocket._socket);
3088
- websocket.close(err[kStatusCode]);
3089
- }
3090
- if (!websocket._errorEmitted) {
3091
- websocket._errorEmitted = true;
3092
- websocket.emit("error", err);
3093
- }
3094
- }
3095
- /**
3096
- * The listener of the `Receiver` `'finish'` event.
3097
- *
3098
- * @private
3099
- */
3100
- function receiverOnFinish() {
3101
- this[kWebSocket].emitClose();
3102
- }
3103
- /**
3104
- * The listener of the `Receiver` `'message'` event.
3105
- *
3106
- * @param {Buffer|ArrayBuffer|Buffer[])} data The message
3107
- * @param {Boolean} isBinary Specifies whether the message is binary or not
3108
- * @private
3109
- */
3110
- function receiverOnMessage(data, isBinary) {
3111
- this[kWebSocket].emit("message", data, isBinary);
3112
- }
3113
- /**
3114
- * The listener of the `Receiver` `'ping'` event.
3115
- *
3116
- * @param {Buffer} data The data included in the ping frame
3117
- * @private
3118
- */
3119
- function receiverOnPing(data) {
3120
- const websocket = this[kWebSocket];
3121
- if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
3122
- websocket.emit("ping", data);
3123
- }
3124
- /**
3125
- * The listener of the `Receiver` `'pong'` event.
3126
- *
3127
- * @param {Buffer} data The data included in the pong frame
3128
- * @private
3129
- */
3130
- function receiverOnPong(data) {
3131
- this[kWebSocket].emit("pong", data);
3132
- }
3133
- /**
3134
- * Resume a readable stream
3135
- *
3136
- * @param {Readable} stream The readable stream
3137
- * @private
3138
- */
3139
- function resume(stream) {
3140
- stream.resume();
3141
- }
3142
- /**
3143
- * The `Sender` error event handler.
3144
- *
3145
- * @param {Error} The error
3146
- * @private
3147
- */
3148
- function senderOnError(err) {
3149
- const websocket = this[kWebSocket];
3150
- if (websocket.readyState === WebSocket.CLOSED) return;
3151
- if (websocket.readyState === WebSocket.OPEN) {
3152
- websocket._readyState = WebSocket.CLOSING;
3153
- setCloseTimer(websocket);
3154
- }
3155
- this._socket.end();
3156
- if (!websocket._errorEmitted) {
3157
- websocket._errorEmitted = true;
3158
- websocket.emit("error", err);
3159
- }
3160
- }
3161
- /**
3162
- * Set a timer to destroy the underlying raw socket of a WebSocket.
3163
- *
3164
- * @param {WebSocket} websocket The WebSocket instance
3165
- * @private
3166
- */
3167
- function setCloseTimer(websocket) {
3168
- websocket._closeTimer = setTimeout(websocket._socket.destroy.bind(websocket._socket), websocket._closeTimeout);
3169
- }
3170
- /**
3171
- * The listener of the socket `'close'` event.
3172
- *
3173
- * @private
3174
- */
3175
- function socketOnClose() {
3176
- const websocket = this[kWebSocket];
3177
- this.removeListener("close", socketOnClose);
3178
- this.removeListener("data", socketOnData);
3179
- this.removeListener("end", socketOnEnd);
3180
- websocket._readyState = WebSocket.CLOSING;
3181
- if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && this._readableState.length !== 0) {
3182
- const chunk = this.read(this._readableState.length);
3183
- websocket._receiver.write(chunk);
3184
- }
3185
- websocket._receiver.end();
3186
- this[kWebSocket] = void 0;
3187
- clearTimeout(websocket._closeTimer);
3188
- if (websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted) websocket.emitClose();
3189
- else {
3190
- websocket._receiver.on("error", receiverOnFinish);
3191
- websocket._receiver.on("finish", receiverOnFinish);
3192
- }
3193
- }
3194
- /**
3195
- * The listener of the socket `'data'` event.
3196
- *
3197
- * @param {Buffer} chunk A chunk of data
3198
- * @private
3199
- */
3200
- function socketOnData(chunk) {
3201
- if (!this[kWebSocket]._receiver.write(chunk)) this.pause();
3202
- }
3203
- /**
3204
- * The listener of the socket `'end'` event.
3205
- *
3206
- * @private
3207
- */
3208
- function socketOnEnd() {
3209
- const websocket = this[kWebSocket];
3210
- websocket._readyState = WebSocket.CLOSING;
3211
- websocket._receiver.end();
3212
- this.end();
3213
- }
3214
- /**
3215
- * The listener of the socket `'error'` event.
3216
- *
3217
- * @private
3218
- */
3219
- function socketOnError() {
3220
- const websocket = this[kWebSocket];
3221
- this.removeListener("error", socketOnError);
3222
- this.on("error", NOOP);
3223
- if (websocket) {
3224
- websocket._readyState = WebSocket.CLOSING;
3225
- this.destroy();
3226
- }
3227
- }
3228
- }));
3229
- //#endregion
3230
- //#region ../../node_modules/ws/lib/stream.js
3231
- var require_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
3232
- require_websocket();
3233
- const { Duplex: Duplex$1 } = __require("stream");
3234
- /**
3235
- * Emits the `'close'` event on a stream.
3236
- *
3237
- * @param {Duplex} stream The stream.
3238
- * @private
3239
- */
3240
- function emitClose(stream) {
3241
- stream.emit("close");
3242
- }
3243
- /**
3244
- * The listener of the `'end'` event.
3245
- *
3246
- * @private
3247
- */
3248
- function duplexOnEnd() {
3249
- if (!this.destroyed && this._writableState.finished) this.destroy();
3250
- }
3251
- /**
3252
- * The listener of the `'error'` event.
3253
- *
3254
- * @param {Error} err The error
3255
- * @private
3256
- */
3257
- function duplexOnError(err) {
3258
- this.removeListener("error", duplexOnError);
3259
- this.destroy();
3260
- if (this.listenerCount("error") === 0) this.emit("error", err);
3261
- }
3262
- /**
3263
- * Wraps a `WebSocket` in a duplex stream.
3264
- *
3265
- * @param {WebSocket} ws The `WebSocket` to wrap
3266
- * @param {Object} [options] The options for the `Duplex` constructor
3267
- * @return {Duplex} The duplex stream
3268
- * @public
3269
- */
3270
- function createWebSocketStream(ws, options) {
3271
- let terminateOnDestroy = true;
3272
- const duplex = new Duplex$1({
3273
- ...options,
3274
- autoDestroy: false,
3275
- emitClose: false,
3276
- objectMode: false,
3277
- writableObjectMode: false
3278
- });
3279
- ws.on("message", function message(msg, isBinary) {
3280
- const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
3281
- if (!duplex.push(data)) ws.pause();
3282
- });
3283
- ws.once("error", function error(err) {
3284
- if (duplex.destroyed) return;
3285
- terminateOnDestroy = false;
3286
- duplex.destroy(err);
3287
- });
3288
- ws.once("close", function close() {
3289
- if (duplex.destroyed) return;
3290
- duplex.push(null);
3291
- });
3292
- duplex._destroy = function(err, callback) {
3293
- if (ws.readyState === ws.CLOSED) {
3294
- callback(err);
3295
- process.nextTick(emitClose, duplex);
3296
- return;
3297
- }
3298
- let called = false;
3299
- ws.once("error", function error(err) {
3300
- called = true;
3301
- callback(err);
3302
- });
3303
- ws.once("close", function close() {
3304
- if (!called) callback(err);
3305
- process.nextTick(emitClose, duplex);
3306
- });
3307
- if (terminateOnDestroy) ws.terminate();
3308
- };
3309
- duplex._final = function(callback) {
3310
- if (ws.readyState === ws.CONNECTING) {
3311
- ws.once("open", function open() {
3312
- duplex._final(callback);
3313
- });
3314
- return;
3315
- }
3316
- if (ws._socket === null) return;
3317
- if (ws._socket._writableState.finished) {
3318
- callback();
3319
- if (duplex._readableState.endEmitted) duplex.destroy();
3320
- } else {
3321
- ws._socket.once("finish", function finish() {
3322
- callback();
3323
- });
3324
- ws.close();
3325
- }
3326
- };
3327
- duplex._read = function() {
3328
- if (ws.isPaused) ws.resume();
3329
- };
3330
- duplex._write = function(chunk, encoding, callback) {
3331
- if (ws.readyState === ws.CONNECTING) {
3332
- ws.once("open", function open() {
3333
- duplex._write(chunk, encoding, callback);
3334
- });
3335
- return;
3336
- }
3337
- ws.send(chunk, callback);
3338
- };
3339
- duplex.on("end", duplexOnEnd);
3340
- duplex.on("error", duplexOnError);
3341
- return duplex;
3342
- }
3343
- module.exports = createWebSocketStream;
3344
- }));
3345
- //#endregion
3346
- //#region ../../node_modules/ws/lib/subprotocol.js
3347
- var require_subprotocol = /* @__PURE__ */ __commonJSMin(((exports, module) => {
3348
- const { tokenChars } = require_validation();
3349
- /**
3350
- * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
3351
- *
3352
- * @param {String} header The field value of the header
3353
- * @return {Set} The subprotocol names
3354
- * @public
3355
- */
3356
- function parse(header) {
3357
- const protocols = /* @__PURE__ */ new Set();
3358
- let start = -1;
3359
- let end = -1;
3360
- let i = 0;
3361
- for (; i < header.length; i++) {
3362
- const code = header.charCodeAt(i);
3363
- if (end === -1 && tokenChars[code] === 1) {
3364
- if (start === -1) start = i;
3365
- } else if (i !== 0 && (code === 32 || code === 9)) {
3366
- if (end === -1 && start !== -1) end = i;
3367
- } else if (code === 44) {
3368
- if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
3369
- if (end === -1) end = i;
3370
- const protocol = header.slice(start, end);
3371
- if (protocols.has(protocol)) throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
3372
- protocols.add(protocol);
3373
- start = end = -1;
3374
- } else throw new SyntaxError(`Unexpected character at index ${i}`);
3375
- }
3376
- if (start === -1 || end !== -1) throw new SyntaxError("Unexpected end of input");
3377
- const protocol = header.slice(start, i);
3378
- if (protocols.has(protocol)) throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
3379
- protocols.add(protocol);
3380
- return protocols;
3381
- }
3382
- module.exports = { parse };
3383
- }));
3384
- //#endregion
3385
- //#region ../../node_modules/ws/lib/websocket-server.js
3386
- var require_websocket_server = /* @__PURE__ */ __commonJSMin(((exports, module) => {
3387
- const EventEmitter = __require("events");
3388
- const http = __require("http");
3389
- const { Duplex } = __require("stream");
3390
- const { createHash } = __require("crypto");
3391
- const extension = require_extension();
3392
- const PerMessageDeflate = require_permessage_deflate();
3393
- const subprotocol = require_subprotocol();
3394
- const WebSocket = require_websocket();
3395
- const { CLOSE_TIMEOUT, GUID, kWebSocket } = require_constants();
3396
- const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
3397
- const RUNNING = 0;
3398
- const CLOSING = 1;
3399
- const CLOSED = 2;
3400
- /**
3401
- * Class representing a WebSocket server.
3402
- *
3403
- * @extends EventEmitter
3404
- */
3405
- var WebSocketServer = class extends EventEmitter {
3406
- /**
3407
- * Create a `WebSocketServer` instance.
3408
- *
3409
- * @param {Object} options Configuration options
3410
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
3411
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
3412
- * multiple times in the same tick
3413
- * @param {Boolean} [options.autoPong=true] Specifies whether or not to
3414
- * automatically send a pong in response to a ping
3415
- * @param {Number} [options.backlog=511] The maximum length of the queue of
3416
- * pending connections
3417
- * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
3418
- * track clients
3419
- * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to
3420
- * wait for the closing handshake to finish after `websocket.close()` is
3421
- * called
3422
- * @param {Function} [options.handleProtocols] A hook to handle protocols
3423
- * @param {String} [options.host] The hostname where to bind the server
3424
- * @param {Number} [options.maxPayload=104857600] The maximum allowed message
3425
- * size
3426
- * @param {Boolean} [options.noServer=false] Enable no server mode
3427
- * @param {String} [options.path] Accept only connections matching this path
3428
- * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
3429
- * permessage-deflate
3430
- * @param {Number} [options.port] The port where to bind the server
3431
- * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
3432
- * server to use
3433
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
3434
- * not to skip UTF-8 validation for text and close messages
3435
- * @param {Function} [options.verifyClient] A hook to reject connections
3436
- * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
3437
- * class to use. It must be the `WebSocket` class or class that extends it
3438
- * @param {Function} [callback] A listener for the `listening` event
3439
- */
3440
- constructor(options, callback) {
3441
- super();
3442
- options = {
3443
- allowSynchronousEvents: true,
3444
- autoPong: true,
3445
- maxPayload: 100 * 1024 * 1024,
3446
- skipUTF8Validation: false,
3447
- perMessageDeflate: false,
3448
- handleProtocols: null,
3449
- clientTracking: true,
3450
- closeTimeout: CLOSE_TIMEOUT,
3451
- verifyClient: null,
3452
- noServer: false,
3453
- backlog: null,
3454
- server: null,
3455
- host: null,
3456
- path: null,
3457
- port: null,
3458
- WebSocket,
3459
- ...options
3460
- };
3461
- if (options.port == null && !options.server && !options.noServer || options.port != null && (options.server || options.noServer) || options.server && options.noServer) throw new TypeError("One and only one of the \"port\", \"server\", or \"noServer\" options must be specified");
3462
- if (options.port != null) {
3463
- this._server = http.createServer((req, res) => {
3464
- const body = http.STATUS_CODES[426];
3465
- res.writeHead(426, {
3466
- "Content-Length": body.length,
3467
- "Content-Type": "text/plain"
3468
- });
3469
- res.end(body);
3470
- });
3471
- this._server.listen(options.port, options.host, options.backlog, callback);
3472
- } else if (options.server) this._server = options.server;
3473
- if (this._server) {
3474
- const emitConnection = this.emit.bind(this, "connection");
3475
- this._removeListeners = addListeners(this._server, {
3476
- listening: this.emit.bind(this, "listening"),
3477
- error: this.emit.bind(this, "error"),
3478
- upgrade: (req, socket, head) => {
3479
- this.handleUpgrade(req, socket, head, emitConnection);
3480
- }
3481
- });
3482
- }
3483
- if (options.perMessageDeflate === true) options.perMessageDeflate = {};
3484
- if (options.clientTracking) {
3485
- this.clients = /* @__PURE__ */ new Set();
3486
- this._shouldEmitClose = false;
3487
- }
3488
- this.options = options;
3489
- this._state = RUNNING;
3490
- }
3491
- /**
3492
- * Returns the bound address, the address family name, and port of the server
3493
- * as reported by the operating system if listening on an IP socket.
3494
- * If the server is listening on a pipe or UNIX domain socket, the name is
3495
- * returned as a string.
3496
- *
3497
- * @return {(Object|String|null)} The address of the server
3498
- * @public
3499
- */
3500
- address() {
3501
- if (this.options.noServer) throw new Error("The server is operating in \"noServer\" mode");
3502
- if (!this._server) return null;
3503
- return this._server.address();
3504
- }
3505
- /**
3506
- * Stop the server from accepting new connections and emit the `'close'` event
3507
- * when all existing connections are closed.
3508
- *
3509
- * @param {Function} [cb] A one-time listener for the `'close'` event
3510
- * @public
3511
- */
3512
- close(cb) {
3513
- if (this._state === CLOSED) {
3514
- if (cb) this.once("close", () => {
3515
- cb(/* @__PURE__ */ new Error("The server is not running"));
3516
- });
3517
- process.nextTick(emitClose, this);
3518
- return;
3519
- }
3520
- if (cb) this.once("close", cb);
3521
- if (this._state === CLOSING) return;
3522
- this._state = CLOSING;
3523
- if (this.options.noServer || this.options.server) {
3524
- if (this._server) {
3525
- this._removeListeners();
3526
- this._removeListeners = this._server = null;
3527
- }
3528
- if (this.clients) if (!this.clients.size) process.nextTick(emitClose, this);
3529
- else this._shouldEmitClose = true;
3530
- else process.nextTick(emitClose, this);
3531
- } else {
3532
- const server = this._server;
3533
- this._removeListeners();
3534
- this._removeListeners = this._server = null;
3535
- server.close(() => {
3536
- emitClose(this);
3537
- });
3538
- }
3539
- }
3540
- /**
3541
- * See if a given request should be handled by this server instance.
3542
- *
3543
- * @param {http.IncomingMessage} req Request object to inspect
3544
- * @return {Boolean} `true` if the request is valid, else `false`
3545
- * @public
3546
- */
3547
- shouldHandle(req) {
3548
- if (this.options.path) {
3549
- const index = req.url.indexOf("?");
3550
- if ((index !== -1 ? req.url.slice(0, index) : req.url) !== this.options.path) return false;
3551
- }
3552
- return true;
3553
- }
3554
- /**
3555
- * Handle a HTTP Upgrade request.
3556
- *
3557
- * @param {http.IncomingMessage} req The request object
3558
- * @param {Duplex} socket The network socket between the server and client
3559
- * @param {Buffer} head The first packet of the upgraded stream
3560
- * @param {Function} cb Callback
3561
- * @public
3562
- */
3563
- handleUpgrade(req, socket, head, cb) {
3564
- socket.on("error", socketOnError);
3565
- const key = req.headers["sec-websocket-key"];
3566
- const upgrade = req.headers.upgrade;
3567
- const version = +req.headers["sec-websocket-version"];
3568
- if (req.method !== "GET") {
3569
- abortHandshakeOrEmitwsClientError(this, req, socket, 405, "Invalid HTTP method");
3570
- return;
3571
- }
3572
- if (upgrade === void 0 || upgrade.toLowerCase() !== "websocket") {
3573
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Invalid Upgrade header");
3574
- return;
3575
- }
3576
- if (key === void 0 || !keyRegex.test(key)) {
3577
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Missing or invalid Sec-WebSocket-Key header");
3578
- return;
3579
- }
3580
- if (version !== 13 && version !== 8) {
3581
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Missing or invalid Sec-WebSocket-Version header", { "Sec-WebSocket-Version": "13, 8" });
3582
- return;
3583
- }
3584
- if (!this.shouldHandle(req)) {
3585
- abortHandshake(socket, 400);
3586
- return;
3587
- }
3588
- const secWebSocketProtocol = req.headers["sec-websocket-protocol"];
3589
- let protocols = /* @__PURE__ */ new Set();
3590
- if (secWebSocketProtocol !== void 0) try {
3591
- protocols = subprotocol.parse(secWebSocketProtocol);
3592
- } catch (err) {
3593
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Invalid Sec-WebSocket-Protocol header");
3594
- return;
3595
- }
3596
- const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
3597
- const extensions = {};
3598
- if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) {
3599
- const perMessageDeflate = new PerMessageDeflate({
3600
- ...this.options.perMessageDeflate,
3601
- isServer: true,
3602
- maxPayload: this.options.maxPayload
3603
- });
3604
- try {
3605
- const offers = extension.parse(secWebSocketExtensions);
3606
- if (offers[PerMessageDeflate.extensionName]) {
3607
- perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
3608
- extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
3609
- }
3610
- } catch (err) {
3611
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Invalid or unacceptable Sec-WebSocket-Extensions header");
3612
- return;
3613
- }
3614
- }
3615
- if (this.options.verifyClient) {
3616
- const info = {
3617
- origin: req.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`],
3618
- secure: !!(req.socket.authorized || req.socket.encrypted),
3619
- req
3620
- };
3621
- if (this.options.verifyClient.length === 2) {
3622
- this.options.verifyClient(info, (verified, code, message, headers) => {
3623
- if (!verified) return abortHandshake(socket, code || 401, message, headers);
3624
- this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
3625
- });
3626
- return;
3627
- }
3628
- if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
3629
- }
3630
- this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
3631
- }
3632
- /**
3633
- * Upgrade the connection to WebSocket.
3634
- *
3635
- * @param {Object} extensions The accepted extensions
3636
- * @param {String} key The value of the `Sec-WebSocket-Key` header
3637
- * @param {Set} protocols The subprotocols
3638
- * @param {http.IncomingMessage} req The request object
3639
- * @param {Duplex} socket The network socket between the server and client
3640
- * @param {Buffer} head The first packet of the upgraded stream
3641
- * @param {Function} cb Callback
3642
- * @throws {Error} If called more than once with the same socket
3643
- * @private
3644
- */
3645
- completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
3646
- if (!socket.readable || !socket.writable) return socket.destroy();
3647
- if (socket[kWebSocket]) throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");
3648
- if (this._state > RUNNING) return abortHandshake(socket, 503);
3649
- const headers = [
3650
- "HTTP/1.1 101 Switching Protocols",
3651
- "Upgrade: websocket",
3652
- "Connection: Upgrade",
3653
- `Sec-WebSocket-Accept: ${createHash("sha1").update(key + GUID).digest("base64")}`
3654
- ];
3655
- const ws = new this.options.WebSocket(null, void 0, this.options);
3656
- if (protocols.size) {
3657
- const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value;
3658
- if (protocol) {
3659
- headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
3660
- ws._protocol = protocol;
3661
- }
3662
- }
3663
- if (extensions[PerMessageDeflate.extensionName]) {
3664
- const params = extensions[PerMessageDeflate.extensionName].params;
3665
- const value = extension.format({ [PerMessageDeflate.extensionName]: [params] });
3666
- headers.push(`Sec-WebSocket-Extensions: ${value}`);
3667
- ws._extensions = extensions;
3668
- }
3669
- this.emit("headers", headers, req);
3670
- socket.write(headers.concat("\r\n").join("\r\n"));
3671
- socket.removeListener("error", socketOnError);
3672
- ws.setSocket(socket, head, {
3673
- allowSynchronousEvents: this.options.allowSynchronousEvents,
3674
- maxPayload: this.options.maxPayload,
3675
- skipUTF8Validation: this.options.skipUTF8Validation
3676
- });
3677
- if (this.clients) {
3678
- this.clients.add(ws);
3679
- ws.on("close", () => {
3680
- this.clients.delete(ws);
3681
- if (this._shouldEmitClose && !this.clients.size) process.nextTick(emitClose, this);
3682
- });
3683
- }
3684
- cb(ws, req);
3685
- }
3686
- };
3687
- module.exports = WebSocketServer;
3688
- /**
3689
- * Add event listeners on an `EventEmitter` using a map of <event, listener>
3690
- * pairs.
3691
- *
3692
- * @param {EventEmitter} server The event emitter
3693
- * @param {Object.<String, Function>} map The listeners to add
3694
- * @return {Function} A function that will remove the added listeners when
3695
- * called
3696
- * @private
3697
- */
3698
- function addListeners(server, map) {
3699
- for (const event of Object.keys(map)) server.on(event, map[event]);
3700
- return function removeListeners() {
3701
- for (const event of Object.keys(map)) server.removeListener(event, map[event]);
3702
- };
3703
- }
3704
- /**
3705
- * Emit a `'close'` event on an `EventEmitter`.
3706
- *
3707
- * @param {EventEmitter} server The event emitter
3708
- * @private
3709
- */
3710
- function emitClose(server) {
3711
- server._state = CLOSED;
3712
- server.emit("close");
3713
- }
3714
- /**
3715
- * Handle socket errors.
3716
- *
3717
- * @private
3718
- */
3719
- function socketOnError() {
3720
- this.destroy();
3721
- }
3722
- /**
3723
- * Close the connection when preconditions are not fulfilled.
3724
- *
3725
- * @param {Duplex} socket The socket of the upgrade request
3726
- * @param {Number} code The HTTP response status code
3727
- * @param {String} [message] The HTTP response body
3728
- * @param {Object} [headers] Additional HTTP response headers
3729
- * @private
3730
- */
3731
- function abortHandshake(socket, code, message, headers) {
3732
- message = message || http.STATUS_CODES[code];
3733
- headers = {
3734
- Connection: "close",
3735
- "Content-Type": "text/html",
3736
- "Content-Length": Buffer.byteLength(message),
3737
- ...headers
3738
- };
3739
- socket.once("finish", socket.destroy);
3740
- socket.end(`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message);
3741
- }
3742
- /**
3743
- * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
3744
- * one listener for it, otherwise call `abortHandshake()`.
3745
- *
3746
- * @param {WebSocketServer} server The WebSocket server
3747
- * @param {http.IncomingMessage} req The request object
3748
- * @param {Duplex} socket The socket of the upgrade request
3749
- * @param {Number} code The HTTP response status code
3750
- * @param {String} message The HTTP response body
3751
- * @param {Object} [headers] The HTTP response headers
3752
- * @private
3753
- */
3754
- function abortHandshakeOrEmitwsClientError(server, req, socket, code, message, headers) {
3755
- if (server.listenerCount("wsClientError")) {
3756
- const err = new Error(message);
3757
- Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
3758
- server.emit("wsClientError", err, socket, req);
3759
- } else abortHandshake(socket, code, message, headers);
3760
- }
3761
- }));
3762
- //#endregion
3763
- //#region ../../node_modules/ws/wrapper.mjs
3764
- init_runtime();
3765
- require_stream();
3766
- require_extension();
3767
- require_permessage_deflate();
3768
- require_receiver();
3769
- require_sender();
3770
- require_subprotocol();
3771
- var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
3772
- require_websocket_server();
3773
- var wrapper_default = import_websocket.default;
3774
- //#endregion
3775
- //#region src/client/ws-client.ts
3776
- const DEFAULT_INITIAL_DELAY_MS = 1e3;
3777
- const DEFAULT_MAX_DELAY_MS = 3e4;
3778
- const DEFAULT_BACKOFF_MULTIPLIER = 2;
3779
- function createMychatWsClient(params) {
3780
- const { wsUrl, token, botSelfId, logger, reconnect } = params;
3781
- const initialDelay = reconnect?.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
3782
- const maxDelay = reconnect?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
3783
- const backoffMultiplier = reconnect?.backoffMultiplier ?? DEFAULT_BACKOFF_MULTIPLIER;
3784
- const prefix = mychatLogPrefix("ws");
3785
- let ws = null;
3786
- let connected = false;
3787
- let reconnectTimer = null;
3788
- let currentDelay = initialDelay;
3789
- const handlers = /* @__PURE__ */ new Set();
3790
- function buildUrl() {
3791
- const url = new URL(wsUrl);
3792
- if (url.pathname.endsWith("/ws/bot")) {} else if (url.pathname.endsWith("/ws/")) url.pathname += "bot";
3793
- else if (url.pathname.endsWith("/ws")) url.pathname += "/bot";
3794
- else url.pathname = url.pathname.replace(/\/+$/, "") + "/ws/bot";
3795
- return url.toString();
3796
- }
3797
- function scheduleReconnect() {
3798
- if (reconnectTimer) return;
3799
- logger?.info(`${prefix} will reconnect in ${currentDelay}ms`);
3800
- reconnectTimer = setTimeout(() => {
3801
- reconnectTimer = null;
3802
- currentDelay = Math.min(currentDelay * backoffMultiplier, maxDelay);
3803
- connect();
3804
- }, currentDelay);
3805
- }
3806
- function connect() {
3807
- if (ws) return;
3808
- try {
3809
- const url = buildUrl();
3810
- logger?.info(`${prefix} connecting to ${url}`);
3811
- ws = new wrapper_default(url, { headers: { Authorization: `Bearer ${token}` } });
3812
- ws.on("open", () => {
3813
- connected = true;
3814
- currentDelay = initialDelay;
3815
- logger?.info(`${prefix} connected botSelfId=${botSelfId ?? "none"}`);
3816
- });
3817
- ws.on("message", (data) => {
3818
- try {
3819
- const message = JSON.parse(String(data));
3820
- for (const handler of handlers) handler(message);
3821
- } catch {}
3822
- });
3823
- ws.on("close", (code, reason) => {
3824
- connected = false;
3825
- ws = null;
3826
- logger?.info(`${prefix} closed code=${code} reason=${reason?.toString() || "none"}`);
3827
- scheduleReconnect();
3828
- });
3829
- ws.on("error", (err) => {
3830
- const errMsg = err instanceof Error ? err.message : String(err);
3831
- logger?.error(`${prefix} error: ${errMsg}`);
3832
- });
3833
- } catch (err) {
3834
- const errMsg = err instanceof Error ? err.message : String(err);
3835
- logger?.error(`${prefix} connect exception: ${errMsg}`);
3836
- scheduleReconnect();
3837
- }
3838
- }
3839
- function disconnect() {
3840
- if (reconnectTimer) {
3841
- clearTimeout(reconnectTimer);
3842
- reconnectTimer = null;
3843
- }
3844
- connected = false;
3845
- ws?.close();
3846
- ws = null;
3847
- }
3848
- function subscribe(conversationId) {
3849
- if (!ws || !connected) {
3850
- logger?.warn(`${prefix} cannot subscribe, not connected`);
3851
- return;
3852
- }
3853
- const subMsg = JSON.stringify({
3854
- type: "subscribe",
3855
- body: { subscribe: { conversationId } }
3856
- });
3857
- logger?.info(`${prefix} subscribing to conversationId=${conversationId}`);
3858
- ws.send(subMsg);
3859
- }
3860
- return {
3861
- connect,
3862
- disconnect,
3863
- subscribe,
3864
- onMessage(handler) {
3865
- handlers.add(handler);
3866
- return () => {
3867
- handlers.delete(handler);
3868
- };
3869
- },
3870
- isConnected() {
3871
- return connected;
3872
- }
3873
- };
3874
- }
3875
- //#endregion
3876
- //#region src/monitor/listeners.ts
3877
- function createMychatMessageListener(params) {
3878
- const { handler } = params;
3879
- return { handle(message) {
3880
- handler.handleMessage(message).catch(() => {});
3881
- } };
3882
- }
3883
- function createMychatReactionListener(params) {
3884
- const logger = getMychatLogger();
3885
- const prefix = mychatLogPrefix("reaction");
3886
- return { handle(message) {
3887
- const emoji = message.body?.reaction;
3888
- const action = message.body?.action ?? "add";
3889
- const target = message.body?.target;
3890
- const senderId = message.from?.id;
3891
- if (logger) logger.debug(`${prefix} ${action} ${emoji} on ${target} by ${senderId}`);
3892
- } };
3893
- }
3894
- function createMychatTypingListener(params) {
3895
- const logger = getMychatLogger();
3896
- const prefix = mychatLogPrefix("typing");
3897
- return { handle(message) {
3898
- const senderId = message.from?.id;
3899
- if (senderId === params.account.accountId) return;
3900
- if (logger) logger.debug(`${prefix} from ${senderId}`);
3901
- } };
3902
- }
3903
- //#endregion
3904
- //#region src/monitor/provider.startup.ts
3905
- function createMychatProviderClients(account, botSelfId, logger) {
3906
- return { wsClient: createMychatWsClient({
3907
- wsUrl: account.wsUrl,
3908
- token: account.token,
3909
- botSelfId,
3910
- logger,
3911
- reconnect: account.reconnect
3912
- }) };
3913
- }
3914
- function registerMychatMonitorListeners(params) {
3915
- const { account, handler, wsClient } = params;
3916
- const messageListener = createMychatMessageListener({
3917
- account,
3918
- handler
3919
- });
3920
- const reactionListener = createMychatReactionListener({ account });
3921
- const typingListener = createMychatTypingListener({ account });
3922
- wsClient.onMessage((message) => {
3923
- switch (message.type) {
3924
- case "message":
3925
- case "stream":
3926
- messageListener.handle(message);
3927
- break;
3928
- case "reaction":
3929
- reactionListener.handle(message);
3930
- break;
3931
- case "typing":
3932
- typingListener.handle(message);
3933
- break;
3934
- default: break;
3935
- }
3936
- });
3937
- }
3938
- //#endregion
3939
- //#region src/monitor/provider.lifecycle.ts
3940
- const DEFAULT_READY_TIMEOUT_MS = 15e3;
3941
- function createMychatProviderLifecycle(params) {
3942
- const { httpClient, wsClient, readyTimeoutMs = DEFAULT_READY_TIMEOUT_MS, logger } = params;
3943
- const prefix = mychatLogPrefix("lifecycle");
3944
- return {
3945
- async waitForReady() {
3946
- const start = Date.now();
3947
- logger?.info(`${prefix} starting timeoutMs=${readyTimeoutMs}`);
3948
- wsClient.connect();
3949
- let wsConnectedAt = null;
3950
- let getSelfAttempts = 0;
3951
- while (Date.now() - start < readyTimeoutMs) {
3952
- if (wsClient.isConnected()) {
3953
- if (!wsConnectedAt) {
3954
- wsConnectedAt = Date.now();
3955
- logger?.info(`${prefix} ws connected, fetching bot identity elapsedMs=${wsConnectedAt - start}`);
3956
- }
3957
- getSelfAttempts++;
3958
- const botSelf = await httpClient.getSelf();
3959
- if (botSelf) {
3960
- logger?.info(`${prefix} bot connected botId=${botSelf.botId} wsConnectMs=${wsConnectedAt - start} getSelfAttempts=${getSelfAttempts}`);
3961
- return botSelf;
3962
- }
3963
- logger?.warn(`${prefix} getSelf() failed attempt=${getSelfAttempts} elapsedMs=${Date.now() - start}`);
3964
- }
3965
- await new Promise((r) => setTimeout(r, 500));
3966
- }
3967
- const wsConnected = wsClient.isConnected();
3968
- const elapsed = Date.now() - start;
3969
- logger?.warn(`${prefix} ready timeout wsConnected=${wsConnected} wsConnectedAt=${wsConnectedAt ? wsConnectedAt - start : "never"} getSelfAttempts=${getSelfAttempts} elapsedMs=${elapsed} timeoutMs=${readyTimeoutMs}`);
3970
- return null;
3971
- },
3972
- shutdown() {
3973
- wsClient.disconnect();
3974
- logger?.info(`${prefix} shutdown`);
3975
- }
3976
- };
3977
- }
3978
- //#endregion
3979
- //#region src/monitor/inbound-dedupe.ts
3980
- const MAX_CACHE_SIZE = 500;
3981
- function createMychatInboundDedupe() {
3982
- const seen = /* @__PURE__ */ new Set();
3983
- return { isDuplicate(messageId) {
3984
- if (seen.has(messageId)) return true;
3985
- seen.add(messageId);
3986
- if (seen.size > MAX_CACHE_SIZE) {
3987
- const first = seen.values().next().value;
3988
- if (first !== void 0) seen.delete(first);
3989
- }
3990
- return false;
3991
- } };
3992
- }
3993
- //#endregion
3994
- //#region src/monitor/message-text.ts
3995
- /** Extract plain text from a WebSocket message body. */
3996
- function extractMychatMessageText(message) {
3997
- return message.body?.text ?? "";
3998
- }
3999
- /** Extract mention user IDs from a message. */
4000
- function extractMentionUserIds(message) {
4001
- return (message.body?.mentions ?? []).map((m) => m.userId).filter(Boolean);
4002
- }
4003
- /** Check if the bot is mentioned in a message. */
4004
- function isBotMentioned(message, botUserId) {
4005
- if (!botUserId) return false;
4006
- if (extractMentionUserIds(message).includes(botUserId)) return true;
4007
- return (message.body?.text ?? "").includes(`@${botUserId}`);
4008
- }
4009
- //#endregion
4010
- //#region src/monitor/message-handler.preflight.ts
4011
- /** Check if an inbound message should be accepted. */
4012
- function mychatPreflight(message, account) {
4013
- const senderId = message.from?.id;
4014
- if (!senderId) return {
4015
- allowed: false,
4016
- reason: "no-sender"
4017
- };
4018
- if (senderId === account.accountId) return {
4019
- allowed: false,
4020
- reason: "self"
4021
- };
4022
- const toKind = message.to?.kind ?? "direct";
4023
- if (toKind === "direct" || toKind === "channel") {
4024
- if (account.dmPolicy === "disabled") return {
4025
- allowed: false,
4026
- reason: "dm-disabled"
4027
- };
4028
- if (account.dmPolicy === "allowlist" && account.allowFrom.length > 0) {
4029
- if (!account.allowFrom.includes(senderId)) return {
4030
- allowed: false,
4031
- reason: "dm-not-allowed"
4032
- };
4033
- }
4034
- }
4035
- if (toKind === "group") {
4036
- if (account.groupPolicy === "disabled") return {
4037
- allowed: false,
4038
- reason: "group-disabled"
4039
- };
4040
- if (account.groupPolicy === "allowlist" && account.groupAllowFrom.length > 0) {
4041
- if (!account.groupAllowFrom.includes(senderId)) return {
4042
- allowed: false,
4043
- reason: "group-not-allowed"
4044
- };
4045
- }
4046
- const groupId = message.to?.id;
4047
- if (groupId && account.groups[groupId]) {
4048
- const groupConfig = account.groups[groupId];
4049
- if (groupConfig.enabled === false) return {
4050
- allowed: false,
4051
- reason: "group-disabled"
4052
- };
4053
- if (groupConfig.requireMention && !isBotMentioned(message, account.accountId)) return {
4054
- allowed: false,
4055
- reason: "mention-required"
4056
- };
4057
- }
4058
- if (account.requireMention && !isBotMentioned(message, account.accountId)) return {
4059
- allowed: false,
4060
- reason: "mention-required"
4061
- };
4062
- }
4063
- return { allowed: true };
4064
- }
4065
- //#endregion
4066
- //#region src/monitor/inbound-context.ts
4067
- function buildMychatInboundContext(message, account) {
4068
- if (message.type !== "message" && message.type !== "stream") return null;
4069
- const senderId = message.from?.id;
4070
- if (!senderId) return null;
4071
- const text = message.body?.text ?? "";
4072
- const toKind = message.to?.kind ?? "direct";
4073
- const chatType = toKind === "group" || toKind === "channel" ? "group" : "direct";
4074
- return {
4075
- messageId: message.id,
4076
- text,
4077
- senderId,
4078
- senderName: message.from?.name,
4079
- chatType,
4080
- conversationId: message.to?.id ?? message.body?.conversationId,
4081
- threadId: message.body?.parentId,
4082
- replyTo: message.body?.parentId,
4083
- mentions: message.body?.mentions ?? [],
4084
- attachments: message.body?.attachments ?? [],
4085
- timestamp: message.timestamp
4086
- };
4087
- }
4088
- //#endregion
4089
- //#region src/monitor/message-media.ts
4090
- /** Resolve media attachments from an inbound message. */
4091
- function resolveMychatMediaAttachments(message) {
4092
- return (message.body?.attachments ?? []).filter((a) => a.url && (a.mimeType.startsWith("image/") || a.mimeType.startsWith("video/") || a.mimeType.startsWith("audio/") || a.mimeType === "application/pdf"));
4093
- }
4094
- //#endregion
4095
- //#region src/monitor/message-handler.process.ts
4096
- /** Process an inbound message into a structured result. */
4097
- function processMychatInbound(message, account) {
4098
- const context = buildMychatInboundContext(message, account);
4099
- if (!context) return null;
4100
- return {
4101
- context,
4102
- text: extractMychatMessageText(message),
4103
- media: resolveMychatMediaAttachments(message)
4104
- };
4105
- }
4106
- //#endregion
4107
- //#region src/monitor/message-handler.ts
4108
- function createMychatMessageHandler(params) {
4109
- const { account, onInbound } = params;
4110
- const dedupe = createMychatInboundDedupe();
4111
- const logger = getMychatLogger();
4112
- const prefix = mychatLogPrefix("handler");
4113
- return { async handleMessage(message) {
4114
- if (dedupe.isDuplicate(message.id)) return;
4115
- const preflight = mychatPreflight(message, account);
4116
- if (!preflight.allowed) {
4117
- if (logger) logger.debug(`${prefix} message rejected reason=${preflight.reason} messageId=${message.id}`);
4118
- return;
4119
- }
4120
- const result = processMychatInbound(message, account);
4121
- if (!result) return;
4122
- if (logger) logger.debug(`${prefix} message accepted messageId=${result.context.messageId} chatType=${result.context.chatType}`);
4123
- await onInbound(result);
4124
- } };
4125
- }
4126
- //#endregion
4127
- //#region src/monitor/provider.ts
4128
- async function monitorMychatProvider(ctx) {
4129
- const { account, setStatus, log: logger } = ctx;
4130
- const prefix = mychatLogPrefix("provider");
4131
- logger?.info(`${prefix} starting accountId=${account.accountId}`);
4132
- setStatus({
4133
- connected: false,
4134
- mode: "websocket"
4135
- });
4136
- const httpClient = createMychatHttpClient({
4137
- baseUrl: account.baseUrl,
4138
- token: account.token,
4139
- logger
4140
- });
4141
- logger?.info(`${prefix} fetching bot identity baseUrl=${account.baseUrl}`);
4142
- const botSelf = await httpClient.getSelf();
4143
- if (!botSelf) {
4144
- const error = `MyChat provider failed to get bot identity (baseUrl=${account.baseUrl}, token=${account.token ? account.token.slice(0, 8) + "..." : "empty"})`;
4145
- logger?.error(`${prefix} ${error}`);
4146
- setStatus({
4147
- connected: false,
4148
- lastError: error
4149
- });
4150
- throw new Error(error);
4151
- }
4152
- logger?.info(`${prefix} got bot identity botId=${botSelf.botId} name=${botSelf.name ?? "unknown"}`);
4153
- const health = await httpClient.healthCheck();
4154
- if (!health.ok) logger?.warn(`${prefix} health check failed latencyMs=${health.latencyMs} baseUrl=${account.baseUrl}`);
4155
- else logger?.info(`${prefix} health check ok latencyMs=${health.latencyMs}`);
4156
- const { wsClient } = createMychatProviderClients(account, botSelf.botId, logger);
4157
- const rt = ctx.runtime;
4158
- rt.mychat = {
4159
- accountId: account.accountId,
4160
- httpClient,
4161
- wsClient,
4162
- botSelf
4163
- };
4164
- try {
4165
- setMychatRuntime(ctx.runtime);
4166
- } catch {}
4167
- registerMychatMonitorListeners({
4168
- account,
4169
- handler: createMychatMessageHandler({
4170
- account,
4171
- onInbound: async (result) => {
4172
- await dispatchMychatInbound(ctx, httpClient, result);
4173
- }
4174
- }),
4175
- wsClient
4176
- });
4177
- logger?.info(`${prefix} starting connection lifecycle`);
4178
- const lifecycle = createMychatProviderLifecycle({
4179
- httpClient,
4180
- wsClient,
4181
- logger
4182
- });
4183
- const readyBotSelf = await lifecycle.waitForReady();
4184
- if (!readyBotSelf) {
4185
- const error = "MyChat provider failed to connect";
4186
- logger?.error(`${prefix} ${error}`);
4187
- setStatus({
4188
- connected: false,
4189
- lastError: error
4190
- });
4191
- lifecycle.shutdown();
4192
- throw new Error(error);
4193
- }
4194
- setStatus({
4195
- connected: true,
4196
- lastConnectedAt: Date.now(),
4197
- lastEventAt: Date.now(),
4198
- mode: "websocket",
4199
- lastError: null
4200
- });
4201
- logger?.info(`${prefix} bot connected botId=${readyBotSelf.botId}`);
4202
- try {
4203
- const conversations = await httpClient.listConversations();
4204
- logger?.info(`${prefix} found ${conversations.length} conversations to subscribe`);
4205
- for (const convId of conversations) wsClient.subscribe(convId);
4206
- } catch (err) {
4207
- logger?.warn(`${prefix} failed to list conversations: ${err}`);
4208
- }
4209
- ctx.abortSignal?.addEventListener("abort", () => {
4210
- logger?.info(`${prefix} abort signal received, shutting down`);
4211
- lifecycle.shutdown();
4212
- setStatus({ connected: false });
4213
- });
4214
- return { unsubscribe() {
4215
- logger?.info(`${prefix} unsubscribe called, shutting down`);
4216
- lifecycle.shutdown();
4217
- setStatus({ connected: false });
4218
- } };
4219
- }
4220
- /** Dispatch an inbound message through the OpenClaw turn runtime. */
4221
- async function dispatchMychatInbound(ctx, httpClient, result) {
4222
- const { runtime, cfg, account } = ctx;
4223
- const logger = getMychatLogger();
4224
- const prefix = mychatLogPrefix("dispatch");
4225
- const rt = runtime;
4226
- if (!rt.channel?.turn?.run) {
4227
- if (logger) logger.warn(`${prefix} channel turn runtime not available, skipping inbound`);
4228
- return;
4229
- }
4230
- const conversationId = result.context.conversationId ?? result.context.senderId;
4231
- const senderId = result.context.senderId;
4232
- const chatType = result.context.chatType;
4233
- const messageId = result.context.messageId;
4234
- await rt.channel.turn.run({
4235
- channel: "mychat",
4236
- accountId: account.accountId,
4237
- raw: result,
4238
- adapter: {
4239
- ingest: () => ({
4240
- id: messageId,
4241
- timestamp: result.context.timestamp,
4242
- rawText: result.text,
4243
- textForAgent: result.text,
4244
- textForCommands: result.text,
4245
- raw: result
4246
- }),
4247
- resolveTurn: (input) => {
4248
- const msgCtx = rt.channel.turn.buildContext({
4249
- channel: "mychat",
4250
- accountId: account.accountId,
4251
- timestamp: input.timestamp,
4252
- from: `mychat:user:${senderId}`,
4253
- sender: {
4254
- id: senderId,
4255
- name: result.context.senderName
4256
- },
4257
- conversation: {
4258
- kind: chatType,
4259
- id: conversationId,
4260
- label: result.context.senderName ?? senderId,
4261
- routePeer: {
4262
- kind: chatType,
4263
- id: conversationId
4264
- }
4265
- },
4266
- route: {
4267
- agentId: void 0,
4268
- accountId: account.accountId
4269
- },
4270
- reply: {
4271
- to: `mychat:${conversationId}`,
4272
- originatingTo: `mychat:${conversationId}`
4273
- },
4274
- message: {
4275
- rawBody: input.rawText,
4276
- commandBody: input.textForCommands,
4277
- bodyForAgent: input.textForAgent,
4278
- envelopeFrom: result.context.senderName
4279
- }
4280
- });
4281
- return {
4282
- cfg,
4283
- channel: "mychat",
4284
- accountId: account.accountId,
4285
- ctxPayload: msgCtx,
4286
- dispatchReplyWithBufferedBlockDispatcher: rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher,
4287
- delivery: { deliver: async (payload) => {
4288
- const text = payload.text?.trim();
4289
- if (!text) return;
4290
- const sendResult = await httpClient.sendMessage({
4291
- to: conversationId,
4292
- text,
4293
- type: chatType === "group" ? "group" : "direct"
4294
- });
4295
- if (logger) logger.debug(`${prefix} reply sent to=${conversationId} ok=${Boolean(sendResult)}`);
4296
- } }
4297
- };
4298
- }
4299
- }
4300
- });
4301
- }
4302
- //#endregion
4303
- //#region src/shared.ts
4304
- function createMychatPluginBase() {
4305
- return {
4306
- ...createChannelPluginBase({
4307
- id: "mychat",
4308
- setup: { applyAccountConfig(params) {
4309
- return params.cfg;
4310
- } },
4311
- meta: {
4312
- label: "MyChat",
4313
- docsPath: "docs/plugins/mychat",
4314
- blurb: "Connect to MyChat server via bot token",
4315
- aliases: ["mychat"]
4316
- },
4317
- capabilities: {
4318
- chatTypes: [
4319
- "direct",
4320
- "group",
4321
- "thread"
4322
- ],
4323
- reactions: true,
4324
- media: true,
4325
- threads: true
4326
- },
4327
- reload: { configPrefixes: ["channels.mychat"] },
4328
- configSchema: mychatConfigSchema,
4329
- config: {
4330
- listAccountIds(cfg) {
4331
- return resolveMychatAccounts(cfg).map((a) => a.accountId);
4332
- },
4333
- resolveAccount(cfg, accountId) {
4334
- return resolveMychatAccount({
4335
- cfg,
4336
- accountId
4337
- });
4338
- },
4339
- async inspectAccount(account) {
4340
- return {
4341
- accountId: account.accountId,
4342
- enabled: account.enabled,
4343
- label: account.name ?? account.baseUrl
4344
- };
4345
- }
4346
- }
4347
- }),
4348
- gateway: { async startAccount(ctx) {
4349
- const setStatus = createAccountStatusSink({
4350
- accountId: ctx.accountId,
4351
- setStatus: ctx.setStatus
4352
- });
4353
- const result = await monitorMychatProvider({
4354
- cfg: ctx.cfg,
4355
- runtime: ctx.runtime,
4356
- account: ctx.account,
4357
- setStatus,
4358
- abortSignal: ctx.abortSignal,
4359
- log: ctx.log
4360
- });
4361
- await new Promise((resolve) => {
4362
- const originalUnsubscribe = result.unsubscribe;
4363
- result.unsubscribe = () => {
4364
- originalUnsubscribe();
4365
- resolve();
4366
- };
4367
- });
4368
- } }
4369
- };
4370
- }
4371
- //#endregion
4372
- //#region src/outbound/outbound-payload.ts
4373
- async function sendMychatOutboundPayload(ctx, body) {
4374
- const logger = getMychatLogger();
4375
- const prefix = mychatLogPrefix("outbound");
4376
- try {
4377
- const result = await ctx.httpClient.sendMessage(body);
4378
- if (result) {
4379
- if (logger) logger.debug(`${prefix} message sent id=${result.id} status=${result.status}`);
4380
- return {
4381
- messageId: result.id,
4382
- ok: true
4383
- };
4384
- }
4385
- return { ok: false };
4386
- } catch (error) {
4387
- if (logger) logger.error(`${prefix} send failed error=${error instanceof Error ? error.message : String(error)}`);
4388
- return { ok: false };
4389
- }
4390
- }
4391
- //#endregion
4392
- //#region src/outbound/outbound-send-context.ts
4393
- function createMychatOutboundSendContext(params) {
4394
- return {
4395
- account: params.account,
4396
- httpClient: params.httpClient
4397
- };
4398
- }
4399
- //#endregion
4400
- //#region src/outbound/outbound-adapter.ts
4401
- init_runtime();
4402
- const TEXT_CHUNK_LIMIT = 4e3;
4403
- function chunkText(text, limit) {
4404
- if (text.length <= limit) return [text];
4405
- const chunks = [];
4406
- let remaining = text;
4407
- while (remaining.length > 0) {
4408
- chunks.push(remaining.slice(0, limit));
4409
- remaining = remaining.slice(limit);
4410
- }
4411
- return chunks;
4412
- }
4413
- const mychatOutbound = {
4414
- deliveryMode: "direct",
4415
- textChunkLimit: TEXT_CHUNK_LIMIT,
4416
- async sendText(params) {
4417
- const logger = getMychatLogger();
4418
- const account = getMychatRuntime().mychat;
4419
- if (!account) {
4420
- if (logger) logger.error(`${mychatLogPrefix("outbound")} no runtime account`);
4421
- return {
4422
- channel: "mychat",
4423
- messageId: "",
4424
- ok: false
4425
- };
4426
- }
4427
- const ctx = createMychatOutboundSendContext({
4428
- account: params.account ?? {},
4429
- httpClient: account.httpClient
4430
- });
4431
- const chunks = chunkText(params.text, TEXT_CHUNK_LIMIT);
4432
- let lastOk = false;
4433
- let lastMessageId = "";
4434
- for (const chunk of chunks) {
4435
- const result = await sendMychatOutboundPayload(ctx, {
4436
- to: params.target ?? "",
4437
- text: chunk,
4438
- type: params.chatType,
4439
- replyTo: params.replyTo
4440
- });
4441
- lastOk = result.ok;
4442
- if (result.messageId) lastMessageId = result.messageId;
4443
- }
4444
- return {
4445
- channel: "mychat",
4446
- messageId: lastMessageId,
4447
- ok: lastOk
4448
- };
4449
- },
4450
- async sendMedia(params) {
4451
- const logger = getMychatLogger();
4452
- const account = getMychatRuntime().mychat;
4453
- if (!account) {
4454
- if (logger) logger.error(`${mychatLogPrefix("outbound")} no runtime account`);
4455
- return {
4456
- channel: "mychat",
4457
- messageId: "",
4458
- ok: false
4459
- };
4460
- }
4461
- if (params.media) {
4462
- const uploadResult = await account.httpClient.uploadFile({
4463
- file: params.media,
4464
- filename: params.filename ?? "upload",
4465
- mimeType: params.mimeType ?? "application/octet-stream"
4466
- });
4467
- if (uploadResult) {
4468
- const result = await sendMychatOutboundPayload(createMychatOutboundSendContext({
4469
- account: params.account ?? {},
4470
- httpClient: account.httpClient
4471
- }), {
4472
- to: params.target ?? "",
4473
- text: params.text ?? "",
4474
- type: params.chatType,
4475
- attachments: [uploadResult.attachment]
4476
- });
4477
- return {
4478
- channel: "mychat",
4479
- messageId: result.messageId ?? "",
4480
- ok: result.ok
4481
- };
4482
- }
4483
- }
4484
- return {
4485
- channel: "mychat",
4486
- messageId: "",
4487
- ok: false
4488
- };
4489
- },
4490
- async sendPayload(params) {
4491
- const logger = getMychatLogger();
4492
- const account = getMychatRuntime().mychat;
4493
- if (!account) {
4494
- if (logger) logger.error(`${mychatLogPrefix("outbound")} no runtime account`);
4495
- return {
4496
- channel: "mychat",
4497
- messageId: "",
4498
- ok: false
4499
- };
4500
- }
4501
- const result = await sendMychatOutboundPayload(createMychatOutboundSendContext({
4502
- account: params.account ?? {},
4503
- httpClient: account.httpClient
4504
- }), {
4505
- to: params.target ?? "",
4506
- text: params.text ?? "",
4507
- type: params.chatType,
4508
- replyTo: params.replyTo
4509
- });
4510
- return {
4511
- channel: "mychat",
4512
- messageId: result.messageId ?? "",
4513
- ok: result.ok
4514
- };
4515
- }
4516
- };
4517
- //#endregion
4518
- //#region src/channel.ts
4519
- const mychatPlugin = createChatChannelPlugin({
4520
- base: createMychatPluginBase(),
4521
- security: { dm: {
4522
- channelKey: "dmPolicy",
4523
- resolvePolicy(account) {
4524
- return account.dmPolicy ?? "open";
4525
- },
4526
- resolveAllowFrom(account) {
4527
- return account.allowFrom;
4528
- }
4529
- } },
4530
- pairing: { text: {
4531
- idLabel: "MyChat Username",
4532
- message: "To connect to MyChat, configure your bot token and server URL in the channel config.",
4533
- notify() {}
4534
- } },
4535
- threading: {
4536
- replyToMode: "always",
4537
- resolveReplyTo(params) {
4538
- return {
4539
- threadId: params.inbound?.threadId ?? params.inbound?.conversationId,
4540
- replyTo: params.inbound?.messageId
4541
- };
4542
- },
4543
- sanitizeThreadName(name) {
4544
- return name.slice(0, 100).replace(/[^\w\s-]/g, "");
4545
- }
4546
- },
4547
- outbound: mychatOutbound
4548
- });
4549
- //#endregion
4550
- export { mychatPlugin as t };