@iobroker/socket-classes 2.6.2 → 2.7.1

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,7 +1,18 @@
1
1
  "use strict";
2
+ var _a;
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.SocketCommands = exports.COMMANDS_PERMISSIONS = void 0;
4
5
  const adapter_core_1 = require("@iobroker/adapter-core"); // Get common adapter utils
6
+ /**
7
+ * The events that are waiting for the database to say whether their socket may see them.
8
+ *
9
+ * Kept per connection and per event, and only ever the **latest** one: while the first event of an id
10
+ * waits for its answer, a newer value of the same state would otherwise overtake it and the client
11
+ * would end up with the older one. What is kept is how to deliver it - the event goes through
12
+ * `publish`/`publishFile` again, so a subscription that was given up in the meantime still counts. It
13
+ * lives in a `WeakMap`, so a connection that goes away takes its waiting events with it.
14
+ */
15
+ const pendingEvents = new WeakMap();
5
16
  exports.COMMANDS_PERMISSIONS = {
6
17
  getObject: { type: 'object', operation: 'read' },
7
18
  getObjects: { type: 'object', operation: 'list' },
@@ -70,6 +81,21 @@ class SocketCommands {
70
81
  subscribes = {};
71
82
  #logEnabled = false;
72
83
  #clientSubscribes = {};
84
+ /**
85
+ * What each user may read, by object id. Filled while the events flow, emptied where an object -
86
+ * or the rights themselves - change. Per user, because every browser tab of one person would
87
+ * otherwise ask the same question again.
88
+ */
89
+ #readable = new Map();
90
+ /** Questions that are with the database right now, so the same id is asked only once at a time */
91
+ #deciding = new Map();
92
+ /**
93
+ * Counts how often the decisions were thrown away. An answer that was asked for before the last
94
+ * change arrives too late to be trusted and is dropped instead of being remembered.
95
+ */
96
+ #readableGeneration = 0;
97
+ /** Whether this instance watches the objects for the sake of its own decisions - see `#rememberDecision` */
98
+ #watchingObjects = false;
73
99
  #updateSession;
74
100
  adapterName;
75
101
  _sendToHost;
@@ -196,41 +222,41 @@ class SocketCommands {
196
222
  if (socket._acl?.user !== 'system.user.admin') {
197
223
  // type: file, object, state, other
198
224
  // operation: create, read, write, list, delete, sendto, execute, sendToHost, readLogs
199
- if (SocketCommands.COMMANDS_PERMISSIONS[_command]) {
225
+ if (_a.COMMANDS_PERMISSIONS[_command]) {
200
226
  // If permission required
201
- const commandType = SocketCommands.COMMANDS_PERMISSIONS[_command].type;
227
+ const commandType = _a.COMMANDS_PERMISSIONS[_command].type;
202
228
  if (commandType) {
203
229
  if (commandType === 'object') {
204
- const operation = SocketCommands.COMMANDS_PERMISSIONS[_command].operation;
230
+ const operation = _a.COMMANDS_PERMISSIONS[_command].operation;
205
231
  if (socket._acl?.object?.[operation]) {
206
232
  return true;
207
233
  }
208
234
  }
209
235
  else if (commandType === 'state') {
210
- const operation = SocketCommands.COMMANDS_PERMISSIONS[_command].operation;
236
+ const operation = _a.COMMANDS_PERMISSIONS[_command].operation;
211
237
  if (socket._acl?.state?.[operation]) {
212
238
  return true;
213
239
  }
214
240
  }
215
241
  else if (commandType === 'users') {
216
- const operation = SocketCommands.COMMANDS_PERMISSIONS[_command].operation;
242
+ const operation = _a.COMMANDS_PERMISSIONS[_command].operation;
217
243
  if (socket._acl?.users?.[operation]) {
218
244
  return true;
219
245
  }
220
246
  }
221
247
  else if (commandType === 'other') {
222
- const operation = SocketCommands.COMMANDS_PERMISSIONS[_command].operation;
248
+ const operation = _a.COMMANDS_PERMISSIONS[_command].operation;
223
249
  if (socket._acl?.other?.[operation]) {
224
250
  return true;
225
251
  }
226
252
  }
227
253
  else if (commandType === 'file') {
228
- const operation = SocketCommands.COMMANDS_PERMISSIONS[_command].operation;
254
+ const operation = _a.COMMANDS_PERMISSIONS[_command].operation;
229
255
  if (socket._acl?.file?.[operation]) {
230
256
  return true;
231
257
  }
232
258
  }
233
- this.adapter.log.warn(`No permission for "${socket._acl?.user}" to call ${_command}. Need "${commandType}"."${SocketCommands.COMMANDS_PERMISSIONS[_command].operation}"`);
259
+ this.adapter.log.warn(`No permission for "${socket._acl?.user}" to call ${_command}. Need "${commandType}"."${_a.COMMANDS_PERMISSIONS[_command].operation}"`);
234
260
  }
235
261
  else {
236
262
  return true;
@@ -240,29 +266,269 @@ class SocketCommands {
240
266
  this.adapter.log.warn(`No rule for command: ${_command}`);
241
267
  }
242
268
  if (typeof callback === 'function') {
243
- callback(SocketCommands.ERROR_PERMISSION);
269
+ callback(_a.ERROR_PERMISSION);
244
270
  }
245
271
  else {
246
- if (SocketCommands.COMMANDS_PERMISSIONS[_command]) {
247
- socket.emit(SocketCommands.ERROR_PERMISSION, {
272
+ if (_a.COMMANDS_PERMISSIONS[_command]) {
273
+ socket.emit(_a.ERROR_PERMISSION, {
248
274
  command,
249
- type: SocketCommands.COMMANDS_PERMISSIONS[_command].type,
250
- operation: SocketCommands.COMMANDS_PERMISSIONS[_command].operation,
275
+ type: _a.COMMANDS_PERMISSIONS[_command].type,
276
+ operation: _a.COMMANDS_PERMISSIONS[_command].operation,
251
277
  args,
252
278
  });
253
279
  }
254
280
  else {
255
- socket.emit(SocketCommands.ERROR_PERMISSION, { command: _command, args });
281
+ socket.emit(_a.ERROR_PERMISSION, { command: _command, args });
256
282
  }
257
283
  }
258
284
  return false;
259
285
  }
260
286
  return true;
261
287
  }
288
+ /**
289
+ * Whether this connection belongs to somebody who may see everything.
290
+ *
291
+ * The administrator group is the whole point of the administrator group, and with authentication
292
+ * switched off every connection is the configured default user - usually exactly that one. So this
293
+ * is the answer for almost every connection there is, and it costs a look at an ACL that the
294
+ * socket layer calculated when the connection was opened.
295
+ *
296
+ * @param socket the connection in question
297
+ */
298
+ static #seesEverything(socket) {
299
+ const acl = socket?._acl;
300
+ return acl?.user === 'system.user.admin' || !!acl?.groups?.includes('system.group.administrator');
301
+ }
302
+ /**
303
+ * Whether the user of this connection may read `id`, as far as it is already known.
304
+ *
305
+ * `undefined` means "not decided yet" - the caller has to let `#decideReadable` ask the database
306
+ * and come back. Decisions are kept per user, not per connection: three browser tabs of the same
307
+ * person ask once.
308
+ *
309
+ * @param socket the connection the event would go to
310
+ * @param question what the event is about
311
+ */
312
+ #mayRead(socket, question) {
313
+ const user = socket?._acl?.user;
314
+ if (!user) {
315
+ // a connection without a user has no rights at all, not even to be told that `id` exists
316
+ return false;
317
+ }
318
+ if (_a.#seesEverything(socket)) {
319
+ return true;
320
+ }
321
+ return this.#readable.get(user)?.get(_a.#questionKey(question));
322
+ }
323
+ /** What one question is remembered under: the kind, the id, and for a file its name */
324
+ static #questionKey(question) {
325
+ return question.fileName
326
+ ? `${question.type}####${question.id}####${question.fileName}`
327
+ : `${question.type}####${question.id}`;
328
+ }
329
+ /**
330
+ * Ask the database whether the user may read `id`, and remember the answer.
331
+ *
332
+ * The database owns this decision - the ACL of the object, its owner, the groups of the user and
333
+ * the default ACL of the system all go into it, and a second implementation here would drift away
334
+ * from it sooner or later. Everybody who is waiting for the same id is answered together.
335
+ *
336
+ * @param socket the connection the event would go to
337
+ * @param question what the event is about
338
+ * @param andThen what to do once it is decided, with the decision
339
+ */
340
+ #decideReadable(socket, question, andThen) {
341
+ // a connection without a user never gets this far: `#mayRead` refuses it outright
342
+ const user = socket._acl.user;
343
+ const questionKey = _a.#questionKey(question);
344
+ const key = `${user}####${questionKey}`;
345
+ const waiting = this.#deciding.get(key);
346
+ if (waiting) {
347
+ waiting.push(andThen);
348
+ return;
349
+ }
350
+ this.#deciding.set(key, [andThen]);
351
+ const generation = this.#readableGeneration;
352
+ const answer = (allowed) => {
353
+ if (generation === this.#readableGeneration) {
354
+ this.#rememberDecision(user, questionKey, allowed);
355
+ }
356
+ /*
357
+ * An answer that is too old to be remembered still answers the events that waited for it:
358
+ * a "no" drops them, a "yes" sends them back through `publish`, which - with nothing in
359
+ * memory - asks again under the rights as they are now.
360
+ */
361
+ const callbacks = this.#deciding.get(key) || [];
362
+ this.#deciding.delete(key);
363
+ for (const callback of callbacks) {
364
+ callback(allowed);
365
+ }
366
+ };
367
+ const mayRead = this.adapter.mayRead;
368
+ if (mayRead) {
369
+ /*
370
+ * The controller answers this itself from js-controller 8.0 on, and it is the only place
371
+ * that knows the whole truth: the ACL of a state rather than of its object, the mode of a
372
+ * single file rather than of the adapter it belongs to.
373
+ */
374
+ mayRead.call(this.adapter, { ...question, user }).then(answer, (e) => {
375
+ this.adapter.log.warn(`Cannot check what "${user}" may read of "${question.id}": ${e.message}`);
376
+ answer(false);
377
+ });
378
+ return;
379
+ }
380
+ /*
381
+ * An older controller cannot be asked, so the object has to stand in for all three. It is
382
+ * coarser - the right on the object instead of the one on the state, the adapter instead of
383
+ * the single file - but it errs the same way: only a refusal of the database counts as "no".
384
+ * That an object does not exist is not a refusal, and `mayRead` of a newer controller says the
385
+ * same, because such a state can be read by anybody.
386
+ */
387
+ // the callback form also returns a promise, which nobody here waits for
388
+ void this.adapter.getForeignObject(question.id, { user }, (error) => answer(!error));
389
+ }
390
+ /**
391
+ * Keep one decision, and make sure the object changes that would invalidate it arrive here.
392
+ *
393
+ * Nothing of this is needed as long as everybody who is connected sees everything anyway, which is
394
+ * the normal case - so the subscription is taken out where the first decision is made and not
395
+ * before. The events themselves reach `publish` the way every other object change does.
396
+ *
397
+ * @param user whose decision it is
398
+ * @param questionKey what was asked - the kind, the id and for a file its name
399
+ * @param allowed what was decided
400
+ */
401
+ #rememberDecision(user, questionKey, allowed) {
402
+ let decisions = this.#readable.get(user);
403
+ if (!decisions) {
404
+ decisions = new Map();
405
+ this.#readable.set(user, decisions);
406
+ }
407
+ decisions.set(questionKey, allowed);
408
+ if (!this.#watchingObjects) {
409
+ this.#watchingObjects = true;
410
+ /*
411
+ * The ACL of an object can change at any time, and without this the decision above would
412
+ * be kept until the connection goes away. The watch counts as one more subscriber of `*`:
413
+ * a client that subscribed to all objects and gives them up again would otherwise take
414
+ * the subscription of the database away from under it.
415
+ */
416
+ this.subscribes.objectChange ||= {};
417
+ if (this.subscribes.objectChange['*'] === undefined) {
418
+ this.subscribes.objectChange['*'] = 1;
419
+ this.adapter
420
+ .subscribeForeignObjectsAsync('*')
421
+ .catch(e => this.adapter.log.warn(`Cannot watch the objects for the permissions of the clients: ${e.message}`));
422
+ }
423
+ else {
424
+ this.subscribes.objectChange['*']++;
425
+ }
426
+ }
427
+ }
428
+ /** Forget what was decided about `id`, because the object - and with it its ACL - changed. */
429
+ #forgetReadable(id) {
430
+ this.#readableGeneration++;
431
+ if (id.startsWith('system.user.') || id.startsWith('system.group.') || id === 'system.config') {
432
+ // the rights themselves moved, so nothing that was decided with them still counts
433
+ this.#readable.clear();
434
+ return;
435
+ }
436
+ for (const decisions of this.#readable.values()) {
437
+ // everything that was decided about this id, whatever was asked about it
438
+ for (const questionKey of decisions.keys()) {
439
+ if (questionKey.endsWith(`####${id}`) || questionKey.includes(`####${id}####`)) {
440
+ decisions.delete(questionKey);
441
+ }
442
+ }
443
+ }
444
+ }
445
+ /**
446
+ * Hold one event until it is decided whether its connection may see it.
447
+ *
448
+ * Only the latest event of the same kind and id waits; a newer one replaces it, so nothing can
449
+ * overtake it. The question is asked once - every further event of that id joins the one that is
450
+ * already open.
451
+ *
452
+ * @param socket the connection the event would go to
453
+ * @param question what the decision is about
454
+ * @param key what identifies this event - its kind and what it is about
455
+ * @param deliver how to send it once it is decided
456
+ */
457
+ #holdUntilDecided(socket, question, key, deliver) {
458
+ let waiting = pendingEvents.get(socket);
459
+ if (!waiting) {
460
+ waiting = new Map();
461
+ pendingEvents.set(socket, waiting);
462
+ }
463
+ const first = !waiting.has(key);
464
+ waiting.set(key, deliver);
465
+ if (first) {
466
+ this.#decideReadable(socket, question, allowed => this.#flushPending(socket, key, allowed));
467
+ }
468
+ }
469
+ /**
470
+ * Send the event that waited for a decision, if it may go out after all.
471
+ *
472
+ * What is sent is whatever arrived last while the question was open - a client that subscribes to
473
+ * a state wants its value, not the one it had a moment ago. It goes through `publish`/`publishFile`
474
+ * again: the subscription may have been given up in the meantime. Usually the decision is in memory
475
+ * by then and the event goes out; only where the object changed while the question was open was
476
+ * the answer not remembered, and the event waits once more for a fresh one.
477
+ *
478
+ * @param socket the connection that waited
479
+ * @param key what identifies the event
480
+ * @param allowed what was decided
481
+ */
482
+ #flushPending(socket, key, allowed) {
483
+ const waiting = pendingEvents.get(socket);
484
+ const deliver = waiting?.get(key);
485
+ if (!deliver || !waiting) {
486
+ return;
487
+ }
488
+ waiting.delete(key);
489
+ if (allowed) {
490
+ deliver();
491
+ }
492
+ }
493
+ /**
494
+ * Give one event to one connection, if it is subscribed to it and may see it.
495
+ *
496
+ * Returns whether the event is on its way to this client: `true` where it was sent, and also
497
+ * where it is waiting for the database to decide whether this user may read the object - the
498
+ * answer to that is not worth holding up every other connection for. `false` means the client is
499
+ * not subscribed to it, or may not see it.
500
+ *
501
+ * @param socket the connection
502
+ * @param type what kind of event it is
503
+ * @param id the object it is about
504
+ * @param obj the state or object as it is sent to the client
505
+ */
262
506
  publish(socket, type, id, obj) {
507
+ if (type === 'objectChange') {
508
+ // the ACL of the object travelled with it, so what was decided about it is out of date
509
+ this.#forgetReadable(id);
510
+ }
263
511
  if (socket?.subscribe?.[type] && this.#updateSession(socket)) {
264
512
  return !!socket.subscribe[type].find(sub => {
265
513
  if (sub.regex.test(id)) {
514
+ /*
515
+ * Who may know that this exists? A subscription says which ids a client is
516
+ * interested in, never which ids it may see - `subscribe` only asks whether the
517
+ * user may read states at all, so whoever subscribed to `*` was told about every
518
+ * state of the system, the ACL of the single objects notwithstanding.
519
+ */
520
+ const question = { type: type === 'objectChange' ? 'object' : 'state', id };
521
+ const allowed = this.#mayRead(socket, question);
522
+ if (allowed === false) {
523
+ return false;
524
+ }
525
+ if (allowed === undefined) {
526
+ // the first event of an id for this user waits for the answer instead of
527
+ // being guessed at
528
+ this.#holdUntilDecided(socket, question, `${type}####${id}`, () => this.publish(socket, type, id, obj));
529
+ // on its way: either it goes out in a moment, or the user may not see it
530
+ return true;
531
+ }
266
532
  // replace language
267
533
  if (this.context.language &&
268
534
  id === 'system.config' &&
@@ -276,11 +542,36 @@ class SocketCommands {
276
542
  }
277
543
  return false;
278
544
  }
545
+ /**
546
+ * Give one file event to one connection, if it is subscribed to it and may see it.
547
+ *
548
+ * The decision is taken per file and user. Where the controller has `mayRead`, it answers for the
549
+ * single file, with its own owner and mode as `chownFile` and `chmodFile` set them. An older
550
+ * controller cannot be asked about a file, so the meta object the files belong to - `vis.0` for
551
+ * every file of vis - stands in for it: still one question per file, but every one of them about
552
+ * the adapter. That also works where the file the event is about has just been deleted.
553
+ *
554
+ * The answer means the same as in {@link publish}: `true` where the event is on its way.
555
+ *
556
+ * @param socket the connection
557
+ * @param id the adapter the file belongs to, e.g. `vis.0`
558
+ * @param fileName the path of the file inside it
559
+ * @param size how big it is now, or null where it is gone
560
+ */
279
561
  publishFile(socket, id, fileName, size) {
280
562
  if (socket?.subscribe?.fileChange && this.#updateSession(socket)) {
281
563
  const key = `${id}####${fileName}`;
282
564
  return !!socket.subscribe.fileChange.find(sub => {
283
565
  if (sub.regex.test(key)) {
566
+ const question = { type: 'file', id, fileName };
567
+ const allowed = this.#mayRead(socket, question);
568
+ if (allowed === false) {
569
+ return false;
570
+ }
571
+ if (allowed === undefined) {
572
+ this.#holdUntilDecided(socket, question, `fileChange####${key}`, () => this.publishFile(socket, id, fileName, size));
573
+ return true;
574
+ }
284
575
  socket.emit('fileChange', id, fileName, size);
285
576
  return true;
286
577
  }
@@ -288,17 +579,30 @@ class SocketCommands {
288
579
  }
289
580
  return false;
290
581
  }
582
+ /**
583
+ * The send options for a message triggered by this socket: the user it is sent on behalf of.
584
+ *
585
+ * Objects, states and files have always been read and written with `{ user }` so the database
586
+ * applies the ACLs of the logged-in user. A message had no such channel: the receiving instance saw
587
+ * `from` and nothing else, so every adapter reachable over `sendTo` had to act with its own rights,
588
+ * and could not tell one caller from another. The user travels with the message now: js-controller
589
+ * 7.2.5 and newer put it into the message as `obj.user`, older ones ignore the option, so nothing
590
+ * breaks. A receiver treats the field as optional - where nobody was named there is nothing to
591
+ * check against, which is how every message looked before.
592
+ *
593
+ * @param socket the socket the command came in on
594
+ */
595
+ static sendOptionsOf(socket) {
596
+ const user = socket?._acl?.user;
597
+ return user ? { user } : undefined;
598
+ }
291
599
  publishInstanceMessage(socket, sourceInstance, messageType, data) {
292
600
  if (this.#clientSubscribes[socket.id]?.[sourceInstance]?.includes(messageType)) {
293
601
  socket.emit('im', messageType, sourceInstance, data);
294
602
  return true;
295
603
  }
296
604
  // inform instance about missing subscription
297
- this.adapter.sendTo(sourceInstance, 'clientSubscribeError', {
298
- type: messageType,
299
- sid: socket.id,
300
- reason: 'no one subscribed',
301
- });
605
+ this.adapter.sendTo(sourceInstance, 'clientSubscribeError', { type: messageType, sid: socket.id, reason: 'no one subscribed' }, undefined, _a.sendOptionsOf(socket));
302
606
  return false;
303
607
  }
304
608
  _showSubscribes(socket, type) {
@@ -550,7 +854,7 @@ class SocketCommands {
550
854
  return;
551
855
  }
552
856
  // inform all instances about disconnected socket, also if the socket has never subscribed to anything
553
- this.#informAboutDisconnect(socket.id);
857
+ this.#informAboutDisconnect(socket);
554
858
  if (!socket.subscribe) {
555
859
  return;
556
860
  }
@@ -859,18 +1163,18 @@ class SocketCommands {
859
1163
  */
860
1164
  this.commands.checkFeatureSupported = (_socket, feature, callback) => {
861
1165
  if (feature === 'INSTANCE_MESSAGES') {
862
- SocketCommands._fixCallback(callback, null, true);
1166
+ _a._fixCallback(callback, null, true);
863
1167
  }
864
1168
  else if (feature === 'PARTIAL_OBJECT_TREE') {
865
- SocketCommands._fixCallback(callback, null, true);
1169
+ _a._fixCallback(callback, null, true);
866
1170
  }
867
1171
  else if (feature === 'OBJECTS_COUNT') {
868
1172
  // only the admin variant of these commands has it, and a client that asks must not
869
1173
  // send a command that nobody answers - it would sit there until its timeout
870
- SocketCommands._fixCallback(callback, null, !!this.commands.getObjectsCount);
1174
+ _a._fixCallback(callback, null, !!this.commands.getObjectsCount);
871
1175
  }
872
1176
  else {
873
- SocketCommands._fixCallback(callback, null, this.adapter.supportsFeature(feature));
1177
+ _a._fixCallback(callback, null, this.adapter.supportsFeature(feature));
874
1178
  }
875
1179
  };
876
1180
  /**
@@ -894,11 +1198,11 @@ class SocketCommands {
894
1198
  options.user = socket._acl?.user;
895
1199
  options.aggregate ||= 'none';
896
1200
  try {
897
- this.adapter.getHistory(id, options, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1201
+ this.adapter.getHistory(id, options, (error, ...args) => _a._fixCallback(callback, error, ...args));
898
1202
  }
899
1203
  catch (error) {
900
1204
  this.adapter.log.error(`[getHistory] ERROR: ${error.toString()}`);
901
- SocketCommands._fixCallback(callback, error);
1205
+ _a._fixCallback(callback, error);
902
1206
  }
903
1207
  }
904
1208
  };
@@ -936,7 +1240,7 @@ class SocketCommands {
936
1240
  this.commands.sendTo = (socket, adapterInstance, command, message, callback) => {
937
1241
  if (this._checkPermissions(socket, 'sendTo', callback, command)) {
938
1242
  try {
939
- this.adapter.sendTo(adapterInstance, command, message, res => typeof callback === 'function' && setImmediate(() => callback(res)));
1243
+ this.adapter.sendTo(adapterInstance, command, message, res => typeof callback === 'function' && setImmediate(() => callback(res)), _a.sendOptionsOf(socket));
940
1244
  }
941
1245
  catch (error) {
942
1246
  if (typeof callback === 'function') {
@@ -971,7 +1275,7 @@ class SocketCommands {
971
1275
  * @param callback callback `(result: { error?: string; result?: any }) => void`
972
1276
  */
973
1277
  this.commands.sendToHost = (socket, host, command, message, callback) => {
974
- if (this._checkPermissions(socket, protectedCommands.includes(command) ? 'cmdExec' : 'sendToHost', (error) => callback({ error: error || SocketCommands.ERROR_PERMISSION }), command)) {
1278
+ if (this._checkPermissions(socket, protectedCommands.includes(command) ? 'cmdExec' : 'sendToHost', (error) => callback({ error: error || _a.ERROR_PERMISSION }), command)) {
975
1279
  // Try to decode this file locally as redis has a limitation for files bigger than 20MB
976
1280
  if (command === 'writeDirAsZip' && message && message.data.length > 1024 * 1024) {
977
1281
  let buffer;
@@ -1002,7 +1306,10 @@ class SocketCommands {
1002
1306
  }
1003
1307
  else {
1004
1308
  try {
1005
- this.adapter.sendToHost(host, command, message, callback);
1309
+ // the 5th parameter exists from js-controller 7.2.5 on; an older one
1310
+ // ignores the extra argument
1311
+ const sendToHost = this.adapter.sendToHost;
1312
+ sendToHost.call(this.adapter, host, command, message, callback, _a.sendOptionsOf(socket));
1006
1313
  }
1007
1314
  catch (error) {
1008
1315
  if (callback) {
@@ -1101,7 +1408,7 @@ class SocketCommands {
1101
1408
  */
1102
1409
  this.commands.listPermissions = (_socket, callback) => {
1103
1410
  if (typeof callback === 'function') {
1104
- callback(SocketCommands.COMMANDS_PERMISSIONS);
1411
+ callback(_a.COMMANDS_PERMISSIONS);
1105
1412
  }
1106
1413
  else {
1107
1414
  this.adapter.log.warn('[listPermissions] Invalid callback');
@@ -1173,11 +1480,11 @@ class SocketCommands {
1173
1480
  this.commands.readFile = (socket, adapter, fileName, callback) => {
1174
1481
  if (this._checkPermissions(socket, 'readFile', callback, fileName)) {
1175
1482
  try {
1176
- this.adapter.readFile(adapter, fileName, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1483
+ this.adapter.readFile(adapter, fileName, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1177
1484
  }
1178
1485
  catch (error) {
1179
1486
  this.adapter.log.error(`[readFile] ERROR: ${error.toString()}`);
1180
- SocketCommands._fixCallback(callback, error);
1487
+ _a._fixCallback(callback, error);
1181
1488
  }
1182
1489
  }
1183
1490
  };
@@ -1226,7 +1533,7 @@ class SocketCommands {
1226
1533
  }
1227
1534
  catch (error) {
1228
1535
  this.adapter.log.error(`[readFile64] ERROR: ${error.toString()}`);
1229
- SocketCommands._fixCallback(callback, error);
1536
+ _a._fixCallback(callback, error);
1230
1537
  }
1231
1538
  }
1232
1539
  };
@@ -1255,16 +1562,16 @@ class SocketCommands {
1255
1562
  }
1256
1563
  if (this._checkPermissions(socket, 'writeFile64', callback, fileName)) {
1257
1564
  if (!data64) {
1258
- return SocketCommands._fixCallback(callback, 'No data provided');
1565
+ return _a._fixCallback(callback, 'No data provided');
1259
1566
  }
1260
1567
  // Convert base 64 to buffer
1261
1568
  try {
1262
1569
  const buffer = Buffer.from(data64, 'base64');
1263
- this.adapter.writeFile(adapter, fileName, buffer, _options, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1570
+ this.adapter.writeFile(adapter, fileName, buffer, _options, (error, ...args) => _a._fixCallback(callback, error, ...args));
1264
1571
  }
1265
1572
  catch (error) {
1266
1573
  this.adapter.log.error(`[writeFile64] Cannot convert data: ${error.toString()}`);
1267
- SocketCommands._fixCallback(callback, `Cannot convert data: ${error.toString()}`);
1574
+ _a._fixCallback(callback, `Cannot convert data: ${error.toString()}`);
1268
1575
  }
1269
1576
  }
1270
1577
  };
@@ -1297,11 +1604,11 @@ class SocketCommands {
1297
1604
  }
1298
1605
  this.adapter.log.debug('writeFile deprecated. Please use writeFile64');
1299
1606
  try {
1300
- this.adapter.writeFile(adapter, fileName, data, _options, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1607
+ this.adapter.writeFile(adapter, fileName, data, _options, (error, ...args) => _a._fixCallback(callback, error, ...args));
1301
1608
  }
1302
1609
  catch (error) {
1303
1610
  this.adapter.log.error(`[writeFile] ERROR: ${error.toString()}`);
1304
- SocketCommands._fixCallback(callback, error);
1611
+ _a._fixCallback(callback, error);
1305
1612
  }
1306
1613
  }
1307
1614
  };
@@ -1318,12 +1625,12 @@ class SocketCommands {
1318
1625
  if (this._checkPermissions(socket, 'unlink', callback, name)) {
1319
1626
  try {
1320
1627
  this.#unlink(adapter, name, { user: socket._acl?.user })
1321
- .then(() => SocketCommands._fixCallback(callback, undefined))
1322
- .catch(error => SocketCommands._fixCallback(callback, error));
1628
+ .then(() => _a._fixCallback(callback, undefined))
1629
+ .catch(error => _a._fixCallback(callback, error));
1323
1630
  }
1324
1631
  catch (error) {
1325
1632
  this.adapter.log.error(`[unlink] ERROR: ${error.toString()}`);
1326
- SocketCommands._fixCallback(callback, error);
1633
+ _a._fixCallback(callback, error);
1327
1634
  }
1328
1635
  }
1329
1636
  };
@@ -1339,11 +1646,11 @@ class SocketCommands {
1339
1646
  this.commands.deleteFile = (socket, adapter, name, callback) => {
1340
1647
  if (this._checkPermissions(socket, 'unlink', callback, name)) {
1341
1648
  try {
1342
- this.adapter.unlink(adapter, name, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1649
+ this.adapter.unlink(adapter, name, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1343
1650
  }
1344
1651
  catch (error) {
1345
1652
  this.adapter.log.error(`[deleteFile] ERROR: ${error.toString()}`);
1346
- SocketCommands._fixCallback(callback, error);
1653
+ _a._fixCallback(callback, error);
1347
1654
  }
1348
1655
  }
1349
1656
  };
@@ -1360,12 +1667,12 @@ class SocketCommands {
1360
1667
  if (this._checkPermissions(socket, 'unlink', callback, name)) {
1361
1668
  try {
1362
1669
  this.#unlink(adapter, name, { user: socket._acl?.user })
1363
- .then(() => SocketCommands._fixCallback(callback, null))
1364
- .catch(error => SocketCommands._fixCallback(callback, error));
1670
+ .then(() => _a._fixCallback(callback, null))
1671
+ .catch(error => _a._fixCallback(callback, error));
1365
1672
  }
1366
1673
  catch (error) {
1367
1674
  this.adapter.log.error(`[deleteFolder] ERROR: ${error.toString()}`);
1368
- SocketCommands._fixCallback(callback, error);
1675
+ _a._fixCallback(callback, error);
1369
1676
  }
1370
1677
  }
1371
1678
  };
@@ -1382,11 +1689,11 @@ class SocketCommands {
1382
1689
  this.commands.renameFile = (socket, adapter, oldName, newName, callback) => {
1383
1690
  if (this._checkPermissions(socket, 'rename', callback, oldName)) {
1384
1691
  try {
1385
- this.adapter.rename(adapter, oldName, newName, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1692
+ this.adapter.rename(adapter, oldName, newName, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1386
1693
  }
1387
1694
  catch (error) {
1388
1695
  this.adapter.log.error(`[renameFile] ERROR: ${error.toString()}`);
1389
- SocketCommands._fixCallback(callback, error);
1696
+ _a._fixCallback(callback, error);
1390
1697
  }
1391
1698
  }
1392
1699
  };
@@ -1404,12 +1711,12 @@ class SocketCommands {
1404
1711
  if (this._checkPermissions(socket, 'rename', callback, oldName)) {
1405
1712
  try {
1406
1713
  this.#rename(adapter, oldName, newName, { user: socket._acl?.user })
1407
- .then(() => SocketCommands._fixCallback(callback, undefined))
1408
- .catch(error => SocketCommands._fixCallback(callback, error));
1714
+ .then(() => _a._fixCallback(callback, undefined))
1715
+ .catch(error => _a._fixCallback(callback, error));
1409
1716
  }
1410
1717
  catch (error) {
1411
1718
  this.adapter.log.error(`[rename] ERROR: ${error.toString()}`);
1412
- SocketCommands._fixCallback(callback, error);
1719
+ _a._fixCallback(callback, error);
1413
1720
  }
1414
1721
  }
1415
1722
  };
@@ -1425,11 +1732,11 @@ class SocketCommands {
1425
1732
  this.commands.mkdir = (socket, adapter, dirName, callback) => {
1426
1733
  if (this._checkPermissions(socket, 'mkdir', callback, dirName)) {
1427
1734
  try {
1428
- this.adapter.mkdir(adapter, dirName, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1735
+ this.adapter.mkdir(adapter, dirName, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1429
1736
  }
1430
1737
  catch (error) {
1431
1738
  this.adapter.log.error(`[mkdir] ERROR: ${error.toString()}`);
1432
- SocketCommands._fixCallback(callback, error);
1739
+ _a._fixCallback(callback, error);
1433
1740
  }
1434
1741
  }
1435
1742
  };
@@ -1449,11 +1756,11 @@ class SocketCommands {
1449
1756
  }
1450
1757
  if (this._checkPermissions(socket, 'readDir', callback, dirName)) {
1451
1758
  try {
1452
- this.adapter.readDir(adapter, dirName, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1759
+ this.adapter.readDir(adapter, dirName, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1453
1760
  }
1454
1761
  catch (error) {
1455
1762
  this.adapter.log.error(`[readDir] ERROR: ${error.toString()}`);
1456
- SocketCommands._fixCallback(callback, error);
1763
+ _a._fixCallback(callback, error);
1457
1764
  }
1458
1765
  }
1459
1766
  };
@@ -1475,16 +1782,16 @@ class SocketCommands {
1475
1782
  }
1476
1783
  else {
1477
1784
  this.adapter.log.error(`[chownFile] ERROR: no options`);
1478
- SocketCommands._fixCallback(callback, 'no options');
1785
+ _a._fixCallback(callback, 'no options');
1479
1786
  return;
1480
1787
  }
1481
1788
  if (this._checkPermissions(socket, 'chmodFile', callback, fileName)) {
1482
1789
  try {
1483
- this.adapter.chmodFile(adapter, fileName, _options, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1790
+ this.adapter.chmodFile(adapter, fileName, _options, (error, ...args) => _a._fixCallback(callback, error, ...args));
1484
1791
  }
1485
1792
  catch (error) {
1486
1793
  this.adapter.log.error(`[chmodFile] ERROR: ${error.toString()}`);
1487
- SocketCommands._fixCallback(callback, error);
1794
+ _a._fixCallback(callback, error);
1488
1795
  }
1489
1796
  }
1490
1797
  };
@@ -1507,16 +1814,16 @@ class SocketCommands {
1507
1814
  }
1508
1815
  else {
1509
1816
  this.adapter.log.error(`[chownFile] ERROR: no options`);
1510
- SocketCommands._fixCallback(callback, 'no options');
1817
+ _a._fixCallback(callback, 'no options');
1511
1818
  return;
1512
1819
  }
1513
1820
  if (this._checkPermissions(socket, 'chownFile', callback, fileName)) {
1514
1821
  try {
1515
- this.adapter.chownFile(adapter, fileName, _options, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1822
+ this.adapter.chownFile(adapter, fileName, _options, (error, ...args) => _a._fixCallback(callback, error, ...args));
1516
1823
  }
1517
1824
  catch (error) {
1518
1825
  this.adapter.log.error(`[chownFile] ERROR: ${error.toString()}`);
1519
- SocketCommands._fixCallback(callback, error);
1826
+ _a._fixCallback(callback, error);
1520
1827
  }
1521
1828
  }
1522
1829
  };
@@ -1532,11 +1839,11 @@ class SocketCommands {
1532
1839
  this.commands.fileExists = (socket, adapter, fileName, callback) => {
1533
1840
  if (this._checkPermissions(socket, 'fileExists', callback, fileName)) {
1534
1841
  try {
1535
- this.adapter.fileExists(adapter, fileName, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1842
+ this.adapter.fileExists(adapter, fileName, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1536
1843
  }
1537
1844
  catch (error) {
1538
1845
  this.adapter.log.error(`[fileExists] ERROR: ${error.toString()}`);
1539
- SocketCommands._fixCallback(callback, error);
1846
+ _a._fixCallback(callback, error);
1540
1847
  }
1541
1848
  }
1542
1849
  };
@@ -1603,7 +1910,7 @@ class SocketCommands {
1603
1910
  }
1604
1911
  catch (error) {
1605
1912
  this.adapter.log.error(`[getAdapterInstances] ERROR: ${error.toString()}`);
1606
- SocketCommands._fixCallback(callback, error);
1913
+ _a._fixCallback(callback, error);
1607
1914
  }
1608
1915
  }
1609
1916
  }
@@ -1627,11 +1934,11 @@ class SocketCommands {
1627
1934
  }
1628
1935
  if (typeof callback === 'function') {
1629
1936
  try {
1630
- this.adapter.getForeignStates(pattern || '*', { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
1937
+ this.adapter.getForeignStates(pattern || '*', { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1631
1938
  }
1632
1939
  catch (error) {
1633
1940
  this.adapter.log.error(`[getStates] ERROR: ${error.toString()}`);
1634
- SocketCommands._fixCallback(callback, error);
1941
+ _a._fixCallback(callback, error);
1635
1942
  }
1636
1943
  }
1637
1944
  else {
@@ -1669,15 +1976,15 @@ class SocketCommands {
1669
1976
  try {
1670
1977
  void this.adapter
1671
1978
  .getForeignStateAsync(id, { user: socket._acl?.user })
1672
- .then(state => SocketCommands._fixCallback(callback, null, state))
1979
+ .then(state => _a._fixCallback(callback, null, state))
1673
1980
  .catch(error => {
1674
1981
  this.adapter.log.error(`[getState] ERROR: ${error.toString()}`);
1675
- SocketCommands._fixCallback(callback, error);
1982
+ _a._fixCallback(callback, error);
1676
1983
  });
1677
1984
  }
1678
1985
  catch (error) {
1679
1986
  this.adapter.log.error(`[getState] ERROR: ${error.toString()}`);
1680
- SocketCommands._fixCallback(callback, error);
1987
+ _a._fixCallback(callback, error);
1681
1988
  }
1682
1989
  }
1683
1990
  }
@@ -1705,11 +2012,11 @@ class SocketCommands {
1705
2012
  delete this.states[id];
1706
2013
  }
1707
2014
  try {
1708
- this.adapter.setForeignState(id, state, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
2015
+ this.adapter.setForeignState(id, state, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
1709
2016
  }
1710
2017
  catch (error) {
1711
2018
  this.adapter.log.error(`[setState] ERROR: ${error.toString()}`);
1712
- SocketCommands._fixCallback(callback, error);
2019
+ _a._fixCallback(callback, error);
1713
2020
  }
1714
2021
  }
1715
2022
  };
@@ -1810,12 +2117,12 @@ class SocketCommands {
1810
2117
  if (this.context.language && id === 'system.config' && obj?.common) {
1811
2118
  obj.common.language = this.context.language;
1812
2119
  }
1813
- SocketCommands._fixCallback(callback, error, obj);
2120
+ _a._fixCallback(callback, error, obj);
1814
2121
  });
1815
2122
  }
1816
2123
  catch (error) {
1817
2124
  this.adapter.log.error(`[getObject] ERROR: ${error.toString()}`);
1818
- SocketCommands._fixCallback(callback, error);
2125
+ _a._fixCallback(callback, error);
1819
2126
  }
1820
2127
  }
1821
2128
  };
@@ -1837,11 +2144,11 @@ class SocketCommands {
1837
2144
  if (this._checkPermissions(socket, 'getObject', callback)) {
1838
2145
  if (typeof callback === 'function') {
1839
2146
  try {
1840
- this.adapter.getForeignObjects(list, { user: socket._acl?.user }, (error, objs) => SocketCommands._fixCallback(callback, error, objs));
2147
+ this.adapter.getForeignObjects(list, { user: socket._acl?.user }, (error, objs) => _a._fixCallback(callback, error, objs));
1841
2148
  }
1842
2149
  catch (error) {
1843
2150
  this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1844
- SocketCommands._fixCallback(callback, error);
2151
+ _a._fixCallback(callback, error);
1845
2152
  }
1846
2153
  }
1847
2154
  else {
@@ -1879,7 +2186,7 @@ class SocketCommands {
1879
2186
  if (this.context.language && result['system.config']?.common) {
1880
2187
  result['system.config'].common.language = this.context.language;
1881
2188
  }
1882
- SocketCommands._fixCallback(callback, error, result);
2189
+ _a._fixCallback(callback, error, result);
1883
2190
  });
1884
2191
  }
1885
2192
  else {
@@ -1888,7 +2195,7 @@ class SocketCommands {
1888
2195
  }
1889
2196
  catch (error) {
1890
2197
  this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1891
- SocketCommands._fixCallback(callback, error);
2198
+ _a._fixCallback(callback, error);
1892
2199
  }
1893
2200
  }
1894
2201
  };
@@ -2045,7 +2352,7 @@ class SocketCommands {
2045
2352
  }
2046
2353
  catch (error) {
2047
2354
  this.adapter.log.error(`[getObjectView] ERROR: ${error.toString()}`);
2048
- SocketCommands._fixCallback(callback, error);
2355
+ _a._fixCallback(callback, error);
2049
2356
  }
2050
2357
  }
2051
2358
  }
@@ -2065,11 +2372,11 @@ class SocketCommands {
2065
2372
  this.commands.setObject = (socket, id, obj, callback) => {
2066
2373
  if (this._checkPermissions(socket, 'setObject', callback, id)) {
2067
2374
  try {
2068
- void this.adapter.setForeignObject(id, obj, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
2375
+ void this.adapter.setForeignObject(id, obj, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
2069
2376
  }
2070
2377
  catch (error) {
2071
2378
  this.adapter.log.error(`[setObject] ERROR: ${error.toString()}`);
2072
- SocketCommands._fixCallback(callback, error);
2379
+ _a._fixCallback(callback, error);
2073
2380
  }
2074
2381
  }
2075
2382
  };
@@ -2087,16 +2394,16 @@ class SocketCommands {
2087
2394
  if (id.startsWith('flot.') || id.startsWith('fullcalendar.')) {
2088
2395
  if (this._checkPermissions(socket, 'delObject', callback, id)) {
2089
2396
  try {
2090
- this.adapter.delForeignObject(id, { user: socket._acl?.user }, (error, ...args) => SocketCommands._fixCallback(callback, error, ...args));
2397
+ this.adapter.delForeignObject(id, { user: socket._acl?.user }, (error, ...args) => _a._fixCallback(callback, error, ...args));
2091
2398
  }
2092
2399
  catch (error) {
2093
2400
  this.adapter.log.error(`[delObject] ERROR: ${error.toString()}`);
2094
- SocketCommands._fixCallback(callback, error);
2401
+ _a._fixCallback(callback, error);
2095
2402
  }
2096
2403
  }
2097
2404
  }
2098
2405
  else {
2099
- SocketCommands._fixCallback(callback, SocketCommands.ERROR_PERMISSION);
2406
+ _a._fixCallback(callback, _a.ERROR_PERMISSION);
2100
2407
  }
2101
2408
  };
2102
2409
  /**
@@ -2131,7 +2438,7 @@ class SocketCommands {
2131
2438
  this.#clientSubscribes[sid][targetInstance].push(messageType);
2132
2439
  }
2133
2440
  // inform instance about new subscription
2134
- this.adapter.sendTo(targetInstance, 'clientSubscribe', { type: messageType, sid, data }, result => SocketCommands._fixCallback(callback, null, result));
2441
+ this.adapter.sendTo(targetInstance, 'clientSubscribe', { type: messageType, sid, data }, result => _a._fixCallback(callback, null, result), _a.sendOptionsOf(socket));
2135
2442
  };
2136
2443
  /**
2137
2444
  * #DOCUMENTATION commands
@@ -2157,16 +2464,12 @@ class SocketCommands {
2157
2464
  if (pos !== -1) {
2158
2465
  this.#clientSubscribes[sid][targetInstance].splice(pos, 1);
2159
2466
  // inform instance about unsubscription
2160
- this.adapter.sendTo(targetInstance, 'clientUnsubscribe', {
2161
- type: [messageType],
2162
- sid,
2163
- reason: 'client',
2164
- });
2165
- SocketCommands._fixCallback(callback, null, true);
2467
+ this.adapter.sendTo(targetInstance, 'clientUnsubscribe', { type: [messageType], sid, reason: 'client' }, undefined, _a.sendOptionsOf(socket));
2468
+ _a._fixCallback(callback, null, true);
2166
2469
  return;
2167
2470
  }
2168
2471
  }
2169
- SocketCommands._fixCallback(callback, null, false);
2472
+ _a._fixCallback(callback, null, false);
2170
2473
  };
2171
2474
  /**
2172
2475
  * #DOCUMENTATION commands
@@ -2190,7 +2493,7 @@ class SocketCommands {
2190
2493
  obj.native ||= {};
2191
2494
  obj.native.vendor = vendor;
2192
2495
  }
2193
- SocketCommands._fixCallback(callback, error, obj);
2496
+ _a._fixCallback(callback, error, obj);
2194
2497
  });
2195
2498
  }
2196
2499
  };
@@ -2202,15 +2505,26 @@ class SocketCommands {
2202
2505
  this._initCommandsStates();
2203
2506
  this._initCommandsFiles();
2204
2507
  }
2205
- #informAboutDisconnect(socketId) {
2508
+ /**
2509
+ * Tell every instance this socket had subscribed to that it is gone.
2510
+ *
2511
+ * Carries the user of the connection like the explicit `clientUnsubscribe` does: an instance that
2512
+ * keeps something per user - a recording, a session, a pending request - learns whose it was,
2513
+ * instead of only which socket id disappeared.
2514
+ *
2515
+ * @param socket the socket that went away
2516
+ */
2517
+ #informAboutDisconnect(socket) {
2518
+ const socketId = socket.id;
2206
2519
  // say to all instances that this socket was disconnected
2207
2520
  if (this.#clientSubscribes[socketId]) {
2521
+ const options = _a.sendOptionsOf(socket);
2208
2522
  Object.keys(this.#clientSubscribes[socketId]).forEach(targetInstance => {
2209
2523
  this.adapter.sendTo(targetInstance, 'clientUnsubscribe', {
2210
2524
  type: this.#clientSubscribes[socketId][targetInstance],
2211
2525
  sid: socketId,
2212
2526
  reason: 'disconnect',
2213
- });
2527
+ }, undefined, options);
2214
2528
  });
2215
2529
  delete this.#clientSubscribes[socketId];
2216
2530
  }
@@ -2220,7 +2534,7 @@ class SocketCommands {
2220
2534
  // Check if the authentication is still valid. Announcing a new access token is the only way
2221
2535
  // to make an expired session valid again, so that command must pass the check - otherwise
2222
2536
  // a client whose token has expired could never recover without reloading the page.
2223
- if (SocketCommands.COMMANDS_WITHOUT_SESSION_CHECK.includes(command) || this.#updateSession(socket)) {
2537
+ if (_a.COMMANDS_WITHOUT_SESSION_CHECK.includes(command) || this.#updateSession(socket)) {
2224
2538
  this.commands[command](socket, ...args);
2225
2539
  }
2226
2540
  else {
@@ -2236,4 +2550,5 @@ class SocketCommands {
2236
2550
  }
2237
2551
  }
2238
2552
  exports.SocketCommands = SocketCommands;
2553
+ _a = SocketCommands;
2239
2554
  //# sourceMappingURL=socketCommands.js.map