@aka_openclaw_plugin/mychat 0.1.16 → 0.1.18

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