@iobroker/js-controller-adapter 7.2.3 → 8.0.0-alpha.1-20260921-e5941ca8a

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.
Files changed (101) hide show
  1. package/build/cjs/index.d.ts +0 -1
  2. package/build/cjs/index.js +5 -8
  3. package/build/cjs/index.js.map +2 -2
  4. package/build/cjs/lib/_Types.d.ts +394 -63
  5. package/build/cjs/lib/adapter/adapter.d.ts +1818 -177
  6. package/build/cjs/lib/adapter/adapter.js +715 -1035
  7. package/build/cjs/lib/adapter/adapter.js.map +2 -2
  8. package/build/cjs/lib/adapter/asyncAdapter.d.ts +124 -0
  9. package/build/cjs/lib/adapter/asyncAdapter.js +184 -0
  10. package/build/cjs/lib/adapter/asyncAdapter.js.map +7 -0
  11. package/build/cjs/lib/adapter/context.d.ts +34 -0
  12. package/build/cjs/lib/adapter/context.js +17 -0
  13. package/build/cjs/lib/adapter/context.js.map +7 -0
  14. package/build/cjs/lib/adapter/defaultObjs.d.ts +5 -0
  15. package/build/cjs/lib/adapter/defaultObjs.js +2 -0
  16. package/build/cjs/lib/adapter/defaultObjs.js.map +2 -2
  17. package/build/cjs/lib/adapter/log.d.ts +25 -0
  18. package/build/cjs/lib/adapter/log.js +29 -0
  19. package/build/cjs/lib/adapter/log.js.map +2 -2
  20. package/build/cjs/lib/adapter/managers/AdapterContextBase.d.ts +49 -0
  21. package/build/cjs/lib/adapter/managers/AdapterContextBase.js +98 -0
  22. package/build/cjs/lib/adapter/managers/AdapterContextBase.js.map +7 -0
  23. package/build/cjs/lib/adapter/managers/AliasManager.d.ts +103 -0
  24. package/build/cjs/lib/adapter/managers/AliasManager.js +293 -0
  25. package/build/cjs/lib/adapter/managers/AliasManager.js.map +7 -0
  26. package/build/cjs/lib/adapter/managers/CertificateManager.d.ts +50 -0
  27. package/build/cjs/lib/adapter/managers/CertificateManager.js +174 -0
  28. package/build/cjs/lib/adapter/managers/CertificateManager.js.map +7 -0
  29. package/build/cjs/lib/adapter/managers/MessagingManager.d.ts +58 -0
  30. package/build/cjs/lib/adapter/managers/MessagingManager.js +289 -0
  31. package/build/cjs/lib/adapter/managers/MessagingManager.js.map +7 -0
  32. package/build/cjs/lib/adapter/managers/SubscriptionManager.d.ts +107 -0
  33. package/build/cjs/lib/adapter/managers/SubscriptionManager.js +349 -0
  34. package/build/cjs/lib/adapter/managers/SubscriptionManager.js.map +7 -0
  35. package/build/cjs/lib/adapter/userInterfaceMessagingController.d.ts +10 -0
  36. package/build/cjs/lib/adapter/userInterfaceMessagingController.js +9 -2
  37. package/build/cjs/lib/adapter/userInterfaceMessagingController.js.map +2 -2
  38. package/build/cjs/lib/adapter/utils.js +15 -1
  39. package/build/cjs/lib/adapter/utils.js.map +2 -2
  40. package/build/cjs/lib/adapter/validator.d.ts +10 -5
  41. package/build/cjs/lib/adapter/validator.js +6 -5
  42. package/build/cjs/lib/adapter/validator.js.map +2 -2
  43. package/build/esm/index.d.ts +0 -1
  44. package/build/esm/index.d.ts.map +1 -1
  45. package/build/esm/index.js +0 -1
  46. package/build/esm/index.js.map +1 -1
  47. package/build/esm/lib/_Types.d.ts +394 -63
  48. package/build/esm/lib/_Types.d.ts.map +1 -1
  49. package/build/esm/lib/adapter/adapter.d.ts +1818 -177
  50. package/build/esm/lib/adapter/adapter.d.ts.map +1 -1
  51. package/build/esm/lib/adapter/adapter.js +827 -1215
  52. package/build/esm/lib/adapter/adapter.js.map +1 -1
  53. package/build/esm/lib/adapter/asyncAdapter.d.ts +124 -0
  54. package/build/esm/lib/adapter/asyncAdapter.d.ts.map +1 -0
  55. package/build/esm/lib/adapter/asyncAdapter.js +157 -0
  56. package/build/esm/lib/adapter/asyncAdapter.js.map +1 -0
  57. package/build/esm/lib/adapter/context.d.ts +34 -0
  58. package/build/esm/lib/adapter/context.d.ts.map +1 -0
  59. package/build/esm/lib/adapter/context.js +2 -0
  60. package/build/esm/lib/adapter/context.js.map +1 -0
  61. package/build/esm/lib/adapter/defaultObjs.d.ts +5 -0
  62. package/build/esm/lib/adapter/defaultObjs.d.ts.map +1 -1
  63. package/build/esm/lib/adapter/defaultObjs.js +5 -0
  64. package/build/esm/lib/adapter/defaultObjs.js.map +1 -1
  65. package/build/esm/lib/adapter/log.d.ts +25 -0
  66. package/build/esm/lib/adapter/log.d.ts.map +1 -1
  67. package/build/esm/lib/adapter/log.js +25 -0
  68. package/build/esm/lib/adapter/log.js.map +1 -1
  69. package/build/esm/lib/adapter/managers/AdapterContextBase.d.ts +49 -0
  70. package/build/esm/lib/adapter/managers/AdapterContextBase.d.ts.map +1 -0
  71. package/build/esm/lib/adapter/managers/AdapterContextBase.js +77 -0
  72. package/build/esm/lib/adapter/managers/AdapterContextBase.js.map +1 -0
  73. package/build/esm/lib/adapter/managers/AliasManager.d.ts +103 -0
  74. package/build/esm/lib/adapter/managers/AliasManager.d.ts.map +1 -0
  75. package/build/esm/lib/adapter/managers/AliasManager.js +269 -0
  76. package/build/esm/lib/adapter/managers/AliasManager.js.map +1 -0
  77. package/build/esm/lib/adapter/managers/CertificateManager.d.ts +50 -0
  78. package/build/esm/lib/adapter/managers/CertificateManager.d.ts.map +1 -0
  79. package/build/esm/lib/adapter/managers/CertificateManager.js +142 -0
  80. package/build/esm/lib/adapter/managers/CertificateManager.js.map +1 -0
  81. package/build/esm/lib/adapter/managers/MessagingManager.d.ts +58 -0
  82. package/build/esm/lib/adapter/managers/MessagingManager.d.ts.map +1 -0
  83. package/build/esm/lib/adapter/managers/MessagingManager.js +267 -0
  84. package/build/esm/lib/adapter/managers/MessagingManager.js.map +1 -0
  85. package/build/esm/lib/adapter/managers/SubscriptionManager.d.ts +107 -0
  86. package/build/esm/lib/adapter/managers/SubscriptionManager.d.ts.map +1 -0
  87. package/build/esm/lib/adapter/managers/SubscriptionManager.js +374 -0
  88. package/build/esm/lib/adapter/managers/SubscriptionManager.js.map +1 -0
  89. package/build/esm/lib/adapter/userInterfaceMessagingController.d.ts +10 -0
  90. package/build/esm/lib/adapter/userInterfaceMessagingController.d.ts.map +1 -1
  91. package/build/esm/lib/adapter/userInterfaceMessagingController.js +8 -2
  92. package/build/esm/lib/adapter/userInterfaceMessagingController.js.map +1 -1
  93. package/build/esm/lib/adapter/utils.d.ts.map +1 -1
  94. package/build/esm/lib/adapter/utils.js +1 -1
  95. package/build/esm/lib/adapter/utils.js.map +1 -1
  96. package/build/esm/lib/adapter/validator.d.ts +10 -5
  97. package/build/esm/lib/adapter/validator.d.ts.map +1 -1
  98. package/build/esm/lib/adapter/validator.js +8 -5
  99. package/build/esm/lib/adapter/validator.js.map +1 -1
  100. package/build/tsconfig.build.tsbuildinfo +1 -1
  101. package/package.json +25 -20
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
9
  var __export = (target, all) => {
9
10
  for (var name in all)
10
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -45,14 +46,18 @@ var import_node = __toESM(require("node.extend"), 1);
45
46
  var import_yargs = __toESM(require("yargs/yargs"), 1);
46
47
  var import_fs_extra = __toESM(require("fs-extra"), 1);
47
48
  var url = __toESM(require("node:url"), 1);
48
- var import_plugin_base = require("@iobroker/plugin-base");
49
49
  var import_js_controller_common = require("@iobroker/js-controller-common");
50
50
  var import_utils = require("../../lib/adapter/utils.js");
51
51
  var import_package = __toESM(require("@iobroker/js-controller-adapter/package.json"), 1);
52
52
  var import_log = require("../../lib/adapter/log.js");
53
53
  var import_validator = require("./validator.js");
54
54
  var import_constants = require("../../lib/adapter/constants.js");
55
+ var import_plugin_base = require("@iobroker/plugin-base");
55
56
  var import_userInterfaceMessagingController = require("../../lib/adapter/userInterfaceMessagingController.js");
57
+ var import_asyncAdapter = require("../../lib/adapter/asyncAdapter.js");
58
+ var import_CertificateManager = require("../../lib/adapter/managers/CertificateManager.js");
59
+ var import_AliasManager = require("../../lib/adapter/managers/AliasManager.js");
60
+ var import_SubscriptionManager = require("../../lib/adapter/managers/SubscriptionManager.js");
56
61
  var import_constants2 = require("@iobroker/js-controller-common-db/constants");
57
62
  var import_tools = require("@iobroker/js-controller-common-db/tools");
58
63
  const controllerVersion = import_package.default.version;
@@ -60,6 +65,9 @@ const { FORBIDDEN_CHARS } = import_js_controller_common.tools;
60
65
  const thisDir = url.fileURLToPath(new URL(".", __import_meta_url || `file://${__filename}`));
61
66
  import_js_controller_common.tools.ensureDNSOrder();
62
67
  class AdapterClass extends import_node_events.EventEmitter {
68
+ static {
69
+ __name(this, "AdapterClass");
70
+ }
63
71
  /** Cache of all deprecations which have already been transmitted */
64
72
  reportedDeprecations = /* @__PURE__ */ new Set();
65
73
  /** Instance to access states DB */
@@ -76,14 +84,10 @@ class AdapterClass extends import_node_events.EventEmitter {
76
84
  startedInCompactMode;
77
85
  /** List of instances which want our logs */
78
86
  logList = /* @__PURE__ */ new Set();
79
- aliases = /* @__PURE__ */ new Map();
80
- aliasPatterns = /* @__PURE__ */ new Set();
81
87
  enums = {};
82
88
  eventLoopLags = [];
83
89
  overwriteLogLevel = false;
84
90
  adapterReady = false;
85
- /** Callbacks from sendTo */
86
- messageCallbacks = /* @__PURE__ */ new Map();
87
91
  /**
88
92
  * Contains a live cache of the adapter's states.
89
93
  * NOTE: This is only defined if the adapter was initialized with the option states: true.
@@ -95,7 +99,6 @@ class AdapterClass extends import_node_events.EventEmitter {
95
99
  */
96
100
  oObjects;
97
101
  _stopInProgress = false;
98
- _callbackId = 1;
99
102
  _firstConnection = true;
100
103
  _timers = /* @__PURE__ */ new Set();
101
104
  _intervals = /* @__PURE__ */ new Set();
@@ -104,12 +107,14 @@ class AdapterClass extends import_node_events.EventEmitter {
104
107
  log;
105
108
  performStrictObjectChecks;
106
109
  _logger;
107
- _restartScheduleJob;
110
+ _restartScheduleJob = null;
108
111
  _schedule;
109
112
  namespaceLog;
110
113
  namespace;
111
114
  name;
112
115
  _systemSecret;
116
+ /** Attributes of `encryptedNative`: their values in `this.config` are decrypted on start */
117
+ _decryptedNativeAttributes = new Array();
113
118
  /** Whether the adapter has already terminated */
114
119
  terminated = false;
115
120
  /** The cache of usernames */
@@ -123,8 +128,6 @@ class AdapterClass extends import_node_events.EventEmitter {
123
128
  // todo
124
129
  /** The cache of user groups */
125
130
  groups = {};
126
- /** An array of instances, that support auto subscribe */
127
- autoSubscribe = [];
128
131
  defaultHistory = null;
129
132
  pluginHandler;
130
133
  _reportInterval;
@@ -156,11 +159,9 @@ class AdapterClass extends import_node_events.EventEmitter {
156
159
  /** latitude configured in system.config, only available if requested via AdapterOptions `useFormatDate`*/
157
160
  latitude;
158
161
  _defaultObjs;
159
- _aliasObjectsSubscribed;
160
162
  config = {};
161
163
  host;
162
164
  common;
163
- mboxSubscribed;
164
165
  /** Stop the adapter */
165
166
  stop;
166
167
  version;
@@ -188,6 +189,32 @@ class AdapterClass extends import_node_events.EventEmitter {
188
189
  SUPPORTED_FEATURES = (0, import_utils.getSupportedFeatures)();
189
190
  /** Controller for messaging related functionality */
190
191
  uiMessagingController;
192
+ /** Shared runtime context handed to managers */
193
+ #context;
194
+ #async;
195
+ #certWatchers = /* @__PURE__ */ new Map();
196
+ #aliasInstance;
197
+ /** Lazily-constructed alias subscription manager. */
198
+ get #alias() {
199
+ return this.#aliasInstance ??= new import_AliasManager.AliasManager(this.#context, (id, allowSystem, options) => this._utils.validateId(id, allowSystem, options));
200
+ }
201
+ #subscriptionsInstance;
202
+ /** Lazily-constructed object/file/state subscription manager. */
203
+ get #subscriptions() {
204
+ return this.#subscriptionsInstance ??= new import_SubscriptionManager.SubscriptionManager(this.#context, (id, isPattern) => this._utils.fixId(id, isPattern), this.#alias, {
205
+ getForeignStateObjects: /* @__PURE__ */ __name((pattern, options) => (
206
+ // @ts-expect-error adjust types
207
+ this.getForeignObjectsAsync(pattern, null, null, options)
208
+ ), "getForeignStateObjects")
209
+ });
210
+ }
211
+ /** True once `system.certificates` is subscribed, i.e. certificates have been requested */
212
+ #certObjectSubscribed = false;
213
+ /** True once a certificate change scheduled a restart, so concurrent changes schedule only one */
214
+ #certRestartScheduled = false;
215
+ /**
216
+ * @param options Adapter options, or the adapter name as a string
217
+ */
191
218
  constructor(options) {
192
219
  super();
193
220
  if (typeof options === "string") {
@@ -309,12 +336,41 @@ class AdapterClass extends import_node_events.EventEmitter {
309
336
  subscribeCallback: this._options.uiClientSubscribe,
310
337
  unsubscribeCallback: this._options.uiClientUnsubscribe
311
338
  });
339
+ const self = this;
340
+ this.#context = {
341
+ logger: this._logger,
342
+ uiMessagingController: this.uiMessagingController,
343
+ countOutput: /* @__PURE__ */ __name(() => {
344
+ self.outputCount++;
345
+ }, "countOutput"),
346
+ get namespace() {
347
+ return self.namespace;
348
+ },
349
+ get namespaceLog() {
350
+ return self.namespaceLog;
351
+ },
352
+ get host() {
353
+ return self.host;
354
+ },
355
+ get states() {
356
+ return self.#states;
357
+ },
358
+ get objects() {
359
+ return self.#objects;
360
+ },
361
+ get common() {
362
+ return self.common;
363
+ },
364
+ get config() {
365
+ return self.config;
366
+ }
367
+ };
368
+ this.#async = new import_asyncAdapter.AsyncAdapter(this.#context);
312
369
  this.getPortAsync = import_js_controller_common.tools.promisifyNoError(this.getPort, this);
313
370
  this.checkPasswordAsync = import_js_controller_common.tools.promisifyNoError(this.checkPassword, this);
314
371
  this.setPasswordAsync = import_js_controller_common.tools.promisify(this.setPassword, this);
315
372
  this.checkGroupAsync = import_js_controller_common.tools.promisifyNoError(this.checkGroup, this);
316
373
  this.calculatePermissionsAsync = import_js_controller_common.tools.promisifyNoError(this.calculatePermissions, this);
317
- this.getCertificatesAsync = import_js_controller_common.tools.promisify(this.getCertificates, this);
318
374
  this.setObjectAsync = import_js_controller_common.tools.promisify(this.setObject, this);
319
375
  this.getAdapterObjectsAsync = import_js_controller_common.tools.promisifyNoError(this.getAdapterObjects, this);
320
376
  this.extendObjectAsync = import_js_controller_common.tools.promisify(this.extendObject, this);
@@ -361,7 +417,6 @@ class AdapterClass extends import_node_events.EventEmitter {
361
417
  this.readFileAsync = import_js_controller_common.tools.promisify(this.readFile, this, ["file", "mimeType"]);
362
418
  this.writeFileAsync = import_js_controller_common.tools.promisify(this.writeFile, this);
363
419
  this.fileExistsAsync = import_js_controller_common.tools.promisify(this.fileExists, this);
364
- this.sendToHostAsync = import_js_controller_common.tools.promisifyNoError(this.sendToHost, this);
365
420
  this.setStateAsync = import_js_controller_common.tools.promisify(this.setState, this);
366
421
  this.setStateChangedAsync = import_js_controller_common.tools.promisify(this.setStateChanged, this, ["id", "notChanged"]);
367
422
  this.setForeignStateAsync = import_js_controller_common.tools.promisify(this.setForeignState, this);
@@ -378,7 +433,7 @@ class AdapterClass extends import_node_events.EventEmitter {
378
433
  this.subscribeStatesAsync = import_js_controller_common.tools.promisify(this.subscribeStates, this);
379
434
  this.unsubscribeStatesAsync = import_js_controller_common.tools.promisify(this.unsubscribeStates, this);
380
435
  this.setExecutableCapabilities = import_js_controller_common.tools.setExecutableCapabilities;
381
- this._init();
436
+ this._init().catch((e) => this._logger.error(`${this.namespaceLog} Cannot initialize adapter: ${e.message}`));
382
437
  }
383
438
  /**
384
439
  * Get the adapter scoped package identifier of a node module
@@ -468,6 +523,12 @@ class AdapterClass extends import_node_events.EventEmitter {
468
523
  return import_js_controller_common.tools.encrypt(secretVal, value);
469
524
  }
470
525
  // unknown guard implementation
526
+ /**
527
+ * Read a session from the states DB
528
+ *
529
+ * @param id the session id
530
+ * @param callback return result
531
+ */
471
532
  getSession(id, callback) {
472
533
  import_validator.Validator.assertString(id, "id");
473
534
  import_validator.Validator.assertCallback(callback, "callback");
@@ -477,11 +538,19 @@ class AdapterClass extends import_node_events.EventEmitter {
477
538
  _getSession(options) {
478
539
  if (!this.#states) {
479
540
  this._logger.info(`${this.namespaceLog} getSession not processed because States database not connected`);
480
- return import_js_controller_common.tools.maybeCallbackWithError(options.callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
541
+ return import_js_controller_common.tools.maybeCallback(options.callback, null);
481
542
  }
482
- this.#states.getSession(options.id, options.callback);
543
+ this.#states.getSession(options.id, (err, session) => import_js_controller_common.tools.maybeCallback(options.callback, session || null));
483
544
  }
484
545
  // unknown implementation guards
546
+ /**
547
+ * Store a session in the states DB
548
+ *
549
+ * @param id the session id
550
+ * @param ttl time to live in seconds
551
+ * @param data the session data to store
552
+ * @param callback return result
553
+ */
485
554
  setSession(id, ttl, data, callback) {
486
555
  import_validator.Validator.assertString(id, "id");
487
556
  import_validator.Validator.assertOptionalCallback(callback, "callback");
@@ -495,8 +564,14 @@ class AdapterClass extends import_node_events.EventEmitter {
495
564
  this._logger.info(`${this.namespaceLog} setSession not processed because States database not connected`);
496
565
  return import_js_controller_common.tools.maybeCallbackWithError(options.callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
497
566
  }
498
- this.#states.setSession(options.id, options.ttl, options.data, options.callback);
567
+ return options.callback ? this.#states.setSession(options.id, options.ttl, options.data, options.callback) : this.#states.setSession(options.id, options.ttl, options.data);
499
568
  }
569
+ /**
570
+ * Destroy a session in the states DB
571
+ *
572
+ * @param id the session id
573
+ * @param callback return result
574
+ */
500
575
  destroySession(id, callback) {
501
576
  import_validator.Validator.assertString(id, "id");
502
577
  import_validator.Validator.assertOptionalCallback(callback, "callback");
@@ -507,12 +582,11 @@ class AdapterClass extends import_node_events.EventEmitter {
507
582
  this._logger.info(`${this.namespaceLog} destroySession not processed because States database not connected`);
508
583
  return import_js_controller_common.tools.maybeCallbackWithError(options.callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
509
584
  }
510
- this.#states.destroySession(options.id, options.callback);
585
+ return options.callback ? this.#states.destroySession(options.id, options.callback) : this.#states.destroySession(options.id);
511
586
  }
512
587
  async _getObjectsByArray(keys, options) {
513
588
  try {
514
- const res = await this.#objects.getObjects(keys, options);
515
- return res;
589
+ return await this.#objects.getObjects(keys, options);
516
590
  } catch (e) {
517
591
  this._logger.error(`Could not get objects by array: ${e.message}`);
518
592
  return [];
@@ -532,7 +606,7 @@ class AdapterClass extends import_node_events.EventEmitter {
532
606
  }
533
607
  this.terminated = true;
534
608
  let shutdownStarted = false;
535
- const shutdownLogic = () => {
609
+ const shutdownLogic = /* @__PURE__ */ __name(() => {
536
610
  if (shutdownStarted) {
537
611
  return;
538
612
  }
@@ -586,7 +660,7 @@ class AdapterClass extends import_node_events.EventEmitter {
586
660
  process.exit(_exitCode);
587
661
  }
588
662
  }, 500);
589
- };
663
+ }, "shutdownLogic");
590
664
  if (this.pluginHandler) {
591
665
  this.pluginHandler.destroyAll().then(() => shutdownLogic()).catch(() => shutdownLogic());
592
666
  } else {
@@ -818,7 +892,7 @@ class AdapterClass extends import_node_events.EventEmitter {
818
892
  options.user = this.usernames[options.user].id;
819
893
  }
820
894
  }
821
- this.getForeignObject(options.user, options, (err, obj) => {
895
+ this.getForeignObject(options.user, options.options, (err, obj) => {
822
896
  if (err || !obj) {
823
897
  return import_js_controller_common.tools.maybeCallbackWithError(options.callback, "User does not exist");
824
898
  }
@@ -895,11 +969,11 @@ class AdapterClass extends import_node_events.EventEmitter {
895
969
  if (options.group && !options.group.startsWith("system.group.")) {
896
970
  options.group = `system.group.${options.group}`;
897
971
  }
898
- this.getForeignObject(options.user, options, (err, obj) => {
972
+ this.getForeignObject(options.user, options.options, (err, obj) => {
899
973
  if (err || !obj) {
900
974
  return import_js_controller_common.tools.maybeCallback(options.callback, false);
901
975
  }
902
- this.getForeignObject(options.group, options, (err2, obj2) => {
976
+ return this.getForeignObject(options.group, options.options, (err2, obj2) => {
903
977
  if (err2 || !obj2) {
904
978
  return import_js_controller_common.tools.maybeCallback(options.callback, false);
905
979
  }
@@ -1004,7 +1078,7 @@ class AdapterClass extends import_node_events.EventEmitter {
1004
1078
  * ```
1005
1079
  */
1006
1080
  calculatePermissions(user, commandsPermissions, options, callback) {
1007
- user = user || "";
1081
+ user ||= "";
1008
1082
  if (typeof options === "function") {
1009
1083
  callback = options;
1010
1084
  options = null;
@@ -1017,7 +1091,12 @@ class AdapterClass extends import_node_events.EventEmitter {
1017
1091
  import_validator.Validator.assertObject(options, "options");
1018
1092
  }
1019
1093
  import_validator.Validator.assertOptionalCallback(callback, "callback");
1020
- return this._calculatePermissions({ user, commandsPermissions, options, callback });
1094
+ return this._calculatePermissions({
1095
+ user,
1096
+ commandsPermissions,
1097
+ options,
1098
+ callback
1099
+ });
1021
1100
  }
1022
1101
  async _calculatePermissions(options) {
1023
1102
  const { user } = options;
@@ -1102,15 +1181,15 @@ class AdapterClass extends import_node_events.EventEmitter {
1102
1181
  try {
1103
1182
  for (const type of Object.keys(gAcl)) {
1104
1183
  if (type === "user") {
1105
- acl.users = acl.users || {};
1184
+ acl.users ||= {};
1106
1185
  } else {
1107
- acl[type] = acl[type] || {};
1186
+ acl[type] ||= {};
1108
1187
  }
1109
1188
  for (const op of Object.keys(gAcl[type])) {
1110
1189
  if (type === "user") {
1111
- acl.users[op] = acl.users[op] || gAcl.user[op];
1190
+ acl.users[op] ||= gAcl.user[op];
1112
1191
  } else {
1113
- acl[type][op] = acl[type][op] || gAcl[type][op];
1192
+ acl[type][op] ||= gAcl[type][op];
1114
1193
  }
1115
1194
  }
1116
1195
  }
@@ -1142,7 +1221,7 @@ class AdapterClass extends import_node_events.EventEmitter {
1142
1221
  this._reportInterval && clearInterval(this._reportInterval);
1143
1222
  this._reportInterval = null;
1144
1223
  const id = `system.adapter.${this.namespace}`;
1145
- const finishUnload = async () => {
1224
+ const finishUnload = /* @__PURE__ */ __name(async () => {
1146
1225
  if (this._timers.size) {
1147
1226
  this._timers.forEach((timer) => clearTimeout(timer));
1148
1227
  this._timers.clear();
@@ -1155,10 +1234,8 @@ class AdapterClass extends import_node_events.EventEmitter {
1155
1234
  this._delays.forEach((timer) => clearTimeout(timer));
1156
1235
  this._delays.clear();
1157
1236
  }
1158
- if (this.messageCallbacks.size) {
1159
- this.messageCallbacks.forEach((callbackObj) => clearTimeout(callbackObj.timer));
1160
- this.messageCallbacks.clear();
1161
- }
1237
+ this.#async.clearPending();
1238
+ await this.stopWatchingCertificates();
1162
1239
  if (this.#states && updateAliveState) {
1163
1240
  this.outputCount++;
1164
1241
  try {
@@ -1171,14 +1248,17 @@ class AdapterClass extends import_node_events.EventEmitter {
1171
1248
  this._logger.info(`${this.namespaceLog} terminating`);
1172
1249
  }
1173
1250
  this.terminate(reason, exitCode);
1174
- };
1251
+ }, "finishUnload");
1175
1252
  if (this.adapterReady) {
1176
1253
  if (typeof this._options.unload === "function") {
1177
1254
  if (this._options.unload.length >= 1) {
1178
1255
  try {
1179
- this._options.unload(finishUnload);
1256
+ const unloadResult = this._options.unload(finishUnload);
1257
+ if (unloadResult instanceof Promise) {
1258
+ unloadResult.catch((e) => this._logger.error(`${this.namespaceLog} Error in unload: ${e.message}`));
1259
+ }
1180
1260
  } catch {
1181
- finishUnload();
1261
+ finishUnload().catch((e) => this._logger.error(`${this.namespaceLog} Error in finishUnload: ${e.message}`));
1182
1262
  }
1183
1263
  } else {
1184
1264
  const unloadPromise = this._options.unload();
@@ -1186,7 +1266,7 @@ class AdapterClass extends import_node_events.EventEmitter {
1186
1266
  try {
1187
1267
  await unloadPromise;
1188
1268
  } finally {
1189
- finishUnload();
1269
+ finishUnload().catch((e) => this._logger.error(`${this.namespaceLog} Error in finishUnload: ${e.message}`));
1190
1270
  }
1191
1271
  } else {
1192
1272
  this._logger.error(`${this.namespaceLog} Error in ${id}: The unload method must return a Promise if it does not accept a callback!`);
@@ -1200,38 +1280,109 @@ class AdapterClass extends import_node_events.EventEmitter {
1200
1280
  if (!this.#states) {
1201
1281
  updateAliveState = false;
1202
1282
  }
1203
- const terminate = () => {
1283
+ const terminate = /* @__PURE__ */ __name(() => {
1204
1284
  if (!isPause) {
1205
1285
  this._logger.info(`${this.namespaceLog} terminating`);
1206
1286
  }
1207
1287
  this.terminate(exitCode);
1208
- };
1288
+ }, "terminate");
1209
1289
  finishUnload().then(terminate, terminate);
1210
1290
  }, this.common?.stopTimeout || 500);
1211
1291
  }
1212
1292
  }
1213
1293
  /**
1214
- * Reads the file certificate from a given path and adds a file watcher to restart adapter on cert changes
1215
- * if a cert is passed it is returned as it is
1294
+ * Installs a restart-on-change watcher for each file-backed certificate path, deduped by path.
1295
+ * A change schedules a graceful restart so the adapter reloads the new certificate.
1216
1296
  *
1217
- * @param cert cert or path to cert
1297
+ * @param paths file-backed certificate paths returned by the certificate manager
1218
1298
  */
1219
- _readFileCertificate(cert) {
1220
- if (typeof cert === "string") {
1299
+ #watchCertFiles(paths) {
1300
+ for (const certFile of paths) {
1301
+ if (this.#certWatchers.has(certFile)) {
1302
+ continue;
1303
+ }
1221
1304
  try {
1222
- if (cert.length < 1024 && import_fs_extra.default.existsSync(cert)) {
1223
- const certFile = cert;
1224
- cert = import_fs_extra.default.readFileSync(certFile, "utf8");
1225
- import_fs_extra.default.watch(certFile, (eventType, filename) => {
1226
- this._logger.warn(`${this.namespaceLog} New certificate "${filename}" detected. Restart adapter`);
1227
- setTimeout(() => this._stop({ isPause: false, isScheduled: true }), 2e3);
1228
- });
1229
- }
1305
+ const watcher = import_fs_extra.default.watch(certFile, (_eventType, filename) => {
1306
+ this.#scheduleCertificateRestart(`New certificate "${filename}" detected`);
1307
+ });
1308
+ this.#certWatchers.set(certFile, watcher);
1230
1309
  } catch (e) {
1231
- this._logger.error(`${this.namespaceLog} Could not read certificate from file ${cert}: ${e.message}`);
1310
+ this._logger.error(`${this.namespaceLog} Cannot watch certificate file ${certFile}: ${e.message}`);
1311
+ }
1312
+ }
1313
+ }
1314
+ /**
1315
+ * Schedules a graceful restart, so the adapter reloads its certificates. Called by both the
1316
+ * file watchers and the `system.certificates` subscription; the first caller wins, so a change
1317
+ * seen through both channels restarts the adapter only once.
1318
+ *
1319
+ * @param reason human-readable cause, logged as a warning
1320
+ */
1321
+ #scheduleCertificateRestart(reason) {
1322
+ if (this.#certRestartScheduled) {
1323
+ return;
1324
+ }
1325
+ this.#certRestartScheduled = true;
1326
+ this._logger.warn(`${this.namespaceLog} ${reason}. Restart adapter`);
1327
+ setTimeout(() => this._stop({ isPause: false, isScheduled: true }), 2e3);
1328
+ }
1329
+ /**
1330
+ * Subscribes to the `system.certificates` object, so inline (text) certificates are watched the
1331
+ * same way file-backed ones are watched on disk. Subscribing on the system level channel keeps
1332
+ * these events out of the adapter's own `objectChange` handler.
1333
+ *
1334
+ * Called after certificates have been requested, so only adapters actually using certificates
1335
+ * pay for the subscription.
1336
+ */
1337
+ async #subscribeCertObject() {
1338
+ if (this.#certObjectSubscribed || !this.#objects) {
1339
+ return;
1340
+ }
1341
+ this.#certObjectSubscribed = true;
1342
+ try {
1343
+ await this.#objects.subscribeAsync(import_CertificateManager.CERTIFICATES_OBJECT_ID);
1344
+ if (!this.#certObjectSubscribed && this.#objects) {
1345
+ await this.#objects.unsubscribeAsync(import_CertificateManager.CERTIFICATES_OBJECT_ID);
1346
+ }
1347
+ } catch (e) {
1348
+ this.#certObjectSubscribed = false;
1349
+ this._logger.error(`${this.namespaceLog} Cannot watch certificate object ${import_CertificateManager.CERTIFICATES_OBJECT_ID}: ${e.message}`);
1350
+ }
1351
+ }
1352
+ /**
1353
+ * Tears down the certificate watching installed by {@link getCertificatesAsync}: closes the file
1354
+ * watchers, unsubscribes from `system.certificates`, and forgets the certificates handed out by the
1355
+ * last call, so a later change no longer schedules a restart. Called on adapter stop.
1356
+ */
1357
+ async stopWatchingCertificates() {
1358
+ for (const watcher of this.#certWatchers.values()) {
1359
+ watcher.close();
1360
+ }
1361
+ this.#certWatchers.clear();
1362
+ this.#certRestartScheduled = false;
1363
+ this.#async.stopWatchingCertificates();
1364
+ if (this.#certObjectSubscribed && this.#objects) {
1365
+ this.#certObjectSubscribed = false;
1366
+ try {
1367
+ await this.#objects.unsubscribeAsync(import_CertificateManager.CERTIFICATES_OBJECT_ID);
1368
+ } catch {
1232
1369
  }
1233
1370
  }
1234
- return cert;
1371
+ }
1372
+ /**
1373
+ * Loads SSL certificates by name and installs restart-on-change watchers: file watchers for
1374
+ * file-backed certificate values, and a subscription to `system.certificates` covering inline
1375
+ * ones and repointed paths.
1376
+ *
1377
+ * @param publicName public certificate name (defaults to `config.certPublic`)
1378
+ * @param privateName private key name (defaults to `config.certPrivate`)
1379
+ * @param chainedName chained certificate name (defaults to `config.certChained`)
1380
+ */
1381
+ async getCertificatesAsync(publicName, privateName, chainedName) {
1382
+ const { certs, useLetsEncrypt, certFilePaths } = await this.#async.getCertificates(publicName, privateName, chainedName);
1383
+ this.#watchCertFiles(certFilePaths);
1384
+ await this.#subscribeCertObject();
1385
+ return [certs, useLetsEncrypt];
1235
1386
  }
1236
1387
  /**
1237
1388
  * returns SSL certificates by name
@@ -1265,59 +1416,16 @@ class AdapterClass extends import_node_events.EventEmitter {
1265
1416
  callback = chainedName;
1266
1417
  chainedName = void 0;
1267
1418
  }
1268
- const config = this.config;
1269
- publicName = publicName || config.certPublic;
1270
- privateName = privateName || config.certPrivate;
1271
- chainedName = chainedName || config.certChained;
1272
- if (publicName !== void 0) {
1273
- import_validator.Validator.assertString(publicName, "publicName");
1274
- }
1275
- if (privateName !== void 0) {
1276
- import_validator.Validator.assertString(privateName, "privateName");
1277
- }
1278
- if (chainedName !== void 0) {
1279
- import_validator.Validator.assertString(chainedName, "chainedName");
1280
- }
1281
1419
  import_validator.Validator.assertOptionalCallback(callback, "callback");
1282
- return this._getCertificates({ publicName, privateName, chainedName, callback });
1283
- }
1284
- async _getCertificates(options) {
1285
- const { publicName, chainedName, privateName, callback } = options;
1286
- let obj;
1287
- if (!this.#objects) {
1288
- this._logger.info(`${this.namespaceLog} getCertificates not processed because Objects database not connected`);
1289
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
1290
- }
1291
- try {
1292
- obj = await this.#objects.getObject("system.certificates");
1293
- } catch {
1294
- }
1295
- if (!obj || !obj.native.certificates || !publicName || !privateName || !obj.native.certificates[publicName] || !obj.native.certificates[privateName] || chainedName && !obj.native.certificates[chainedName]) {
1296
- this._logger.error(`${this.namespaceLog} Cannot configure secure web server, because no certificates found: ${publicName}, ${privateName}, ${chainedName}`);
1297
- if (publicName === "defaultPublic" || privateName === "defaultPrivate") {
1298
- this._logger.info(`${this.namespaceLog} Default certificates seem to be configured but missing. You can execute "iobroker cert create" in your shell to create these.`);
1299
- }
1300
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_NOT_FOUND);
1301
- }
1302
- let ca;
1303
- if (chainedName) {
1304
- const chained = this._readFileCertificate(obj.native.certificates[chainedName]).split("-----END CERTIFICATE-----\r\n");
1305
- if (chained.join("").length >= 512) {
1306
- const caArr = [];
1307
- for (const cert of chained) {
1308
- if (cert.replace(/(\r\n|\r|\n)/g, "").trim()) {
1309
- caArr.push(`${cert}-----END CERTIFICATE-----\r
1310
- `);
1311
- }
1312
- }
1313
- ca = caArr.join("");
1314
- }
1420
+ const cb = callback;
1421
+ if (typeof cb === "function") {
1422
+ return this.getCertificatesAsync(publicName, privateName, chainedName).then(([certs, useLetsEncrypt]) => {
1423
+ cb(null, certs, useLetsEncrypt);
1424
+ }, (err) => {
1425
+ cb(err);
1426
+ });
1315
1427
  }
1316
- return import_js_controller_common.tools.maybeCallbackWithError(callback, null, {
1317
- key: this._readFileCertificate(obj.native.certificates[privateName]),
1318
- cert: this._readFileCertificate(obj.native.certificates[publicName]),
1319
- ca
1320
- }, obj.native.letsEncrypt);
1428
+ return this.getCertificatesAsync(publicName, privateName, chainedName);
1321
1429
  }
1322
1430
  /**
1323
1431
  * Restarts an instance of the adapter.
@@ -1326,7 +1434,7 @@ class AdapterClass extends import_node_events.EventEmitter {
1326
1434
  restart() {
1327
1435
  if (this.stop) {
1328
1436
  this._logger.warn(`${this.namespaceLog} Restart initiated`);
1329
- this.stop();
1437
+ this.stop().catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
1330
1438
  } else {
1331
1439
  this._logger.warn(`${this.namespaceLog} Cannot initiate restart, because this.stop is not defined`);
1332
1440
  }
@@ -1389,7 +1497,7 @@ class AdapterClass extends import_node_events.EventEmitter {
1389
1497
  return this.setForeignObjectAsync(configObjId, obj);
1390
1498
  }
1391
1499
  /**
1392
- * Reads the encrypted parameter from config.
1500
+ * Reads a parameter which is stored encrypted and returns its decrypted value.
1393
1501
  *
1394
1502
  * It returns promise if no callback is provided.
1395
1503
  *
@@ -1404,14 +1512,12 @@ class AdapterClass extends import_node_events.EventEmitter {
1404
1512
  async _getEncryptedConfig(options) {
1405
1513
  const { attribute, callback } = options;
1406
1514
  const value = (0, import_utils.getObjectAttribute)(this.config, attribute);
1515
+ if ((Array.isArray(value) || typeof value === "string") && this._decryptedNativeAttributes.includes(attribute)) {
1516
+ return import_js_controller_common.tools.maybeCallbackWithError(callback, null, value);
1517
+ }
1407
1518
  if (Array.isArray(value)) {
1408
1519
  const secret = await this.getSystemSecret();
1409
- const result = [];
1410
- for (let i = 0; i < value.length; i++) {
1411
- if (typeof value[i] === "string") {
1412
- result[i] = import_js_controller_common.tools.decrypt(secret, value[i]);
1413
- }
1414
- }
1520
+ const result = value.map((item) => typeof item === "string" ? import_js_controller_common.tools.decrypt(secret, item) : item);
1415
1521
  return import_js_controller_common.tools.maybeCallbackWithError(callback, null, result);
1416
1522
  } else if (typeof value === "string") {
1417
1523
  const secret = await this.getSystemSecret();
@@ -1705,13 +1811,13 @@ class AdapterClass extends import_node_events.EventEmitter {
1705
1811
  }
1706
1812
  async _getAdapterObjects(options) {
1707
1813
  const ret = {};
1708
- const addRows = (rows) => {
1814
+ const addRows = /* @__PURE__ */ __name((rows) => {
1709
1815
  if (rows) {
1710
1816
  for (const { id, value } of rows) {
1711
1817
  ret[id] = value;
1712
1818
  }
1713
1819
  }
1714
- };
1820
+ }, "addRows");
1715
1821
  if (!this.#objects) {
1716
1822
  return import_js_controller_common.tools.maybeCallback(options.callback, ret);
1717
1823
  }
@@ -1767,7 +1873,7 @@ class AdapterClass extends import_node_events.EventEmitter {
1767
1873
  * }
1768
1874
  * ```
1769
1875
  *
1770
- * If following object will be passed as argument
1876
+ * If the following object will be passed as an argument
1771
1877
  *
1772
1878
  * ```js
1773
1879
  * {
@@ -1868,28 +1974,28 @@ class AdapterClass extends import_node_events.EventEmitter {
1868
1974
  this._logger.error(`${this.namespaceLog} Object ${options.id} not exist!`);
1869
1975
  oldObj = {};
1870
1976
  }
1871
- if (options.obj.native && "repositories" in options.obj.native && oldObj.native && oldObj.native.repositories) {
1872
- oldObj.native.repositories = [];
1977
+ if (options.obj.native && "repositories" in options.obj.native && oldObj.native?.repositories) {
1978
+ oldObj.native.repositories = {};
1873
1979
  }
1874
- if (options.obj.common && "members" in options.obj.common && oldObj.common && oldObj.common.members) {
1980
+ if (options.obj.common && "members" in options.obj.common && oldObj.common?.members) {
1875
1981
  oldObj.common.members = [];
1876
1982
  }
1877
- if (options.obj.native && "certificates" in options.obj.native && oldObj.native && oldObj.native.certificates) {
1878
- oldObj.native.certificates = [];
1983
+ if (options.obj.native && "certificates" in options.obj.native && oldObj.native?.certificates) {
1984
+ oldObj.native.certificates = {};
1879
1985
  }
1880
- if (options.obj.native && "devices" in options.obj.native && oldObj.native && oldObj.native.devices) {
1986
+ if (options.obj.native && "devices" in options.obj.native && oldObj.native?.devices) {
1881
1987
  oldObj.native.devices = [];
1882
1988
  }
1883
- options.obj.from = options.obj.from || `system.adapter.${this.namespace}`;
1884
- options.obj.user = options.obj.user || (options.options ? options.options.user : "") || import_constants.SYSTEM_ADMIN_USER;
1885
- options.obj.ts = options.obj.ts || Date.now();
1989
+ options.obj.from ||= `system.adapter.${this.namespace}`;
1990
+ options.obj.user ||= (options.options ? options.options.user : "") || import_constants.SYSTEM_ADMIN_USER;
1991
+ options.obj.ts ||= Date.now();
1886
1992
  options.obj = (0, import_node.default)(true, oldObj, options.obj);
1887
1993
  return this.#objects.setObject(options.id, options.obj, options.options, options.callback);
1888
1994
  }
1889
- options.obj.from = options.obj.from || `system.adapter.${this.namespace}`;
1890
- options.obj.user = options.obj.user || (options.options ? options.options.user : "") || import_constants.SYSTEM_ADMIN_USER;
1891
- options.obj.ts = options.obj.ts || Date.now();
1892
- if (options.obj.type && options.obj.type === "state" || !options.obj.type && oldObj && oldObj.type === "state") {
1995
+ options.obj.from ||= `system.adapter.${this.namespace}`;
1996
+ options.obj.user ||= (options.options ? options.options.user : "") || import_constants.SYSTEM_ADMIN_USER;
1997
+ options.obj.ts ||= Date.now();
1998
+ if (options.obj?.type === "state" || !options.obj.type && oldObj?.type === "state") {
1893
1999
  if (options.obj.common && "custom" in options.obj.common && options.obj.common.custom !== null && !import_js_controller_common.tools.isObject(options.obj.common.custom)) {
1894
2000
  this._logger.error(`${this.namespaceLog} extendObject ${options.id} (type=${options.obj.type}) property common.custom is of type ${typeof options.obj.common.custom}, expected object.`);
1895
2001
  return import_js_controller_common.tools.maybeCallbackWithError(options.callback, "common.custom needs to be an object");
@@ -1904,12 +2010,12 @@ class AdapterClass extends import_node_events.EventEmitter {
1904
2010
  return this.setForeignObject(options.id, options.obj, options.options, options.callback);
1905
2011
  }
1906
2012
  try {
1907
- const cbObj = await this.#objects.extendObjectAsync(options.id, options.obj, options.options || {});
2013
+ const cbObj = await this.#objects.extendObject(options.id, options.obj, options.options);
1908
2014
  let defState;
1909
2015
  if (options.obj.type === "state" || oldObj.type === "state") {
1910
2016
  if (options.obj.common && "def" in options.obj.common && options.obj.common.def !== void 0) {
1911
2017
  defState = options.obj.common.def;
1912
- } else if (oldObj.common && oldObj.common.def !== void 0) {
2018
+ } else if (oldObj.common?.def !== void 0) {
1913
2019
  defState = oldObj.common.def;
1914
2020
  }
1915
2021
  }
@@ -2068,28 +2174,28 @@ class AdapterClass extends import_node_events.EventEmitter {
2068
2174
  this._logger.error(`${this.namespaceLog} Object ${id} not exist!`);
2069
2175
  oldObj = {};
2070
2176
  }
2071
- if (obj.native && "repositories" in obj.native && oldObj.native && oldObj.native.repositories) {
2072
- oldObj.native.repositories = [];
2177
+ if (obj.native && "repositories" in obj.native && oldObj.native?.repositories) {
2178
+ oldObj.native.repositories = {};
2073
2179
  }
2074
- if (obj.common && "members" in obj.common && oldObj.common && oldObj.common.members) {
2180
+ if (obj.common && "members" in obj.common && oldObj.common?.members) {
2075
2181
  oldObj.common.members = [];
2076
2182
  }
2077
- if (obj.native && "certificates" in obj.native && oldObj.native && oldObj.native.certificates) {
2078
- oldObj.native.certificates = [];
2183
+ if (obj.native && "certificates" in obj.native && oldObj.native?.certificates) {
2184
+ oldObj.native.certificates = {};
2079
2185
  }
2080
- if (obj.native && "devices" in obj.native && oldObj.native && oldObj.native.devices) {
2186
+ if (obj.native && "devices" in obj.native && oldObj.native?.devices) {
2081
2187
  oldObj.native.devices = [];
2082
2188
  }
2083
- obj.from = obj.from || `system.adapter.${this.namespace}`;
2084
- obj.user = obj.user || options?.user || import_constants.SYSTEM_ADMIN_USER;
2085
- obj.ts = obj.ts || Date.now();
2189
+ obj.from ||= `system.adapter.${this.namespace}`;
2190
+ obj.user ||= options?.user || import_constants.SYSTEM_ADMIN_USER;
2191
+ obj.ts ||= Date.now();
2086
2192
  obj = (0, import_node.default)(true, oldObj, obj);
2087
- return this.#objects.setObject(id, obj, options, callback);
2193
+ return callback ? this.#objects.setObject(id, obj, options, callback) : this.#objects.setObject(id, obj, options);
2088
2194
  }
2089
- obj.from = obj.from || `system.adapter.${this.namespace}`;
2090
- obj.user = obj.user || options?.user || import_constants.SYSTEM_ADMIN_USER;
2091
- obj.ts = obj.ts || Date.now();
2092
- if (obj.type && obj.type === "state" || !obj.type && oldObj && oldObj.type === "state") {
2195
+ obj.from ||= `system.adapter.${this.namespace}`;
2196
+ obj.user ||= options?.user || import_constants.SYSTEM_ADMIN_USER;
2197
+ obj.ts ||= Date.now();
2198
+ if (obj.type && obj.type === "state" || !obj.type && oldObj?.type === "state") {
2093
2199
  if (obj.common && "custom" in obj.common && obj.common.custom !== null && !import_js_controller_common.tools.isObject(obj.common.custom)) {
2094
2200
  this._logger.error(`${this.namespaceLog} extendObject ${id} (type=${obj.type}) property common.custom is of type ${typeof obj.common.custom}, expected object.`);
2095
2201
  return import_js_controller_common.tools.maybeCallbackWithError(callback, "common.custom needs to be an object");
@@ -2104,12 +2210,12 @@ class AdapterClass extends import_node_events.EventEmitter {
2104
2210
  return this.setForeignObject(id, obj, options, callback);
2105
2211
  }
2106
2212
  try {
2107
- const cbObj = await this.#objects.extendObjectAsync(id, obj, options || {});
2213
+ const cbObj = await this.#objects.extendObject(id, obj, options);
2108
2214
  if (cbObj?.value.type === "state") {
2109
2215
  let defState;
2110
- if (obj.common && "def" in obj.common && obj.common.def !== void 0) {
2216
+ if (obj.common && "def" in obj.common && obj.common?.def !== void 0) {
2111
2217
  defState = obj.common.def;
2112
- } else if (oldObj.common && oldObj.common.def !== void 0) {
2218
+ } else if (oldObj.common?.def !== void 0) {
2113
2219
  defState = oldObj.common.def;
2114
2220
  }
2115
2221
  if (defState !== void 0) {
@@ -2242,7 +2348,7 @@ class AdapterClass extends import_node_events.EventEmitter {
2242
2348
  import_validator.Validator.assertString(design, "design");
2243
2349
  import_validator.Validator.assertString(search, "search");
2244
2350
  import_validator.Validator.assertOptionalCallback(callback, "callback");
2245
- params = params || {};
2351
+ params ||= {};
2246
2352
  import_validator.Validator.assertObject(params, "params");
2247
2353
  if (options !== null && options !== void 0) {
2248
2354
  import_validator.Validator.assertObject(options, "options");
@@ -2503,9 +2609,7 @@ class AdapterClass extends import_node_events.EventEmitter {
2503
2609
  if (!parts[2]) {
2504
2610
  continue;
2505
2611
  }
2506
- if (!result[`${parts[0]}.${parts[1]}`]) {
2507
- result[`${parts[0]}.${parts[1]}`] = {};
2508
- }
2612
+ result[`${parts[0]}.${parts[1]}`] ||= {};
2509
2613
  result[`${parts[0]}.${parts[1]}`][row.id] = row.value;
2510
2614
  }
2511
2615
  }
@@ -2712,7 +2816,7 @@ class AdapterClass extends import_node_events.EventEmitter {
2712
2816
  * @param options optional user context with language
2713
2817
  * @param options.user current user
2714
2818
  * @param options.language language in which the search must be done for multi-language names
2715
- * @result if the object was found by ID it will return id and may be the multi-language name it exists. If the object was found by name it will return id and the multi-language name. If the object was not found, it will return only name that was searched for.
2819
+ * @returns if the object was found by ID it will return id and may be the multi-language name it exists. If the object was found by name it will return id and the multi-language name. If the object was not found, it will return only name that was searched for.
2716
2820
  */
2717
2821
  findForeignObjectAsync(id, type, options) {
2718
2822
  return new Promise((resolve, reject) => this.findForeignObject(id, type, options || {}, (err, id2, name) => {
@@ -2759,8 +2863,8 @@ class AdapterClass extends import_node_events.EventEmitter {
2759
2863
  return import_js_controller_common.tools.maybeCallbackWithError(options.callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
2760
2864
  }
2761
2865
  try {
2762
- const obj = await this.#objects.getObjectAsync(options.id, options);
2763
- if (obj && "protectedNative" in obj && Array.isArray(obj.protectedNative) && obj._id && obj._id.startsWith("system.adapter.") && obj.native && !import_constants.NO_PROTECT_ADAPTERS.includes(this.name) && this.name !== obj._id.split(".")[2]) {
2866
+ const obj = await this.#objects.getObjectAsync(options.id, options.options);
2867
+ if (obj?.native && "protectedNative" in obj && Array.isArray(obj.protectedNative) && obj._id?.startsWith("system.adapter.") && !import_constants.NO_PROTECT_ADAPTERS.includes(this.name) && this.name !== obj._id.split(".")[2]) {
2764
2868
  for (const attr of obj.protectedNative) {
2765
2869
  (0, import_utils.deleteObjectAttribute)(obj.native, attr);
2766
2870
  }
@@ -2792,29 +2896,32 @@ class AdapterClass extends import_node_events.EventEmitter {
2792
2896
  id = this._utils.fixId(id);
2793
2897
  this.delForeignObject(id, options, callback);
2794
2898
  }
2795
- _deleteObjects(tasks, options, cb) {
2796
- if (!tasks || !tasks.length) {
2899
+ async _deleteObjects(tasks, options, cb) {
2900
+ if (!tasks?.length) {
2797
2901
  return import_js_controller_common.tools.maybeCallback(cb);
2798
2902
  }
2799
- const task = tasks.shift();
2800
- this.#objects.delObject(task.id, options, async (err) => {
2801
- if (err) {
2802
- return import_js_controller_common.tools.maybeCallbackWithError(cb, err);
2803
- }
2804
- if (task.state) {
2903
+ try {
2904
+ for (const task of tasks) {
2905
+ await new Promise((resolve, reject) => this.#objects.delObject(task.id, options, (err) => {
2906
+ err ? reject(err) : resolve();
2907
+ }));
2908
+ if (task.state) {
2909
+ try {
2910
+ await this.delForeignStateAsync(task.id, options);
2911
+ } catch (e) {
2912
+ this._logger.warn(`${this.namespaceLog} Could not remove state of ${task.id}: ${e.message}`);
2913
+ }
2914
+ }
2805
2915
  try {
2806
- await this.delForeignStateAsync(task.id, options);
2916
+ await import_js_controller_common.tools.removeIdFromAllEnums(this.#objects, task.id, this.enums);
2807
2917
  } catch (e) {
2808
- this._logger.warn(`${this.namespaceLog} Could not remove state of ${task.id}: ${e.message}`);
2918
+ this._logger.warn(`${this.namespaceLog} Could not remove ${task.id} from enums: ${e.message}`);
2809
2919
  }
2810
2920
  }
2811
- try {
2812
- await import_js_controller_common.tools.removeIdFromAllEnums(this.#objects, task.id, this.enums);
2813
- } catch (e) {
2814
- this._logger.warn(`${this.namespaceLog} Could not remove ${task.id} from enums: ${e.message}`);
2815
- }
2816
- setImmediate(() => this._deleteObjects(tasks, options, cb));
2817
- });
2921
+ } catch (err) {
2922
+ return import_js_controller_common.tools.maybeCallbackWithError(cb, err);
2923
+ }
2924
+ return import_js_controller_common.tools.maybeCallback(cb);
2818
2925
  }
2819
2926
  /**
2820
2927
  * Delete any object.
@@ -2862,16 +2969,17 @@ class AdapterClass extends import_node_events.EventEmitter {
2862
2969
  const tasks = obj && (!obj.common || !obj.common.dontDelete) ? [{ id, state: obj.type === "state" }] : [];
2863
2970
  const selector = { startkey: `${id}.`, endkey: `${id}.\u9999` };
2864
2971
  this.#objects.getObjectList(selector, options, (err2, res) => {
2865
- res && res.rows.forEach((item) => !tasks.find((task) => task.id === item.id) && (!item.value || !item.value.common || !item.value.common.dontDelete) && // exclude objects with dontDelete flag
2866
- tasks.push({ id: item.id, state: item.value && item.value.type === "state" }));
2867
- this._deleteObjects(tasks, options, callback);
2972
+ res?.rows.forEach((item) => !tasks.find((task) => task.id === item.id) && !item.value?.common?.dontDelete && // exclude objects with dontDelete flag
2973
+ tasks.push({ id: item.id, state: item.value?.type === "state" }));
2974
+ return this._deleteObjects(tasks, options, callback);
2868
2975
  });
2869
2976
  });
2870
2977
  } else {
2871
2978
  this.#objects.getObject(id, options, async (err, obj) => {
2872
2979
  if (err) {
2873
2980
  return import_js_controller_common.tools.maybeCallbackWithError(callback, err);
2874
- } else if (obj) {
2981
+ }
2982
+ if (obj) {
2875
2983
  if (obj.common?.dontDelete) {
2876
2984
  return import_js_controller_common.tools.maybeCallbackWithError(callback, new Error("not deletable"));
2877
2985
  }
@@ -2918,16 +3026,8 @@ class AdapterClass extends import_node_events.EventEmitter {
2918
3026
  if (options !== null && options !== void 0) {
2919
3027
  import_validator.Validator.assertObject(options, "options");
2920
3028
  }
2921
- if (!this.#objects) {
2922
- this._logger.info(`${this.namespaceLog} subscribeObjects not processed because Objects database not connected`);
2923
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
2924
- }
2925
- if (pattern === "*") {
2926
- this.#objects.subscribeUser(`${this.namespace}.*`, options, callback);
2927
- } else {
2928
- const fixedPattern = Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true);
2929
- this.#objects.subscribeUser(fixedPattern, options, callback);
2930
- }
3029
+ const cb = callback;
3030
+ this.#subscriptions.subscribeObjects(pattern, options).then(() => cb?.(), (err) => cb?.(err));
2931
3031
  }
2932
3032
  /**
2933
3033
  * Unsubscribe on the changes of objects in this instance.
@@ -2951,16 +3051,8 @@ class AdapterClass extends import_node_events.EventEmitter {
2951
3051
  if (options !== null && options !== void 0) {
2952
3052
  import_validator.Validator.assertObject(options, "options");
2953
3053
  }
2954
- if (!this.#objects) {
2955
- this._logger.info(`${this.namespaceLog} unsubscribeObjects not processed because Objects database not connected`);
2956
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
2957
- }
2958
- if (pattern === "*") {
2959
- this.#objects.unsubscribeUser(`${this.namespace}.*`, options, callback);
2960
- } else {
2961
- const fixedPattern = Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true);
2962
- this.#objects.unsubscribeUser(fixedPattern, options, callback);
2963
- }
3054
+ const cb = callback;
3055
+ this.#subscriptions.unsubscribeObjects(pattern, options).then(() => cb?.(), (err) => cb?.(err));
2964
3056
  }
2965
3057
  /**
2966
3058
  * Subscribe for the changes of objects in any instance.
@@ -2984,11 +3076,8 @@ class AdapterClass extends import_node_events.EventEmitter {
2984
3076
  if (options !== null && options !== void 0) {
2985
3077
  import_validator.Validator.assertObject(options, "options");
2986
3078
  }
2987
- if (!this.#objects) {
2988
- this._logger.info(`${this.namespaceLog} subscribeForeignObjects not processed because Objects database not connected`);
2989
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
2990
- }
2991
- this.#objects.subscribeUser(pattern, options, callback);
3079
+ const cb = callback;
3080
+ this.#subscriptions.subscribeForeignObjects(pattern, options).then(() => cb?.(), (err) => cb?.(err));
2992
3081
  }
2993
3082
  /**
2994
3083
  * Unsubscribe for the patterns on all objects.
@@ -3015,11 +3104,8 @@ class AdapterClass extends import_node_events.EventEmitter {
3015
3104
  if (options !== null && options !== void 0) {
3016
3105
  import_validator.Validator.assertObject(options, "options");
3017
3106
  }
3018
- if (!this.#objects) {
3019
- this._logger.info(`${this.namespaceLog} unsubscribeForeignObjects not processed because Objects database not connected`);
3020
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
3021
- }
3022
- this.#objects.unsubscribeUser(pattern, options, callback);
3107
+ const cb = callback;
3108
+ this.#subscriptions.unsubscribeForeignObjects(pattern, options).then(() => cb?.(), (err) => cb?.(err));
3023
3109
  }
3024
3110
  /**
3025
3111
  * Subscribe for the changes of files in specific instance.
@@ -3029,16 +3115,12 @@ class AdapterClass extends import_node_events.EventEmitter {
3029
3115
  * @param options optional user context
3030
3116
  */
3031
3117
  subscribeForeignFiles(id, pattern, options) {
3032
- if (!this.#objects) {
3033
- this._logger.info(`${this.namespaceLog} subscribeForeignFiles not processed because Objects database not connected`);
3034
- throw new Error(import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
3035
- }
3036
3118
  import_validator.Validator.assertString(id, "id");
3037
3119
  import_validator.Validator.assertPattern(pattern, "pattern");
3038
3120
  if (options !== null && options !== void 0) {
3039
3121
  import_validator.Validator.assertObject(options, "options");
3040
3122
  }
3041
- return this.#objects.subscribeUserFile(id, pattern, options);
3123
+ return this.#subscriptions.subscribeForeignFiles(id, pattern, options);
3042
3124
  }
3043
3125
  /**
3044
3126
  * Unsubscribe for the changes of files on specific instance.
@@ -3051,16 +3133,12 @@ class AdapterClass extends import_node_events.EventEmitter {
3051
3133
  if (!pattern) {
3052
3134
  pattern = "*";
3053
3135
  }
3054
- if (!this.#objects) {
3055
- this._logger.info(`${this.namespaceLog} unsubscribeForeignFiles not processed because Objects database not connected`);
3056
- throw new Error(import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
3057
- }
3058
3136
  import_validator.Validator.assertString(id, "id");
3059
3137
  import_validator.Validator.assertPattern(pattern, "pattern");
3060
3138
  if (options !== null && options !== void 0) {
3061
3139
  import_validator.Validator.assertObject(options, "options");
3062
3140
  }
3063
- return this.#objects.unsubscribeUserFile(id, pattern, options);
3141
+ return this.#subscriptions.unsubscribeForeignFiles(id, pattern, options);
3064
3142
  }
3065
3143
  /**
3066
3144
  * Same as {@link AdapterClass.setObject}, but with check if the object exists.
@@ -3208,11 +3286,11 @@ class AdapterClass extends import_node_events.EventEmitter {
3208
3286
  return id;
3209
3287
  }
3210
3288
  /**
3211
- * @param deviceName
3212
- * @param common
3213
- * @param _native
3214
- * @param options
3215
- * @param callback
3289
+ * @param deviceName the name of the device
3290
+ * @param common the common section of the device object
3291
+ * @param _native the native section of the device object
3292
+ * @param options optional user context
3293
+ * @param callback return result
3216
3294
  * @deprecated use `this.extendObject` instead
3217
3295
  */
3218
3296
  createDevice(deviceName, common, _native, options, callback) {
@@ -3249,25 +3327,28 @@ class AdapterClass extends import_node_events.EventEmitter {
3249
3327
  _createDevice(_options) {
3250
3328
  let { common, deviceName, _native } = _options;
3251
3329
  const { callback, options } = _options;
3252
- common = common || {};
3253
- common.name = common.name || deviceName;
3330
+ common ||= {};
3331
+ common.name ||= deviceName;
3254
3332
  deviceName = deviceName.replace(FORBIDDEN_CHARS, "_").replace(/\./g, "_");
3255
3333
  _native = _native || {};
3256
- this.setObjectNotExists(deviceName, {
3334
+ const createResult = this.setObjectNotExists(deviceName, {
3257
3335
  type: "device",
3258
3336
  common,
3259
3337
  native: _native
3260
3338
  }, options, callback);
3339
+ if (createResult instanceof Promise) {
3340
+ createResult.catch((e) => this._logger.error(`${this.namespaceLog} Cannot create device: ${e.message}`));
3341
+ }
3261
3342
  }
3262
3343
  /**
3263
3344
  * Name of channel must be in format "channel"
3264
3345
  *
3265
- * @param parentDevice
3266
- * @param channelName
3267
- * @param roleOrCommon
3268
- * @param _native
3269
- * @param options
3270
- * @param callback
3346
+ * @param parentDevice the parent device name
3347
+ * @param channelName the name of the channel
3348
+ * @param roleOrCommon role string or the common section of the channel object
3349
+ * @param _native the native section of the channel object
3350
+ * @param options optional user context
3351
+ * @param callback return result
3271
3352
  * @deprecated use `this.extendObject` instead
3272
3353
  */
3273
3354
  createChannel(parentDevice, channelName, roleOrCommon, _native, options, callback) {
@@ -3300,28 +3381,29 @@ class AdapterClass extends import_node_events.EventEmitter {
3300
3381
  import_validator.Validator.assertString(channelName, "channelName");
3301
3382
  import_validator.Validator.assertString(parentDevice, "parentDevice");
3302
3383
  import_validator.Validator.assertOptionalCallback(callback, "callback");
3303
- common.name = common.name || channelName;
3384
+ common.name ||= channelName;
3304
3385
  if (parentDevice) {
3305
3386
  parentDevice = parentDevice.replace(FORBIDDEN_CHARS, "_").replace(/\./g, "_");
3306
3387
  }
3307
3388
  channelName = channelName.replace(FORBIDDEN_CHARS, "_").replace(/\./g, "_");
3308
3389
  channelName = this._DCS2ID(parentDevice, channelName);
3309
- _native = _native || {};
3390
+ _native ||= {};
3310
3391
  const obj = {
3392
+ _id: channelName,
3311
3393
  type: "channel",
3312
3394
  common,
3313
3395
  native: _native
3314
3396
  };
3315
- this.setObjectNotExists(channelName, obj, options, callback);
3397
+ return this.setObjectNotExists(channelName, obj, options, callback);
3316
3398
  }
3317
3399
  /**
3318
- * @param parentDevice
3319
- * @param parentChannel
3320
- * @param stateName
3321
- * @param roleOrCommon
3322
- * @param _native
3323
- * @param options
3324
- * @param callback
3400
+ * @param parentDevice the parent device name
3401
+ * @param parentChannel the parent channel name
3402
+ * @param stateName the name of the state
3403
+ * @param roleOrCommon role string or the common section of the state object
3404
+ * @param _native the native section of the state object
3405
+ * @param options optional user context
3406
+ * @param callback return result
3325
3407
  * @deprecated use `this.extendObject` instead
3326
3408
  */
3327
3409
  createState(parentDevice, parentChannel, stateName, roleOrCommon, _native, options, callback) {
@@ -3347,12 +3429,13 @@ class AdapterClass extends import_node_events.EventEmitter {
3347
3429
  read: true,
3348
3430
  write: false,
3349
3431
  name: "",
3350
- role: roleOrCommon
3432
+ role: roleOrCommon,
3433
+ type: "mixed"
3351
3434
  };
3352
3435
  } else if (import_js_controller_common.tools.isObject(roleOrCommon)) {
3353
3436
  common = roleOrCommon;
3354
3437
  }
3355
- _native = _native || {};
3438
+ _native ||= {};
3356
3439
  import_validator.Validator.assertObject(common, "common");
3357
3440
  import_validator.Validator.assertString(stateName, "stateName");
3358
3441
  import_validator.Validator.assertString(parentDevice, "parentDevice");
@@ -3367,9 +3450,9 @@ class AdapterClass extends import_node_events.EventEmitter {
3367
3450
  _createState(_options) {
3368
3451
  const { _native, common, callback, options } = _options;
3369
3452
  let { parentChannel, parentDevice, stateName } = _options;
3370
- common.name = common.name || stateName;
3371
- common.read = common.read === void 0 ? true : common.read;
3372
- common.write = common.write === void 0 ? false : common.write;
3453
+ common.name ||= stateName;
3454
+ common.read ??= true;
3455
+ common.write ??= false;
3373
3456
  if (!common.role) {
3374
3457
  this._logger.error(`${this.namespaceLog} Try to create state ${parentDevice ? `${parentDevice}.` : ""}${parentChannel}.${stateName} without role`);
3375
3458
  return;
@@ -3438,35 +3521,36 @@ class AdapterClass extends import_node_events.EventEmitter {
3438
3521
  common.def = max;
3439
3522
  }
3440
3523
  }
3441
- this.setObjectNotExists(id, {
3524
+ const stateResult = this.setObjectNotExists(id, {
3442
3525
  type: "state",
3443
3526
  common,
3444
3527
  native: _native
3445
3528
  }, options, (err) => {
3446
3529
  if (err) {
3447
3530
  return import_js_controller_common.tools.maybeCallbackWithError(callback, err);
3448
- } else if (common.def !== void 0) {
3531
+ }
3532
+ if (common.def !== void 0) {
3449
3533
  this.getState(id, null, (err2, state) => {
3450
3534
  if (!state) {
3451
3535
  if (common.defAck !== void 0) {
3452
- this.setState(id, common.def, common.defAck, options, callback);
3453
- } else {
3454
- this.setState(id, common.def, options, callback);
3536
+ return this.setState(id, common.def, common.defAck, options, callback);
3455
3537
  }
3456
- } else {
3457
- return import_js_controller_common.tools.maybeCallback(callback);
3538
+ return this.setState(id, common.def, options, callback);
3458
3539
  }
3540
+ return import_js_controller_common.tools.maybeCallback(callback);
3459
3541
  });
3460
3542
  } else {
3461
3543
  this.getState(id, null, (err2, state) => {
3462
3544
  if (!state) {
3463
- this.setState(id, null, true, options, callback);
3464
- } else {
3465
- return import_js_controller_common.tools.maybeCallback(callback);
3545
+ return this.setState(id, null, true, options, callback);
3466
3546
  }
3547
+ return import_js_controller_common.tools.maybeCallback(callback);
3467
3548
  });
3468
3549
  }
3469
3550
  });
3551
+ if (stateResult instanceof Promise) {
3552
+ stateResult.catch((e) => this._logger.error(`${this.namespaceLog} Cannot create state object: ${e.message}`));
3553
+ }
3470
3554
  }
3471
3555
  /**
3472
3556
  * Delete device with all its channels and states.
@@ -3518,6 +3602,16 @@ class AdapterClass extends import_node_events.EventEmitter {
3518
3602
  }
3519
3603
  return import_js_controller_common.tools.maybeCallback(callback);
3520
3604
  }
3605
+ /**
3606
+ * Add a channel to an enum.
3607
+ *
3608
+ * @param enumName the enum category (e.g. rooms, functions)
3609
+ * @param addTo the enum id to add the channel to
3610
+ * @param parentDevice the parent device name
3611
+ * @param channelName the name of the channel
3612
+ * @param options optional user context
3613
+ * @param callback return result
3614
+ */
3521
3615
  addChannelToEnum(enumName, addTo, parentDevice, channelName, options, callback) {
3522
3616
  if (typeof options === "function") {
3523
3617
  callback = options;
@@ -3564,10 +3658,9 @@ class AdapterClass extends import_node_events.EventEmitter {
3564
3658
  obj.from = `system.adapter.${this.namespace}`;
3565
3659
  obj.user = options?.user || import_constants.SYSTEM_ADMIN_USER;
3566
3660
  obj.ts = Date.now();
3567
- this.#objects.setObject(obj._id, obj, options, callback);
3568
- } else {
3569
- return import_js_controller_common.tools.maybeCallback(callback);
3661
+ return callback ? this.#objects.setObject(obj._id, obj, options, callback) : this.#objects.setObject(obj._id, obj, options);
3570
3662
  }
3663
+ return import_js_controller_common.tools.maybeCallback(callback);
3571
3664
  }
3572
3665
  });
3573
3666
  } else {
@@ -3584,25 +3677,35 @@ class AdapterClass extends import_node_events.EventEmitter {
3584
3677
  obj.from = `system.adapter.${this.namespace}`;
3585
3678
  obj.user = options?.user || import_constants.SYSTEM_ADMIN_USER;
3586
3679
  obj.ts = Date.now();
3587
- this.#objects.setObject(obj._id, obj, options, callback);
3588
- } else {
3589
- return import_js_controller_common.tools.maybeCallback(callback);
3680
+ return callback ? this.#objects.setObject(obj._id, obj, options, callback) : this.#objects.setObject(obj._id, obj, options);
3590
3681
  }
3591
- } else {
3592
- this.#objects.setObject(`enum.${enumName}.${addTo}`, {
3593
- common: {
3594
- name: addTo,
3595
- members: [objId]
3596
- },
3597
- from: `system.adapter.${this.namespace}`,
3598
- ts: Date.now(),
3599
- type: "enum",
3600
- native: {}
3601
- }, options, callback);
3682
+ return import_js_controller_common.tools.maybeCallback(callback);
3602
3683
  }
3684
+ return callback ? this.#objects.setObject(`enum.${enumName}.${addTo}`, {
3685
+ common: { name: addTo, members: [objId] },
3686
+ from: `system.adapter.${this.namespace}`,
3687
+ ts: Date.now(),
3688
+ type: "enum",
3689
+ native: {}
3690
+ }, options, callback) : this.#objects.setObject(`enum.${enumName}.${addTo}`, {
3691
+ common: { name: addTo, members: [objId] },
3692
+ from: `system.adapter.${this.namespace}`,
3693
+ ts: Date.now(),
3694
+ type: "enum",
3695
+ native: {}
3696
+ }, options);
3603
3697
  });
3604
3698
  }
3605
3699
  }
3700
+ /**
3701
+ * Remove a channel from an enum.
3702
+ *
3703
+ * @param enumName the enum category (e.g. rooms, functions)
3704
+ * @param parentDevice the parent device name
3705
+ * @param channelName the name of the channel
3706
+ * @param options optional user context
3707
+ * @param callback return result
3708
+ */
3606
3709
  deleteChannelFromEnum(enumName, parentDevice, channelName, options, callback) {
3607
3710
  if (typeof options === "function") {
3608
3711
  callback = options;
@@ -3755,11 +3858,11 @@ class AdapterClass extends import_node_events.EventEmitter {
3755
3858
  return import_js_controller_common.tools.maybeCallback(callback);
3756
3859
  }
3757
3860
  /**
3758
- * @param parentDevice
3759
- * @param parentChannel
3760
- * @param stateName
3761
- * @param options
3762
- * @param callback
3861
+ * @param parentDevice the parent device name
3862
+ * @param parentChannel the parent channel name
3863
+ * @param stateName the name of the state
3864
+ * @param options optional user context
3865
+ * @param callback return result
3763
3866
  * @deprecated use `this.delObject` instead
3764
3867
  */
3765
3868
  deleteState(parentDevice, parentChannel, stateName, options, callback) {
@@ -3841,6 +3944,12 @@ class AdapterClass extends import_node_events.EventEmitter {
3841
3944
  const _name = this._DCS2ID(parentDevice, parentChannel, stateName);
3842
3945
  this.delObject(_name, options, callback);
3843
3946
  }
3947
+ /**
3948
+ * Get all devices of this adapter.
3949
+ *
3950
+ * @param options optional user context, or the callback
3951
+ * @param callback return result
3952
+ */
3844
3953
  getDevices(options, callback) {
3845
3954
  if (typeof options === "function" && typeof callback === "object") {
3846
3955
  const tmp = callback;
@@ -3879,6 +3988,13 @@ class AdapterClass extends import_node_events.EventEmitter {
3879
3988
  return import_js_controller_common.tools.maybeCallbackWithError(callback, null, res);
3880
3989
  });
3881
3990
  }
3991
+ /**
3992
+ * Get all channels of this adapter or of the given device.
3993
+ *
3994
+ * @param parentDevice the parent device name, or the callback
3995
+ * @param options optional user context, or the callback
3996
+ * @param callback return result
3997
+ */
3882
3998
  getChannelsOf(parentDevice, options, callback) {
3883
3999
  if (typeof options === "function") {
3884
4000
  callback = options;
@@ -3926,6 +4042,14 @@ class AdapterClass extends import_node_events.EventEmitter {
3926
4042
  return import_js_controller_common.tools.maybeCallbackWithError(options.callback, null, res);
3927
4043
  });
3928
4044
  }
4045
+ /**
4046
+ * Get all states of this adapter or of the given device/channel.
4047
+ *
4048
+ * @param parentDevice the parent device name, or the callback
4049
+ * @param parentChannel the parent channel name, or the callback
4050
+ * @param options optional user context, or the callback
4051
+ * @param callback return result
4052
+ */
3929
4053
  getStatesOf(parentDevice, parentChannel, options, callback) {
3930
4054
  if (typeof options === "function") {
3931
4055
  callback = options;
@@ -4002,6 +4126,17 @@ class AdapterClass extends import_node_events.EventEmitter {
4002
4126
  }
4003
4127
  });
4004
4128
  }
4129
+ /**
4130
+ * Add a state to an enum.
4131
+ *
4132
+ * @param enumName the enum category (e.g. rooms, functions)
4133
+ * @param addTo the enum id to add the state to
4134
+ * @param parentDevice the parent device name
4135
+ * @param parentChannel the parent channel name
4136
+ * @param stateName the name of the state
4137
+ * @param options optional user context
4138
+ * @param callback return result
4139
+ */
4005
4140
  addStateToEnum(enumName, addTo, parentDevice, parentChannel, stateName, options, callback) {
4006
4141
  if (typeof options === "function") {
4007
4142
  callback = options;
@@ -4061,10 +4196,9 @@ class AdapterClass extends import_node_events.EventEmitter {
4061
4196
  obj.from = `system.adapter.${this.namespace}`;
4062
4197
  obj.user = options?.user || import_constants.SYSTEM_ADMIN_USER;
4063
4198
  obj.ts = Date.now();
4064
- this.#objects.setObject(obj._id, obj, options, callback);
4065
- } else {
4066
- return import_js_controller_common.tools.maybeCallback(callback);
4199
+ return callback ? this.#objects.setObject(obj._id, obj, options, callback) : this.#objects.setObject(obj._id, obj, options);
4067
4200
  }
4201
+ return import_js_controller_common.tools.maybeCallback(callback);
4068
4202
  });
4069
4203
  } else {
4070
4204
  if (enumName.startsWith("enum.")) {
@@ -4077,28 +4211,39 @@ class AdapterClass extends import_node_events.EventEmitter {
4077
4211
  obj.from = `system.adapter.${this.namespace}`;
4078
4212
  obj.user = options?.user || import_constants.SYSTEM_ADMIN_USER;
4079
4213
  obj.ts = Date.now();
4080
- this.#objects.setObject(obj._id, obj, callback);
4081
- } else {
4082
- return import_js_controller_common.tools.maybeCallback(callback);
4083
- }
4084
- } else {
4085
- if (err) {
4086
- return import_js_controller_common.tools.maybeCallbackWithError(callback, err);
4214
+ return callback ? this.#objects.setObject(obj._id, obj, callback) : this.#objects.setObject(obj._id, obj);
4087
4215
  }
4088
- this.#objects.setObject(`enum.${enumName}.${addTo}`, {
4089
- common: {
4090
- name: addTo,
4091
- members: [objId]
4092
- },
4093
- from: `system.adapter.${this.namespace}`,
4094
- ts: Date.now(),
4095
- type: "enum",
4096
- native: {}
4097
- }, options, callback);
4216
+ return import_js_controller_common.tools.maybeCallback(callback);
4217
+ }
4218
+ if (err) {
4219
+ return import_js_controller_common.tools.maybeCallbackWithError(callback, err);
4098
4220
  }
4221
+ return callback ? this.#objects.setObject(`enum.${enumName}.${addTo}`, {
4222
+ common: { name: addTo, members: [objId] },
4223
+ from: `system.adapter.${this.namespace}`,
4224
+ ts: Date.now(),
4225
+ type: "enum",
4226
+ native: {}
4227
+ }, options, callback) : this.#objects.setObject(`enum.${enumName}.${addTo}`, {
4228
+ common: { name: addTo, members: [objId] },
4229
+ from: `system.adapter.${this.namespace}`,
4230
+ ts: Date.now(),
4231
+ type: "enum",
4232
+ native: {}
4233
+ }, options);
4099
4234
  });
4100
4235
  }
4101
4236
  }
4237
+ /**
4238
+ * Remove a state from an enum.
4239
+ *
4240
+ * @param enumName the enum category (e.g. rooms, functions)
4241
+ * @param parentDevice the parent device name
4242
+ * @param parentChannel the parent channel name
4243
+ * @param stateName the name of the state
4244
+ * @param options optional user context
4245
+ * @param callback return result
4246
+ */
4102
4247
  deleteStateFromEnum(enumName, parentDevice, parentChannel, stateName, options, callback) {
4103
4248
  if (typeof options === "function") {
4104
4249
  callback = options;
@@ -4312,6 +4457,14 @@ class AdapterClass extends import_node_events.EventEmitter {
4312
4457
  }
4313
4458
  this.#objects.readDir(_adapter, path, options, callback);
4314
4459
  }
4460
+ /**
4461
+ * Deletes a file in the DB.
4462
+ *
4463
+ * @param _adapter adapter name, or null for the current adapter
4464
+ * @param name path to the file
4465
+ * @param options optional user context
4466
+ * @param callback return result
4467
+ */
4315
4468
  unlink(_adapter, name, options, callback) {
4316
4469
  if (_adapter === null) {
4317
4470
  _adapter = this.name;
@@ -4332,6 +4485,15 @@ class AdapterClass extends import_node_events.EventEmitter {
4332
4485
  }
4333
4486
  this.#objects.unlink(_adapter, name, options, callback);
4334
4487
  }
4488
+ /**
4489
+ * Renames a file in the DB.
4490
+ *
4491
+ * @param _adapter adapter name, or null for the current adapter
4492
+ * @param oldName current path to the file
4493
+ * @param newName new path to the file
4494
+ * @param options optional user context
4495
+ * @param callback return result
4496
+ */
4335
4497
  rename(_adapter, oldName, newName, options, callback) {
4336
4498
  if (_adapter === null) {
4337
4499
  _adapter = this.name;
@@ -4351,8 +4513,16 @@ class AdapterClass extends import_node_events.EventEmitter {
4351
4513
  this._logger.info(`${this.namespaceLog} rename not processed because Objects database not connected`);
4352
4514
  return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4353
4515
  }
4354
- this.#objects.rename(_adapter, oldName, newName, options, callback);
4516
+ return this.#objects.rename(_adapter, oldName, newName, options, callback);
4355
4517
  }
4518
+ /**
4519
+ * Creates a directory in the DB.
4520
+ *
4521
+ * @param _adapter adapter name, or null for the current adapter
4522
+ * @param dirname path to the directory
4523
+ * @param options optional user context
4524
+ * @param callback return result
4525
+ */
4356
4526
  mkdir(_adapter, dirname, options, callback) {
4357
4527
  if (_adapter === null) {
4358
4528
  _adapter = this.name;
@@ -4489,6 +4659,13 @@ class AdapterClass extends import_node_events.EventEmitter {
4489
4659
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
4490
4660
  }
4491
4661
  }
4662
+ /**
4663
+ * Formats a numeric value using the given format string.
4664
+ *
4665
+ * @param value the value to format
4666
+ * @param decimals number of decimals to keep, or the format string
4667
+ * @param _format optional format string for the decimal and thousands separator
4668
+ */
4492
4669
  formatValue(value, decimals, _format) {
4493
4670
  if (typeof decimals !== "number") {
4494
4671
  _format = decimals;
@@ -4506,6 +4683,13 @@ class AdapterClass extends import_node_events.EventEmitter {
4506
4683
  value.toFixed(decimals).replace(format[0], format[1]).replace(/\B(?=(\d{3})+(?!\d))/g, format[0])
4507
4684
  );
4508
4685
  }
4686
+ /**
4687
+ * Formats a date or duration according to the given format string.
4688
+ *
4689
+ * @param dateObj the date to format
4690
+ * @param isDuration whether the value represents a duration, or the format string
4691
+ * @param _format optional format string
4692
+ */
4509
4693
  formatDate(dateObj, isDuration, _format) {
4510
4694
  if (typeof isDuration === "string" && isDuration.toLowerCase() === "duration" || isDuration === true) {
4511
4695
  isDuration = true;
@@ -4552,7 +4736,7 @@ class AdapterClass extends import_node_events.EventEmitter {
4552
4736
  const validFormatChars = "YJ\u0413M\u041CDT\u0414hS\u0447m\u043Cs\u0441";
4553
4737
  let s = "";
4554
4738
  let result = "";
4555
- const put = (s2) => {
4739
+ const put = /* @__PURE__ */ __name((s2) => {
4556
4740
  let v = "";
4557
4741
  switch (s2) {
4558
4742
  case "YYYY":
@@ -4630,7 +4814,7 @@ class AdapterClass extends import_node_events.EventEmitter {
4630
4814
  v = v.toString();
4631
4815
  }
4632
4816
  return result += v;
4633
- };
4817
+ }, "put");
4634
4818
  for (let i = 0; i < format.length; i++) {
4635
4819
  if (validFormatChars.includes(format[i])) {
4636
4820
  s += format[i];
@@ -4678,13 +4862,42 @@ class AdapterClass extends import_node_events.EventEmitter {
4678
4862
  if (options !== void 0) {
4679
4863
  import_validator.Validator.assertObject(options, "options");
4680
4864
  }
4681
- return this._sendTo({
4682
- instanceName,
4683
- command,
4684
- message,
4685
- options,
4686
- callback
4687
- });
4865
+ if (import_js_controller_common.tools.isObject(callback)) {
4866
+ this.#fireAndForget(this.#async.sendTo(instanceName, command, message, this.#withSendFlags(options, { callback })), "Error in sendTo");
4867
+ return;
4868
+ }
4869
+ const cb = callback;
4870
+ if (typeof cb === "function") {
4871
+ this.sendToAsync(instanceName, command, message, options).then((reply) => cb(reply), (err) => cb(err));
4872
+ return;
4873
+ }
4874
+ this.#fireAndForget(this.#async.sendTo(instanceName, command, message, this.#withSendFlags(options, { expectReply: false })), "Error in sendTo");
4875
+ }
4876
+ /**
4877
+ * Merges send-control flags into the caller-supplied options for delegation to the async facade.
4878
+ * A non-object `options` is forwarded unchanged so the facade's validation surfaces it.
4879
+ *
4880
+ * @param options caller-supplied send options (unvalidated)
4881
+ * @param flags control flags to apply
4882
+ * @param flags.expectReply when false, the facade sends fire-and-forget
4883
+ * @param flags.callback legacy callback-info header to attach to the message
4884
+ */
4885
+ #withSendFlags(options, flags) {
4886
+ if (options !== void 0 && !import_js_controller_common.tools.isObject(options)) {
4887
+ return options;
4888
+ }
4889
+ return { ...options, ...flags };
4890
+ }
4891
+ /**
4892
+ * Observes a fire-and-forget promise from the callback-compat layer, logging any rejection without
4893
+ * rethrowing. Used only where the legacy callback API had no channel to surface the error; async
4894
+ * callers on {@link AsyncAdapter} instead await and catch.
4895
+ *
4896
+ * @param promise the promise to observe
4897
+ * @param errorMessage log prefix describing the failed action
4898
+ */
4899
+ #fireAndForget(promise, errorMessage) {
4900
+ promise.catch((e) => this._logger.error(`${this.namespaceLog} ${errorMessage}: ${e instanceof Error ? e.message : String(e)}`));
4688
4901
  }
4689
4902
  /**
4690
4903
  * Async version of sendTo
@@ -4696,105 +4909,15 @@ class AdapterClass extends import_node_events.EventEmitter {
4696
4909
  * @param options optional options to define a timeout. This allows to get an error callback if no answer received in time (only if target is specific instance)
4697
4910
  */
4698
4911
  sendToAsync(instanceName, command, message, options) {
4699
- return new Promise((resolve, reject) => {
4700
- const callback = (resOrError) => {
4701
- if (resOrError instanceof Error) {
4702
- reject(resOrError);
4703
- }
4704
- resolve(resOrError);
4705
- };
4706
- this.sendTo(instanceName, command, message, callback, options);
4707
- });
4708
- }
4709
- async _sendTo(_options) {
4710
- const { command, message, callback, options } = _options;
4711
- let { instanceName } = _options;
4712
- const obj = {
4713
- command,
4714
- message,
4715
- from: `system.adapter.${this.namespace}`
4716
- };
4717
- if (!instanceName) {
4718
- return import_js_controller_common.tools.maybeCallbackWithError(callback, "No instanceName provided or not a string");
4719
- }
4720
- if (!instanceName.startsWith("system.adapter.")) {
4721
- instanceName = `system.adapter.${instanceName}`;
4722
- }
4723
- if (!this.#states) {
4724
- this._logger.info(`${this.namespaceLog} sendTo not processed because States database not connected`);
4725
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4726
- }
4727
- if (typeof message !== "object") {
4728
- this._logger.silly(`${this.namespaceLog} sendTo "${command}" to ${instanceName} from system.adapter.${this.namespace}: ${message}`);
4729
- } else {
4730
- this._logger.silly(`${this.namespaceLog} sendTo "${command}" to ${instanceName} from system.adapter.${this.namespace}`);
4731
- }
4732
- if (!instanceName.match(/\.[0-9]+$/)) {
4733
- if (!this.#objects) {
4734
- this._logger.info(`${this.namespaceLog} sendTo not processed because Objects database not connected`);
4735
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4736
- }
4737
- try {
4738
- const res = await this.#objects.getObjectView("system", "instance", {
4739
- startkey: `${instanceName}.`,
4740
- endkey: `${instanceName}.\u9999`
4741
- });
4742
- if (res) {
4743
- for (const row of res.rows) {
4744
- try {
4745
- await this.#states.pushMessage(row.id, obj);
4746
- } catch (e) {
4747
- return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
4748
- }
4749
- }
4750
- }
4751
- } catch {
4752
- }
4753
- } else {
4754
- if (callback) {
4755
- if (typeof callback === "function") {
4756
- if (!(0, import_utils.isMessageboxSupported)(this.common) && !this.mboxSubscribed) {
4757
- this.mboxSubscribed = true;
4758
- this.#states.subscribeMessage(`system.adapter.${this.namespace}`);
4759
- }
4760
- obj.callback = {
4761
- message,
4762
- id: this._callbackId++,
4763
- ack: false,
4764
- time: Date.now()
4765
- };
4766
- if (this._callbackId >= 4294967295) {
4767
- this._callbackId = 1;
4768
- }
4769
- const callbackId = obj.callback.id;
4770
- let timer;
4771
- if (options?.timeout) {
4772
- timer = setTimeout(() => {
4773
- const callbackObj = this.messageCallbacks.get(callbackId);
4774
- if (callbackObj) {
4775
- callbackObj.cb(new Error("Timeout exceeded"));
4776
- this.messageCallbacks.delete(callbackId);
4777
- }
4778
- }, options.timeout);
4779
- }
4780
- this.messageCallbacks.set(callbackId, { cb: callback, time: Date.now(), timer });
4781
- const now = Date.now();
4782
- for (const [_id, cb] of this.messageCallbacks) {
4783
- if (now - cb.time > 36e5) {
4784
- this.messageCallbacks.delete(_id);
4785
- }
4786
- }
4787
- } else {
4788
- obj.callback = callback;
4789
- obj.callback.ack = true;
4790
- }
4791
- }
4792
- try {
4793
- await this.#states.pushMessage(instanceName, obj);
4794
- } catch (e) {
4795
- return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
4796
- }
4912
+ if (typeof message === "function") {
4913
+ options = void 0;
4914
+ message = command;
4915
+ command = "send";
4916
+ } else if (typeof message === "undefined") {
4917
+ message = command;
4918
+ command = "send";
4797
4919
  }
4920
+ return this.#async.sendTo(instanceName, command, message, this.#withSendFlags(options, { expectReply: true }));
4798
4921
  }
4799
4922
  /**
4800
4923
  * Send message to specific host or to all hosts.
@@ -4814,6 +4937,10 @@ class AdapterClass extends import_node_events.EventEmitter {
4814
4937
  * ```
4815
4938
  */
4816
4939
  sendToHost(hostName, command, message, callback) {
4940
+ if (typeof message === "function" && typeof callback === "undefined") {
4941
+ callback = message;
4942
+ message = void 0;
4943
+ }
4817
4944
  if (typeof message === "undefined") {
4818
4945
  message = command;
4819
4946
  command = "send";
@@ -4825,77 +4952,32 @@ class AdapterClass extends import_node_events.EventEmitter {
4825
4952
  if (!import_js_controller_common.tools.isObject(callback)) {
4826
4953
  import_validator.Validator.assertOptionalCallback(callback, "callback");
4827
4954
  }
4828
- return this._sendToHost({
4829
- hostName,
4830
- command,
4831
- message,
4832
- callback
4833
- });
4834
- }
4835
- async _sendToHost(_options) {
4836
- const { command, message, callback } = _options;
4837
- let { hostName } = _options;
4838
- const obj = { command, message, from: `system.adapter.${this.namespace}` };
4839
- if (!this.#states) {
4840
- this._logger.info(`${this.namespaceLog} sendToHost not processed because States database not connected`);
4841
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4955
+ if (import_js_controller_common.tools.isObject(callback)) {
4956
+ this.#fireAndForget(this.#async.sendToHost(hostName, command, message, {
4957
+ callback
4958
+ }), "Error in sendToHost");
4959
+ return;
4842
4960
  }
4843
- if (hostName && !hostName.startsWith("system.host.")) {
4844
- hostName = `system.host.${hostName}`;
4961
+ const cb = callback;
4962
+ if (typeof cb === "function" && hostName !== null) {
4963
+ this.sendToHostAsync(hostName, command, message).then((reply) => cb(reply), (err) => cb(err));
4964
+ return;
4845
4965
  }
4846
- if (!hostName) {
4847
- if (!this.#objects) {
4848
- this._logger.info(`${this.namespaceLog} sendToHost not processed because Objects database not connected`);
4849
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4850
- }
4851
- this.#objects.getObjectList({
4852
- startkey: "system.host.",
4853
- endkey: `system.host.\u9999`
4854
- }, null, async (err, res) => {
4855
- if (!this.#states) {
4856
- return;
4857
- }
4858
- if (!err && res?.rows.length) {
4859
- for (const row of res.rows) {
4860
- const parts = row.id.split(".");
4861
- if (parts.length === 3) {
4862
- try {
4863
- await this.#states.pushMessage(row.id, obj);
4864
- } catch (e) {
4865
- return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
4866
- }
4867
- }
4868
- }
4869
- }
4870
- });
4871
- } else {
4872
- if (callback) {
4873
- if (typeof callback === "function") {
4874
- if (!(0, import_utils.isMessageboxSupported)(this.common) && !this.mboxSubscribed) {
4875
- this.mboxSubscribed = true;
4876
- this.#states.subscribeMessage(`system.adapter.${this.namespace}`);
4877
- }
4878
- obj.callback = {
4879
- message,
4880
- id: this._callbackId++,
4881
- ack: false,
4882
- time: Date.now()
4883
- };
4884
- if (this._callbackId >= 4294967295) {
4885
- this._callbackId = 1;
4886
- }
4887
- this.messageCallbacks.set(obj.callback.id, { cb: callback, time: Date.now() });
4888
- } else {
4889
- obj.callback = callback;
4890
- obj.callback.ack = true;
4891
- }
4892
- }
4893
- try {
4894
- await this.#states.pushMessage(hostName, obj);
4895
- } catch (e) {
4896
- return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
4897
- }
4966
+ this.#fireAndForget(this.#async.sendToHost(hostName, command, message, { expectReply: false }), "Error in sendToHost");
4967
+ }
4968
+ /**
4969
+ * Async version of sendToHost
4970
+ *
4971
+ * @param hostName name of the host where the message must be sent to. E.g. "myPC" or "system.host.myPC". If argument is null, the message will be sent to all hosts.
4972
+ * @param command command name. One of: "cmdExec", "getRepository", "getInstalled", "getVersion", "getDiagData", "getLocationOnDisk", "getDevList", "getLogs", "delLogs", "readDirAsZip", "writeDirAsZip", "readObjectsAsZip", "writeObjectsAsZip", "checkLogging". Commands can be checked in controller.js (function processMessage)
4973
+ * @param message object that will be given as argument for request
4974
+ */
4975
+ sendToHostAsync(hostName, command, message) {
4976
+ if (typeof message === "undefined") {
4977
+ message = command;
4978
+ command = "send";
4898
4979
  }
4980
+ return this.#async.sendToHost(hostName, command, message, { expectReply: hostName !== null });
4899
4981
  }
4900
4982
  /**
4901
4983
  * Send a message to an active UI Client
@@ -4903,22 +4985,7 @@ class AdapterClass extends import_node_events.EventEmitter {
4903
4985
  * @param options clientId and data options
4904
4986
  */
4905
4987
  sendToUI(options) {
4906
- if (!this.#states) {
4907
- throw new Error(import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4908
- }
4909
- const { clientId, data } = options;
4910
- if (clientId === void 0) {
4911
- return this.uiMessagingController.sendToAllClients({
4912
- data,
4913
- states: this.#states
4914
- });
4915
- }
4916
- import_validator.Validator.assertString(clientId, "clientId");
4917
- return this.uiMessagingController.sendToClient({
4918
- clientId,
4919
- data,
4920
- states: this.#states
4921
- });
4988
+ return this.#async.sendToUI(options);
4922
4989
  }
4923
4990
  /**
4924
4991
  * Send notification with given scope and category to host of this adapter
@@ -4929,30 +4996,7 @@ class AdapterClass extends import_node_events.EventEmitter {
4929
4996
  * @param options - Additional options for the notification, currently `contextData` is supported
4930
4997
  */
4931
4998
  async registerNotification(scope, category, message, options) {
4932
- if (!this.#states) {
4933
- this._logger.info(`${this.namespaceLog} registerNotification not processed because States database not connected`);
4934
- throw new Error(import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
4935
- }
4936
- import_validator.Validator.assertString(scope, "scope");
4937
- if (category !== null) {
4938
- import_validator.Validator.assertString(category, "category");
4939
- }
4940
- import_validator.Validator.assertString(message, "message");
4941
- if (options !== void 0) {
4942
- import_validator.Validator.assertObject(options, "options");
4943
- }
4944
- const obj = {
4945
- command: "addNotification",
4946
- message: {
4947
- scope,
4948
- category,
4949
- message,
4950
- instance: this.namespace,
4951
- contextData: options?.contextData
4952
- },
4953
- from: `system.adapter.${this.namespace}`
4954
- };
4955
- await this.#states.pushMessage(`system.host.${this.host}`, obj);
4999
+ return this.#async.registerNotification(scope, category, message, options);
4956
5000
  }
4957
5001
  /**
4958
5002
  * Writes value into states DB.
@@ -5155,8 +5199,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5155
5199
  }
5156
5200
  this.users[options.user] = {
5157
5201
  groups: options.groups,
5158
- // @ts-expect-error TODO: UserCommon has no acl
5159
- acl: userAcl.common?.acl || {}
5202
+ acl: {}
5160
5203
  };
5161
5204
  await this._getGroups(options.groups);
5162
5205
  const user = this.users[options.user];
@@ -5166,71 +5209,71 @@ class AdapterClass extends import_node_events.EventEmitter {
5166
5209
  }
5167
5210
  const group = this.groups[gName];
5168
5211
  if (group.common?.acl?.file) {
5169
- if (!user.acl || !user.acl.file) {
5170
- user.acl = user.acl || {};
5171
- user.acl.file = user.acl.file || {};
5212
+ if (!user.acl?.file) {
5213
+ user.acl ||= {};
5214
+ user.acl.file ||= {};
5172
5215
  user.acl.file.create = group.common.acl.file.create;
5173
5216
  user.acl.file.read = group.common.acl.file.read;
5174
5217
  user.acl.file.write = group.common.acl.file.write;
5175
5218
  user.acl.file.delete = group.common.acl.file.delete;
5176
5219
  user.acl.file.list = group.common.acl.file.list;
5177
5220
  } else {
5178
- user.acl.file.create = user.acl.file.create || group.common.acl.file.create;
5179
- user.acl.file.read = user.acl.file.read || group.common.acl.file.read;
5180
- user.acl.file.write = user.acl.file.write || group.common.acl.file.write;
5181
- user.acl.file.delete = user.acl.file.delete || group.common.acl.file.delete;
5182
- user.acl.file.list = user.acl.file.list || group.common.acl.file.list;
5221
+ user.acl.file.create ||= group.common.acl.file.create;
5222
+ user.acl.file.read ||= group.common.acl.file.read;
5223
+ user.acl.file.write ||= group.common.acl.file.write;
5224
+ user.acl.file.delete ||= group.common.acl.file.delete;
5225
+ user.acl.file.list ||= group.common.acl.file.list;
5183
5226
  }
5184
5227
  }
5185
5228
  if (group.common?.acl?.object) {
5186
5229
  if (!user.acl || !user.acl.object) {
5187
- user.acl = user.acl || {};
5188
- user.acl.object = user.acl.object || {};
5230
+ user.acl ||= {};
5231
+ user.acl.object ||= {};
5189
5232
  user.acl.object.create = group.common.acl.object.create;
5190
5233
  user.acl.object.read = group.common.acl.object.read;
5191
5234
  user.acl.object.write = group.common.acl.object.write;
5192
5235
  user.acl.object.delete = group.common.acl.object.delete;
5193
5236
  user.acl.object.list = group.common.acl.object.list;
5194
5237
  } else {
5195
- user.acl.object.create = user.acl.object.create || group.common.acl.object.create;
5196
- user.acl.object.read = user.acl.object.read || group.common.acl.object.read;
5197
- user.acl.object.write = user.acl.object.write || group.common.acl.object.write;
5198
- user.acl.object.delete = user.acl.object.delete || group.common.acl.object.delete;
5199
- user.acl.object.list = user.acl.object.list || group.common.acl.object.list;
5238
+ user.acl.object.create ||= group.common.acl.object.create;
5239
+ user.acl.object.read ||= group.common.acl.object.read;
5240
+ user.acl.object.write ||= group.common.acl.object.write;
5241
+ user.acl.object.delete ||= group.common.acl.object.delete;
5242
+ user.acl.object.list ||= group.common.acl.object.list;
5200
5243
  }
5201
5244
  }
5202
5245
  if (group.common?.acl?.users) {
5203
5246
  if (!user.acl || !user.acl.users) {
5204
- user.acl = user.acl || {};
5205
- user.acl.users = user.acl.users || {};
5247
+ user.acl ||= {};
5248
+ user.acl.users ||= {};
5206
5249
  user.acl.users.create = group.common.acl.users.create;
5207
5250
  user.acl.users.read = group.common.acl.users.read;
5208
5251
  user.acl.users.write = group.common.acl.users.write;
5209
5252
  user.acl.users.delete = group.common.acl.users.delete;
5210
5253
  user.acl.users.list = group.common.acl.users.list;
5211
5254
  } else {
5212
- user.acl.users.create = user.acl.users.create || group.common.acl.users.create;
5213
- user.acl.users.read = user.acl.users.read || group.common.acl.users.read;
5214
- user.acl.users.write = user.acl.users.write || group.common.acl.users.write;
5215
- user.acl.users.delete = user.acl.users.delete || group.common.acl.users.delete;
5216
- user.acl.users.list = user.acl.users.list || group.common.acl.users.list;
5255
+ user.acl.users.create ||= group.common.acl.users.create;
5256
+ user.acl.users.read ||= group.common.acl.users.read;
5257
+ user.acl.users.write ||= group.common.acl.users.write;
5258
+ user.acl.users.delete ||= group.common.acl.users.delete;
5259
+ user.acl.users.list ||= group.common.acl.users.list;
5217
5260
  }
5218
5261
  }
5219
5262
  if (group.common?.acl?.state) {
5220
5263
  if (!user.acl || !user.acl.state) {
5221
- user.acl = user.acl || {};
5222
- user.acl.state = user.acl.state || {};
5264
+ user.acl ||= {};
5265
+ user.acl.state ||= {};
5223
5266
  user.acl.state.create = group.common.acl.state.create;
5224
5267
  user.acl.state.read = group.common.acl.state.read;
5225
5268
  user.acl.state.write = group.common.acl.state.write;
5226
5269
  user.acl.state.delete = group.common.acl.state.delete;
5227
5270
  user.acl.state.list = group.common.acl.state.list;
5228
5271
  } else {
5229
- user.acl.state.create = user.acl.state.create || group.common.acl.state.create;
5230
- user.acl.state.read = user.acl.state.read || group.common.acl.state.read;
5231
- user.acl.state.write = user.acl.state.write || group.common.acl.state.write;
5232
- user.acl.state.delete = user.acl.state.delete || group.common.acl.state.delete;
5233
- user.acl.state.list = user.acl.state.list || group.common.acl.state.list;
5272
+ user.acl.state.create ||= group.common.acl.state.create;
5273
+ user.acl.state.read ||= group.common.acl.state.read;
5274
+ user.acl.state.write ||= group.common.acl.state.write;
5275
+ user.acl.state.delete ||= group.common.acl.state.delete;
5276
+ user.acl.state.list ||= group.common.acl.state.list;
5234
5277
  }
5235
5278
  }
5236
5279
  }
@@ -5238,10 +5281,17 @@ class AdapterClass extends import_node_events.EventEmitter {
5238
5281
  return options;
5239
5282
  }
5240
5283
  _checkState(obj, options, command) {
5284
+ if (options.groups?.includes(import_constants.SYSTEM_ADMIN_GROUP)) {
5285
+ return true;
5286
+ }
5241
5287
  const limitToOwnerRights = options.limitToOwnerRights === true;
5242
5288
  if (obj?.acl) {
5243
- obj.acl.state = obj.acl.state || obj.acl.object;
5289
+ obj.acl.state ||= obj.acl.object;
5244
5290
  if (obj.acl.state) {
5291
+ if (!options.acl) {
5292
+ this._logger.warn(`${this.namespaceLog} Permission error for user "${options.user} on "${obj._id}": ${command}`);
5293
+ return false;
5294
+ }
5245
5295
  if (options.user === obj.acl.owner) {
5246
5296
  if (command === "setState" || command === "delState") {
5247
5297
  if (command === "delState" && !options.acl.state.delete) {
@@ -5262,7 +5312,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5262
5312
  } else {
5263
5313
  this._logger.warn(`${this.namespaceLog} Called unknown command on "${obj._id}": ${command}`);
5264
5314
  }
5265
- } else if (options.groups.includes(obj.acl.ownerGroup) && !limitToOwnerRights) {
5315
+ } else if (options.groups?.includes(obj.acl.ownerGroup) && !limitToOwnerRights) {
5266
5316
  if (command === "setState" || command === "delState") {
5267
5317
  if (command === "delState" && !options.acl.state.delete) {
5268
5318
  this._logger.warn(`${this.namespaceLog} Permission error for user "${options.user} on "${obj._id}": ${command}`);
@@ -5630,7 +5680,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5630
5680
  this.outputCount++;
5631
5681
  this.#states.setState(aliasId, import_js_controller_common.tools.formatAliasValue({
5632
5682
  sourceCommon: obj?.common,
5633
- targetCommon: targetObj && targetObj.common,
5683
+ targetCommon: targetObj?.common,
5634
5684
  state,
5635
5685
  logger: this._logger,
5636
5686
  logNamespace: this.namespaceLog,
@@ -5805,7 +5855,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5805
5855
  * }
5806
5856
  * ```
5807
5857
  *
5808
- * See possible attributes of the state in @setState explanation
5858
+ * See possible attributes of the state in `setState` explanation
5809
5859
  */
5810
5860
  getState(id, options, callback) {
5811
5861
  if (!import_js_controller_common.tools.isObject(id)) {
@@ -5828,7 +5878,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5828
5878
  * }
5829
5879
  * ```
5830
5880
  *
5831
- * See possible attributes of the state in @setState explanation
5881
+ * See possible attributes of the state in `setState` explanation
5832
5882
  */
5833
5883
  getForeignState(id, options, callback) {
5834
5884
  if (typeof options === "function") {
@@ -5918,7 +5968,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5918
5968
  if (this.oStates && this.oStates[id]) {
5919
5969
  return import_js_controller_common.tools.maybeCallbackWithError(callback, null, this.oStates[id]);
5920
5970
  }
5921
- return this.#states.getState(id, callback);
5971
+ return callback ? this.#states.getState(id, callback) : this.#states.getState(id);
5922
5972
  }
5923
5973
  }
5924
5974
  // find out default history instance
@@ -5996,7 +6046,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5996
6046
  * }
5997
6047
  * ```
5998
6048
  *
5999
- * See possible attributes of the state in @setState explanation
6049
+ * See possible attributes of the state in `setState` explanation
6000
6050
  */
6001
6051
  getHistory(id, options, callback) {
6002
6052
  if (typeof options === "function") {
@@ -6019,10 +6069,10 @@ class AdapterClass extends import_node_events.EventEmitter {
6019
6069
  } catch (e) {
6020
6070
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6021
6071
  }
6022
- options = options || {};
6023
- options.end = options.end || Date.now() + 5e6;
6072
+ options ||= {};
6073
+ options.end ||= Date.now() + 5e6;
6024
6074
  if (!options.count && !options.start) {
6025
- options.start = options.start || Date.now() - 6048e5;
6075
+ options.start ||= Date.now() - 6048e5;
6026
6076
  }
6027
6077
  if (!options.instance) {
6028
6078
  if (!this.defaultHistory) {
@@ -6065,7 +6115,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6065
6115
  }
6066
6116
  /**
6067
6117
  * Deletes a state of this instance.
6068
- * The object will NOT be deleted. If you want to delete it too, use @delObject instead.
6118
+ * The object will NOT be deleted. If you want to delete it too, use `delObject` instead.
6069
6119
  *
6070
6120
  * It is not required to provice the adapter namespace, because it will automatically be added.
6071
6121
  * E.g. to delete "adapterName.X.myObject", only "myObject" is required as ID.
@@ -6106,7 +6156,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6106
6156
  }
6107
6157
  /**
6108
6158
  * Deletes a state of any adapter.
6109
- * The object is NOT deleted. If you want to delete it too, use @delForeignObject instead.
6159
+ * The object is NOT deleted. If you want to delete it too, use `delForeignObject` instead.
6110
6160
  *
6111
6161
  * No error is returned if state does not exist.
6112
6162
  *
@@ -6147,7 +6197,11 @@ class AdapterClass extends import_node_events.EventEmitter {
6147
6197
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6148
6198
  }
6149
6199
  }
6150
- await this.#states.delState(id, callback);
6200
+ if (callback) {
6201
+ this.#states.delState(id, callback);
6202
+ } else {
6203
+ await this.#states.delState(id);
6204
+ }
6151
6205
  }
6152
6206
  /**
6153
6207
  * Read all states of this adapter, that pass the pattern
@@ -6181,7 +6235,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6181
6235
  const arr = await this.#states.getStates(keys);
6182
6236
  const result = {};
6183
6237
  for (let i = 0; i < keys.length; i++) {
6184
- const obj = targetObjs && targetObjs[i];
6238
+ const obj = targetObjs?.[i];
6185
6239
  if (obj?.common?.alias && srcObjs) {
6186
6240
  const srcObj = srcObjs[i];
6187
6241
  if (srcObj) {
@@ -6295,7 +6349,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6295
6349
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6296
6350
  }
6297
6351
  } else {
6298
- const res = await this._processStates(pattern, options?._objects);
6352
+ const res = await this._processStates(pattern, options._objects);
6299
6353
  return import_js_controller_common.tools.maybeCallbackWithError(callback, null, res);
6300
6354
  }
6301
6355
  } else {
@@ -6354,76 +6408,6 @@ class AdapterClass extends import_node_events.EventEmitter {
6354
6408
  }
6355
6409
  }
6356
6410
  }
6357
- /**
6358
- * Add subscription for given alias, if it is not a state it will be ignored
6359
- *
6360
- * @param aliasObj the alias object
6361
- * @param pattern pattern to subscribe for
6362
- */
6363
- async _addAliasSubscribe(aliasObj, pattern) {
6364
- if (aliasObj.type !== "state") {
6365
- return;
6366
- }
6367
- if (!aliasObj.common?.alias?.id) {
6368
- this._logger.warn(`${this.namespaceLog} Alias ${aliasObj._id} has no target 5`);
6369
- throw new Error(`Alias ${aliasObj._id} has no target`);
6370
- }
6371
- const sourceId = import_js_controller_common.tools.isObject(aliasObj.common.alias.id) ? aliasObj.common.alias.id.read : aliasObj.common.alias.id;
6372
- try {
6373
- this._utils.validateId(sourceId, true, null);
6374
- } catch (e) {
6375
- throw new Error(`Error validating alias id of ${aliasObj._id}: ${e.message}`);
6376
- }
6377
- const targetEntry = {
6378
- alias: (0, import_deep_clone.default)(aliasObj.common.alias),
6379
- id: aliasObj._id,
6380
- pattern,
6381
- type: aliasObj.common.type,
6382
- max: aliasObj.common.max,
6383
- min: aliasObj.common.min,
6384
- unit: aliasObj.common.unit
6385
- };
6386
- let aliasDetails;
6387
- if (!this.aliases.has(sourceId)) {
6388
- aliasDetails = { targets: [] };
6389
- this.aliases.set(sourceId, aliasDetails);
6390
- } else {
6391
- aliasDetails = this.aliases.get(sourceId);
6392
- }
6393
- if (!aliasDetails.source) {
6394
- await this.#states.subscribe(sourceId);
6395
- const sourceObj = await this.#objects.getObject(sourceId, { user: import_constants.SYSTEM_ADMIN_USER });
6396
- if (sourceObj?.common && this.aliases.has(sourceObj._id)) {
6397
- aliasDetails.source = {
6398
- min: sourceObj.common.min,
6399
- max: sourceObj.common.max,
6400
- type: sourceObj.common.type,
6401
- unit: sourceObj.common.unit
6402
- };
6403
- }
6404
- }
6405
- aliasDetails.targets.push(targetEntry);
6406
- }
6407
- /**
6408
- * Remove an alias subscribe
6409
- *
6410
- * @param sourceId id of the source object
6411
- * @param aliasObjOrIdx the alias target or the index of the targets array
6412
- */
6413
- async _removeAliasSubscribe(sourceId, aliasObjOrIdx) {
6414
- if (!this.aliases.has(sourceId)) {
6415
- return;
6416
- }
6417
- const alias = this.aliases.get(sourceId);
6418
- const pos = typeof aliasObjOrIdx === "number" ? aliasObjOrIdx : alias.targets.indexOf(aliasObjOrIdx);
6419
- if (pos !== -1) {
6420
- alias.targets.splice(pos, 1);
6421
- if (!alias.targets.length) {
6422
- this.aliases.delete(sourceId);
6423
- await this.#states.unsubscribe(sourceId);
6424
- }
6425
- }
6426
- }
6427
6411
  /**
6428
6412
  * Subscribe for changes on all states of all adapters (and system states), that pass the pattern
6429
6413
  *
@@ -6450,136 +6434,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6450
6434
  import_validator.Validator.assertObject(options, "options");
6451
6435
  }
6452
6436
  import_validator.Validator.assertPattern(pattern, "pattern");
6453
- return this._subscribeForeignStates({ pattern, options, callback });
6454
- }
6455
- async _subscribeForeignStates(_options) {
6456
- const { pattern, options, callback } = _options;
6457
- await this._autoSubscribeOn();
6458
- if (!this.#states) {
6459
- this._logger.info(`${this.namespaceLog} subscribeForeignStates not processed because States database not connected`);
6460
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
6461
- }
6462
- if (!this.#objects) {
6463
- this._logger.info(`${this.namespaceLog} subscribeForeignStates not processed because Objects database not connected`);
6464
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
6465
- }
6466
- for (const autoSubEntry of this.autoSubscribe) {
6467
- if (typeof pattern === "string" && (pattern === "*" || pattern.startsWith(`${autoSubEntry}.`))) {
6468
- let state;
6469
- try {
6470
- state = await this.#states.getState(`system.adapter.${autoSubEntry}.subscribes`);
6471
- } catch {
6472
- }
6473
- state = state || { val: "{}" };
6474
- state.val = state.val || "{}";
6475
- let subs;
6476
- try {
6477
- subs = JSON.parse(state.val);
6478
- } catch {
6479
- this._logger.error(`${this.namespaceLog} Cannot parse subscribes for "${autoSubEntry}.subscribes"`);
6480
- }
6481
- if (!import_js_controller_common.tools.isObject(subs)) {
6482
- subs = {};
6483
- }
6484
- if (!import_js_controller_common.tools.isObject(subs[pattern])) {
6485
- subs[pattern] = {};
6486
- }
6487
- if (typeof subs[pattern][this.namespace] !== "number") {
6488
- subs[pattern][this.namespace] = 0;
6489
- }
6490
- subs[pattern][this.namespace]++;
6491
- this.outputCount++;
6492
- await this.#states.setState(`system.adapter.${autoSubEntry}.subscribes`, JSON.stringify(subs));
6493
- }
6494
- }
6495
- if (Array.isArray(pattern)) {
6496
- const aliasesIds = pattern.map((id) => id.startsWith(import_constants.ALIAS_STARTS_WITH) ? id : null).filter((id) => id);
6497
- const nonAliasesIds = pattern.map((id) => !id.startsWith(import_constants.ALIAS_STARTS_WITH) ? id : null).filter((id) => id);
6498
- for (const aliasPattern of pattern) {
6499
- if ((aliasPattern.startsWith(import_constants.ALIAS_STARTS_WITH) || aliasPattern.includes("*")) && !this.aliasPatterns.has(aliasPattern)) {
6500
- this.aliasPatterns.add(aliasPattern);
6501
- }
6502
- }
6503
- const promises = [];
6504
- if (aliasesIds.length) {
6505
- if (!this._aliasObjectsSubscribed) {
6506
- this._aliasObjectsSubscribed = true;
6507
- this.#objects.subscribe(`${import_constants.ALIAS_STARTS_WITH}*`);
6508
- }
6509
- const aliasObjs = await this._getObjectsByArray(aliasesIds, options);
6510
- for (const aliasObj of aliasObjs) {
6511
- if (aliasObj) {
6512
- promises.push(this._addAliasSubscribe(aliasObj, aliasObj._id));
6513
- }
6514
- }
6515
- }
6516
- if (nonAliasesIds.length) {
6517
- for (const id of nonAliasesIds) {
6518
- promises.push(new Promise((resolve) => this.#states.subscribeUser(id, resolve)));
6519
- }
6520
- }
6521
- try {
6522
- await Promise.all(promises);
6523
- } catch (e) {
6524
- this._logger.error(`${this.namespaceLog} Error on "subscribeForeignStates": ${e.message}`);
6525
- }
6526
- return import_js_controller_common.tools.maybeCallback(callback);
6527
- } else if (pattern.includes("*")) {
6528
- if (pattern === "*" || pattern.startsWith(import_constants.ALIAS_STARTS_WITH)) {
6529
- if (!this._aliasObjectsSubscribed) {
6530
- this._aliasObjectsSubscribed = true;
6531
- this.#objects.subscribe(`${import_constants.ALIAS_STARTS_WITH}*`);
6532
- }
6533
- try {
6534
- const objs = await this.getForeignObjectsAsync(pattern, null, null, options);
6535
- const promises = [];
6536
- if (!this.aliasPatterns.has(pattern)) {
6537
- this.aliasPatterns.add(pattern);
6538
- }
6539
- for (const id of Object.keys(objs)) {
6540
- if (id.startsWith(import_constants.ALIAS_STARTS_WITH)) {
6541
- const aliasObj = objs[id];
6542
- promises.push(this._addAliasSubscribe(aliasObj, pattern));
6543
- }
6544
- }
6545
- try {
6546
- await Promise.all(promises);
6547
- } catch (e) {
6548
- this._logger.error(`${this.namespaceLog} Error on "subscribeForeignStates": ${e.message}`);
6549
- }
6550
- if (!this.#states) {
6551
- this._logger.info(`${this.namespaceLog} subscribeForeignStates not processed because States database not connected`);
6552
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
6553
- }
6554
- if (promises.length && pattern !== "*") {
6555
- return import_js_controller_common.tools.maybeCallback(callback);
6556
- }
6557
- this.#states.subscribeUser(pattern, callback);
6558
- } catch (e) {
6559
- this._logger.warn(`${this.namespaceLog} Cannot subscribe to ${pattern}: ${e.message}`);
6560
- return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6561
- }
6562
- } else {
6563
- this.#states.subscribeUser(pattern, callback);
6564
- }
6565
- } else if (pattern.startsWith(import_constants.ALIAS_STARTS_WITH)) {
6566
- if (!this._aliasObjectsSubscribed) {
6567
- this._aliasObjectsSubscribed = true;
6568
- this.#objects.subscribe(`${import_constants.ALIAS_STARTS_WITH}*`);
6569
- }
6570
- try {
6571
- const aliasObj = await this.#objects.getObject(pattern, options);
6572
- if (aliasObj) {
6573
- await this._addAliasSubscribe(aliasObj, pattern);
6574
- return import_js_controller_common.tools.maybeCallback(callback);
6575
- }
6576
- return import_js_controller_common.tools.maybeCallback(callback);
6577
- } catch (e) {
6578
- this._logger.warn(`${this.namespaceLog} cannot subscribe on alias "${pattern}": ${e.message}`);
6579
- }
6580
- } else {
6581
- this.#states.subscribeUser(pattern, callback);
6582
- }
6437
+ const cb = callback;
6438
+ this.#subscriptions.subscribeForeignStates(pattern, options).then(() => cb?.(), (err) => cb?.(err));
6583
6439
  }
6584
6440
  /**
6585
6441
  * Unsubscribe for changes for given pattern
@@ -6612,85 +6468,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6612
6468
  if (options !== null && options !== void 0) {
6613
6469
  import_validator.Validator.assertObject(options, "options");
6614
6470
  }
6615
- return this._unsubscribeForeignStates({ pattern, options, callback });
6616
- }
6617
- async _unsubscribeForeignStates(_options) {
6618
- const { pattern, callback } = _options;
6619
- if (!this.#states) {
6620
- this._logger.info(`${this.namespaceLog} unsubscrubeForeignStates not processed because States database not connected`);
6621
- return import_js_controller_common.tools.maybeCallbackWithError(callback, import_js_controller_common.tools.ERRORS.ERROR_DB_CLOSED);
6622
- }
6623
- if (this.autoSubscribe && typeof pattern === "string") {
6624
- for (const autoSub of this.autoSubscribe) {
6625
- if (pattern === "*" || pattern.substring(0, autoSub.length + 1) === `${autoSub}.`) {
6626
- let state;
6627
- try {
6628
- state = await this.#states.getState(`system.adapter.${autoSub}.subscribes`);
6629
- } catch {
6630
- }
6631
- if (!state || !state.val) {
6632
- continue;
6633
- }
6634
- let subs;
6635
- try {
6636
- subs = JSON.parse(state.val);
6637
- } catch {
6638
- this._logger.error(`${this.namespaceLog} Cannot parse subscribes for "${autoSub}.subscribes"`);
6639
- continue;
6640
- }
6641
- if (!import_js_controller_common.tools.isObject(subs) || !import_js_controller_common.tools.isObject(subs[pattern]) || subs[pattern][this.namespace] === void 0) {
6642
- continue;
6643
- }
6644
- if (typeof subs[pattern][this.namespace] === "number") {
6645
- subs[pattern][this.namespace]--;
6646
- if (subs[pattern][this.namespace] <= 0) {
6647
- delete subs[pattern][this.namespace];
6648
- }
6649
- } else {
6650
- delete subs[pattern][this.namespace];
6651
- }
6652
- if (!Object.keys(subs[pattern]).length) {
6653
- delete subs[pattern];
6654
- }
6655
- this.outputCount++;
6656
- await this.#states.setState(`system.adapter.${autoSub}.subscribes`, JSON.stringify(subs));
6657
- }
6658
- }
6659
- }
6660
- let aliasPattern;
6661
- const promises = [];
6662
- if (Array.isArray(pattern)) {
6663
- for (const _pattern of pattern) {
6664
- promises.push(this.unsubscribeForeignStatesAsync(_pattern));
6665
- }
6666
- } else if (pattern.includes("*") || pattern.startsWith(import_constants.ALIAS_STARTS_WITH)) {
6667
- if (pattern === "*" || pattern.startsWith(import_constants.ALIAS_STARTS_WITH)) {
6668
- aliasPattern = pattern;
6669
- if (pattern === "*") {
6670
- promises.push(this.#states.unsubscribeUser(pattern));
6671
- }
6672
- } else {
6673
- promises.push(this.#states.unsubscribeUser(pattern));
6674
- }
6675
- } else {
6676
- promises.push(this.#states.unsubscribeUser(pattern));
6677
- }
6678
- if (aliasPattern) {
6679
- this.aliasPatterns.delete(aliasPattern);
6680
- for (const [sourceId, alias] of this.aliases) {
6681
- for (let i = alias.targets.length - 1; i >= 0; i--) {
6682
- if (alias.targets[i].pattern === aliasPattern) {
6683
- promises.push(this._removeAliasSubscribe(sourceId, i));
6684
- }
6685
- }
6686
- }
6687
- }
6688
- await Promise.all(promises);
6689
- if (!this.aliases.size && this._aliasObjectsSubscribed) {
6690
- this._aliasObjectsSubscribed = false;
6691
- this.#objects.unsubscribe(`${import_constants.ALIAS_STARTS_WITH}*`);
6692
- }
6693
- return import_js_controller_common.tools.maybeCallback(callback);
6471
+ const cb = callback;
6472
+ this.#subscriptions.unsubscribeForeignStates(pattern, options).then(() => cb?.(), (err) => cb?.(err));
6694
6473
  }
6695
6474
  /**
6696
6475
  * Subscribe for changes on all states of this instance, that pass the pattern
@@ -6714,11 +6493,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6714
6493
  if (options !== null && options !== void 0) {
6715
6494
  import_validator.Validator.assertObject(options, "options");
6716
6495
  }
6717
- return this._subscribeForeignStates({
6718
- pattern: Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true),
6719
- options,
6720
- callback
6721
- });
6496
+ const cb = callback;
6497
+ this.#subscriptions.subscribeForeignStates(Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true), options).then(() => cb?.(), (err) => cb?.(err));
6722
6498
  }
6723
6499
  /**
6724
6500
  * Unsubscribe for changes for given pattern for own states.
@@ -6744,11 +6520,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6744
6520
  if (options !== null && options !== void 0) {
6745
6521
  import_validator.Validator.assertObject(options, "options");
6746
6522
  }
6747
- return this._unsubscribeForeignStates({
6748
- pattern: Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true),
6749
- options,
6750
- callback
6751
- });
6523
+ const cb = callback;
6524
+ this.#subscriptions.unsubscribeForeignStates(Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true), options).then(() => cb?.(), (err) => cb?.(err));
6752
6525
  }
6753
6526
  /**
6754
6527
  * Return plugin instance
@@ -6776,27 +6549,6 @@ class AdapterClass extends import_node_events.EventEmitter {
6776
6549
  import_validator.Validator.assertString(name, "name");
6777
6550
  return this.pluginHandler.getPluginConfig(name);
6778
6551
  }
6779
- async _autoSubscribeOn() {
6780
- if (!this.autoSubscribe && this.#objects) {
6781
- try {
6782
- const res = await this.#objects.getObjectViewAsync("system", "instance", {
6783
- startkey: "system.adapter.",
6784
- endkey: "system.adapter.\u9999"
6785
- });
6786
- this.autoSubscribe = [];
6787
- for (const row of res.rows) {
6788
- if (row.value?.common.subscribable) {
6789
- const _id = row.id.substring(15);
6790
- if (!this.autoSubscribe.includes(_id)) {
6791
- this.autoSubscribe.push(_id);
6792
- }
6793
- }
6794
- }
6795
- await this.#objects.subscribeAsync("system.adapter.*");
6796
- } catch {
6797
- }
6798
- }
6799
- }
6800
6552
  /**
6801
6553
  * This method returns the list of license that can be used by this adapter
6802
6554
  *
@@ -6902,7 +6654,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6902
6654
  ack: true,
6903
6655
  expire: reportStatusExpirySec,
6904
6656
  from: id
6905
- });
6657
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set alive state: ${e.message}`));
6906
6658
  this.outputCount++;
6907
6659
  if (this.connected) {
6908
6660
  this.#states.setState(`${id}.connected`, {
@@ -6910,24 +6662,24 @@ class AdapterClass extends import_node_events.EventEmitter {
6910
6662
  ack: true,
6911
6663
  expire: reportStatusExpirySec,
6912
6664
  from: id
6913
- });
6665
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set connected state: ${e.message}`));
6914
6666
  this.outputCount++;
6915
6667
  }
6916
6668
  if (!this.startedInCompactMode) {
6917
6669
  (0, import_pidusage.default)(process.pid, (err, stats) => {
6918
- if (!err && this && this.#states && this.#states.setState && stats) {
6670
+ if (!err && this && this.#states && this.#states.setState && stats && !this.terminated) {
6919
6671
  this.#states.setState(`${id}.cpu`, {
6920
6672
  ack: true,
6921
6673
  from: id,
6922
6674
  val: Math.round(100 * stats.cpu) / 100,
6923
6675
  expire: reportStatusExpirySec
6924
- });
6676
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set cpu state: ${e.message}`));
6925
6677
  this.#states.setState(`${id}.cputime`, {
6926
6678
  ack: true,
6927
6679
  from: id,
6928
6680
  val: stats.ctime / 1e3,
6929
6681
  expire: reportStatusExpirySec
6930
- });
6682
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set cputime state: ${e.message}`));
6931
6683
  this.outputCount += 2;
6932
6684
  }
6933
6685
  });
@@ -6938,19 +6690,19 @@ class AdapterClass extends import_node_events.EventEmitter {
6938
6690
  ack: true,
6939
6691
  from: id,
6940
6692
  expire: reportStatusExpirySec
6941
- });
6693
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set memRss state: ${e.message}`));
6942
6694
  this.#states.setState(`${id}.memHeapTotal`, {
6943
6695
  val: parseFloat((mem.heapTotal / 1048576).toFixed(2)),
6944
6696
  ack: true,
6945
6697
  from: id,
6946
6698
  expire: reportStatusExpirySec
6947
- });
6699
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set memHeapTotal state: ${e.message}`));
6948
6700
  this.#states.setState(`${id}.memHeapUsed`, {
6949
6701
  val: parseFloat((mem.heapUsed / 1048576).toFixed(2)),
6950
6702
  ack: true,
6951
6703
  from: id,
6952
6704
  expire: reportStatusExpirySec
6953
- });
6705
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set memHeapUsed state: ${e.message}`));
6954
6706
  } catch (e) {
6955
6707
  this._logger.warn(`${this.namespaceLog} Could not query used process memory: ${e.message}`);
6956
6708
  }
@@ -6962,7 +6714,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6962
6714
  ack: true,
6963
6715
  from: id,
6964
6716
  expire: reportStatusExpirySec
6965
- });
6717
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set eventLoopLag state: ${e.message}`));
6966
6718
  this.eventLoopLags = [];
6967
6719
  this.outputCount++;
6968
6720
  }
@@ -6973,19 +6725,19 @@ class AdapterClass extends import_node_events.EventEmitter {
6973
6725
  ack: true,
6974
6726
  from: id,
6975
6727
  expire: reportStatusExpirySec
6976
- });
6728
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set uptime state: ${e.message}`));
6977
6729
  this.#states.setState(`${id}.inputCount`, {
6978
6730
  val: this.inputCount,
6979
6731
  ack: true,
6980
6732
  from: id,
6981
6733
  expire: reportStatusExpirySec
6982
- });
6734
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set inputCount state: ${e.message}`));
6983
6735
  this.#states.setState(`${id}.outputCount`, {
6984
6736
  val: this.outputCount,
6985
6737
  ack: true,
6986
6738
  from: id,
6987
6739
  expire: reportStatusExpirySec
6988
- });
6740
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set outputCount state: ${e.message}`));
6989
6741
  this.inputCount = 0;
6990
6742
  this.outputCount = 0;
6991
6743
  }
@@ -7053,7 +6805,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7053
6805
  }
7054
6806
  } else if (this.#states?.pushLog) {
7055
6807
  for (const instanceId of this.logList) {
7056
- this.#states.pushLog(instanceId, info);
6808
+ this.#states.pushLog(instanceId, info).catch((e) => this._logger.error(`${this.namespaceLog} Cannot push log: ${e.message}`));
7057
6809
  }
7058
6810
  }
7059
6811
  });
@@ -7077,7 +6829,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7077
6829
  if (this.logList.size && messages?.length && this.#states) {
7078
6830
  for (const message of messages) {
7079
6831
  for (const instanceId of this.logList) {
7080
- this.#states.pushLog(instanceId, message);
6832
+ this.#states.pushLog(instanceId, message).catch((e) => this._logger.error(`${this.namespaceLog} Cannot push log: ${e.message}`));
7081
6833
  }
7082
6834
  }
7083
6835
  }
@@ -7139,7 +6891,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7139
6891
  this.emit("log", msg);
7140
6892
  }
7141
6893
  };
7142
- this.#states.subscribeLog(`system.adapter.${this.namespace}`);
6894
+ this.#states.subscribeLog(`system.adapter.${this.namespace}`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to log: ${e.message}`));
7143
6895
  } else {
7144
6896
  this.requireLog = (isActive) => {
7145
6897
  if (isActive) {
@@ -7168,7 +6920,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7168
6920
  this.#states = new this.States({
7169
6921
  namespace: this.namespaceLog,
7170
6922
  connection: this._config.states,
7171
- connected: async () => {
6923
+ connected: /* @__PURE__ */ __name(async () => {
7172
6924
  if (!this.#states) {
7173
6925
  return;
7174
6926
  }
@@ -7179,11 +6931,11 @@ class AdapterClass extends import_node_events.EventEmitter {
7179
6931
  this._initializeTimeout = null;
7180
6932
  }
7181
6933
  if (!this._config.isInstall) {
7182
- this.#states.subscribe(`system.adapter.${this.namespace}.sigKill`);
7183
- this.#states.subscribe(`system.adapter.${this.namespace}.logLevel`);
6934
+ this.#states.subscribe(`system.adapter.${this.namespace}.sigKill`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to sigKill: ${e.message}`));
6935
+ this.#states.subscribe(`system.adapter.${this.namespace}.logLevel`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to logLevel: ${e.message}`));
7184
6936
  }
7185
6937
  if (this._options.subscribable) {
7186
- this.#states.subscribe(`system.adapter.${this.namespace}.subscribes`);
6938
+ this.#states.subscribe(`system.adapter.${this.namespace}.subscribes`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to subscribes: ${e.message}`));
7187
6939
  let state;
7188
6940
  try {
7189
6941
  state = await this.#states.getStateAsync(`system.adapter.${this.namespace}.subscribes`);
@@ -7202,9 +6954,9 @@ class AdapterClass extends import_node_events.EventEmitter {
7202
6954
  return import_js_controller_common.tools.maybeCallback(cb);
7203
6955
  }
7204
6956
  return import_js_controller_common.tools.maybeCallback(cb);
7205
- },
6957
+ }, "connected"),
7206
6958
  logger: this._logger,
7207
- change: async (id, stateOrMessage) => {
6959
+ change: /* @__PURE__ */ __name(async (id, stateOrMessage) => {
7208
6960
  this.inputCount++;
7209
6961
  const state = stateOrMessage;
7210
6962
  if (!id || typeof id !== "string") {
@@ -7225,7 +6977,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7225
6977
  isScheduled: false,
7226
6978
  exitCode: import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION,
7227
6979
  updateAliveState: false
7228
- });
6980
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7229
6981
  }
7230
6982
  }
7231
6983
  }
@@ -7236,12 +6988,9 @@ class AdapterClass extends import_node_events.EventEmitter {
7236
6988
  if (state.val && state.val !== currentLevel && (0, import_tools.isLogLevel)(newLogLevel)) {
7237
6989
  this.overwriteLogLevel = true;
7238
6990
  this._config.log.level = newLogLevel;
7239
- for (const transport in this._logger.transports) {
7240
- if (!Object.prototype.hasOwnProperty.call(this._logger.transports, transport)) {
7241
- continue;
7242
- }
7243
- if (!this._logger.transports[transport]._defaultConfigLoglevel) {
7244
- this._logger.transports[transport].level = newLogLevel;
6991
+ for (const transport of this._logger.transports) {
6992
+ if (!transport._defaultConfigLoglevel) {
6993
+ transport.level = newLogLevel;
7245
6994
  }
7246
6995
  }
7247
6996
  this._logger.info(`${this.namespaceLog} Loglevel changed from "${currentLevel}" to "${state.val}"`);
@@ -7254,7 +7003,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7254
7003
  val: currentLevel,
7255
7004
  ack: true,
7256
7005
  from: `system.adapter.${this.namespace}`
7257
- });
7006
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set logLevel state: ${e.message}`));
7258
7007
  }
7259
7008
  }
7260
7009
  if (id === `system.adapter.${this.namespace}.checkLogging`) {
@@ -7286,25 +7035,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7286
7035
  } else if (id === `messagebox.system.adapter.${this.namespace}` && state) {
7287
7036
  const obj = state;
7288
7037
  if (obj) {
7289
- let callbackObj;
7290
- if (obj.callback?.id) {
7291
- callbackObj = this.messageCallbacks.get(obj.callback.id);
7292
- }
7293
- if (obj.callback?.ack && obj.callback.id && callbackObj) {
7294
- if (typeof callbackObj.cb === "function") {
7295
- callbackObj.cb(obj.message);
7296
- if (callbackObj.timer) {
7297
- clearTimeout(callbackObj.timer);
7298
- }
7299
- this.messageCallbacks.delete(obj.callback.id);
7300
- }
7301
- const now = Date.now();
7302
- for (const [_id, callback] of this.messageCallbacks) {
7303
- if (now - callback.time > 36e5) {
7304
- this.messageCallbacks.delete(_id);
7305
- }
7306
- }
7307
- } else if (!this._stopInProgress) {
7038
+ if (!this.#async.resolveReply(obj) && !this._stopInProgress) {
7308
7039
  if (obj.command === "clientSubscribe") {
7309
7040
  const res = await this.uiMessagingController.registerClientSubscribeByMessage(obj);
7310
7041
  this.sendTo(obj.from, obj.command, res, obj.callback);
@@ -7314,7 +7045,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7314
7045
  return this.uiMessagingController.removeClientSubscribeByMessage(obj);
7315
7046
  }
7316
7047
  if (this._options.message) {
7317
- this._options.message(obj);
7048
+ Promise.resolve(this._options.message(obj)).catch((e) => this._logger.error(`${this.namespaceLog} Error in message handler: ${e.message}`));
7318
7049
  }
7319
7050
  this.emit("message", obj);
7320
7051
  }
@@ -7345,36 +7076,17 @@ class AdapterClass extends import_node_events.EventEmitter {
7345
7076
  }
7346
7077
  }
7347
7078
  }
7348
- } else if (!this._stopInProgress && this.adapterReady && this.aliases.has(id)) {
7349
- const alias = this.aliases.get(id);
7350
- const uniqueTargets = /* @__PURE__ */ new Set();
7351
- for (const target of alias.targets) {
7352
- const targetId = target.id;
7353
- if (uniqueTargets.has(targetId)) {
7354
- continue;
7355
- }
7356
- uniqueTargets.add(targetId);
7357
- const source = alias.source;
7358
- const aState = state ? import_js_controller_common.tools.formatAliasValue({
7359
- sourceCommon: source,
7360
- targetCommon: target,
7361
- state: (0, import_deep_clone.default)(state),
7362
- logger: this._logger,
7363
- logNamespace: this.namespaceLog,
7364
- sourceId: id,
7365
- targetId
7366
- }) : null;
7367
- if (aState || !state) {
7368
- if (typeof this._options.stateChange === "function") {
7369
- this._options.stateChange(targetId, aState);
7370
- } else {
7371
- setImmediate(() => this.emit("stateChange", targetId, aState));
7372
- }
7079
+ } else if (!this._stopInProgress && this.adapterReady && this.#alias.hasSource(id)) {
7080
+ for (const { targetId, state: aState } of this.#alias.resolveSourceChange(id, state)) {
7081
+ if (typeof this._options.stateChange === "function") {
7082
+ Promise.resolve(this._options.stateChange(targetId, aState)).catch((e) => this._logger.error(`${this.namespaceLog} Error in stateChange handler: ${e.message}`));
7083
+ } else {
7084
+ setImmediate(() => this.emit("stateChange", targetId, aState));
7373
7085
  }
7374
7086
  }
7375
7087
  }
7376
- },
7377
- changeUser: (id, state) => {
7088
+ }, "change"),
7089
+ changeUser: /* @__PURE__ */ __name((id, state) => {
7378
7090
  this.inputCount++;
7379
7091
  if (!id || typeof id !== "string") {
7380
7092
  this._logger.warn(`${this.namespaceLog} Invalid id on state change: ${JSON.stringify(id)}`);
@@ -7396,17 +7108,17 @@ class AdapterClass extends import_node_events.EventEmitter {
7396
7108
  }
7397
7109
  }
7398
7110
  }
7399
- },
7400
- disconnected: () => {
7111
+ }, "changeUser"),
7112
+ disconnected: /* @__PURE__ */ __name(() => {
7401
7113
  this.connected = false;
7402
7114
  !this.terminated && setTimeout(() => {
7403
7115
  if (this.connected) {
7404
7116
  return;
7405
7117
  }
7406
7118
  this._logger.warn(`${this.namespaceLog} Cannot connect/reconnect to states DB. Stopping adapter.`);
7407
- this._stop({ exitCode: import_js_controller_common.EXIT_CODES.NO_ERROR, updateAliveState: false });
7119
+ this._stop({ exitCode: import_js_controller_common.EXIT_CODES.NO_ERROR, updateAliveState: false }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7408
7120
  }, 5e3);
7409
- }
7121
+ }, "disconnected")
7410
7122
  });
7411
7123
  }
7412
7124
  _initObjects(cb) {
@@ -7427,7 +7139,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7427
7139
  namespace: this.namespaceLog,
7428
7140
  connection: this._config.objects,
7429
7141
  logger: this._logger,
7430
- connected: async () => {
7142
+ connected: /* @__PURE__ */ __name(async () => {
7431
7143
  this.connected = true;
7432
7144
  if (this._initializeTimeout) {
7433
7145
  clearTimeout(this._initializeTimeout);
@@ -7457,25 +7169,31 @@ class AdapterClass extends import_node_events.EventEmitter {
7457
7169
  } else {
7458
7170
  return import_js_controller_common.tools.maybeCallback(cb);
7459
7171
  }
7460
- },
7461
- disconnected: () => {
7172
+ }, "connected"),
7173
+ disconnected: /* @__PURE__ */ __name(() => {
7462
7174
  this.connected = false;
7463
7175
  !this.terminated && setTimeout(() => {
7464
7176
  if (this.connected) {
7465
7177
  return;
7466
7178
  }
7467
7179
  this._logger.warn(`${this.namespaceLog} Cannot connect/reconnect to objects DB. Stopping adapter.`);
7468
- this._stop({ exitCode: import_js_controller_common.EXIT_CODES.NO_ERROR, updateAliveState: false });
7180
+ this._stop({ exitCode: import_js_controller_common.EXIT_CODES.NO_ERROR, updateAliveState: false }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7469
7181
  }, 4e3);
7470
- },
7471
- change: async (id, obj) => {
7182
+ }, "disconnected"),
7183
+ change: /* @__PURE__ */ __name(async (id, obj) => {
7472
7184
  if (!id) {
7473
7185
  this._logger.error(`${this.namespaceLog} change ID is empty: ${JSON.stringify(obj)}`);
7474
7186
  return;
7475
7187
  }
7476
7188
  if (id === `system.adapter.${this.namespace}` && obj?.common?.enabled === false) {
7477
7189
  this._logger.info(`${this.namespaceLog} Adapter is disabled => stop`);
7478
- this._stop();
7190
+ this._stop().catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7191
+ return;
7192
+ }
7193
+ if (id === import_CertificateManager.CERTIFICATES_OBJECT_ID) {
7194
+ if (this.#async.hasRelevantCertificateChange(obj)) {
7195
+ this.#scheduleCertificateRestart("Changed certificate detected");
7196
+ }
7479
7197
  return;
7480
7198
  }
7481
7199
  if (id === "system.config" && obj?.common && (this._options.useFormatDate || this.defaultHistory !== void 0)) {
@@ -7487,57 +7205,15 @@ class AdapterClass extends import_node_events.EventEmitter {
7487
7205
  this.defaultHistory = obj.common.defaultHistory;
7488
7206
  }
7489
7207
  if (id.startsWith(import_constants.ALIAS_STARTS_WITH)) {
7490
- let isNewAlias = true;
7491
- for (const [sourceId, alias] of this.aliases) {
7492
- const targetAlias = alias.targets.find((entry) => entry.id === id);
7493
- if (targetAlias) {
7494
- isNewAlias = false;
7495
- if (obj?.common?.alias?.id) {
7496
- const newSourceId = typeof obj.common.alias.id.read === "string" ? obj.common.alias.id.read : obj.common.alias.id;
7497
- if (newSourceId !== sourceId) {
7498
- await this._removeAliasSubscribe(sourceId, targetAlias);
7499
- try {
7500
- await this._addAliasSubscribe(obj, targetAlias.pattern);
7501
- } catch (e) {
7502
- this._logger.error(`${this.namespaceLog} Could not add alias subscription: ${e.message}`);
7503
- }
7504
- } else {
7505
- targetAlias.min = obj.common.min;
7506
- targetAlias.max = obj.common.max;
7507
- targetAlias.type = obj.common.type;
7508
- targetAlias.alias = (0, import_deep_clone.default)(obj.common.alias);
7509
- }
7510
- } else {
7511
- await this._removeAliasSubscribe(sourceId, targetAlias);
7512
- }
7513
- }
7514
- }
7515
- if (isNewAlias && obj) {
7516
- for (const aliasPattern of this.aliasPatterns) {
7517
- const testPattern = aliasPattern.slice(-1) === "*" ? new RegExp(import_js_controller_common.tools.pattern2RegEx(aliasPattern)) : aliasPattern;
7518
- if (typeof testPattern === "string" && aliasPattern === id || testPattern instanceof RegExp && testPattern.test(id)) {
7519
- try {
7520
- await this._addAliasSubscribe(obj, id);
7521
- } catch (e) {
7522
- this._logger.warn(`${this.namespaceLog} Could not add alias subscription: ${e.message}`);
7523
- }
7524
- break;
7525
- }
7526
- }
7527
- }
7208
+ await this.#alias.handleAliasObjectChange(id, obj);
7528
7209
  }
7529
7210
  if (id.startsWith("system.adapter.")) {
7530
7211
  if (obj?.common?.subscribable) {
7531
7212
  const _id = id.substring(15);
7532
7213
  if (obj.common.enabled) {
7533
- if (!this.autoSubscribe.includes(_id)) {
7534
- this.autoSubscribe.push(_id);
7535
- }
7214
+ this.#subscriptions.addSubscribableInstance(_id);
7536
7215
  } else {
7537
- const pos = this.autoSubscribe.indexOf(_id);
7538
- if (pos !== -1) {
7539
- this.autoSubscribe.splice(pos, 1);
7540
- }
7216
+ this.#subscriptions.removeSubscribableInstance(_id);
7541
7217
  }
7542
7218
  }
7543
7219
  }
@@ -7553,8 +7229,8 @@ class AdapterClass extends import_node_events.EventEmitter {
7553
7229
  this.enums[id] = obj;
7554
7230
  }
7555
7231
  }
7556
- },
7557
- changeUser: (id, obj) => {
7232
+ }, "change"),
7233
+ changeUser: /* @__PURE__ */ __name((id, obj) => {
7558
7234
  if (!id) {
7559
7235
  this._logger.error(`${this.namespaceLog} change ID is empty: ${JSON.stringify(obj)}`);
7560
7236
  return;
@@ -7578,8 +7254,8 @@ class AdapterClass extends import_node_events.EventEmitter {
7578
7254
  setImmediate(() => this.emit("objectChange", id, obj));
7579
7255
  }
7580
7256
  }
7581
- },
7582
- changeFileUser: (id, fileName, size) => {
7257
+ }, "changeUser"),
7258
+ changeFileUser: /* @__PURE__ */ __name((id, fileName, size) => {
7583
7259
  if (!id) {
7584
7260
  this._logger.error(`${this.namespaceLog} change file name is empty`);
7585
7261
  return;
@@ -7588,7 +7264,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7588
7264
  typeof this._options.fileChange === "function" && setImmediate(() => this._options.fileChange(id, fileName, size));
7589
7265
  setImmediate(() => this.emit("fileChange", id, fileName, size));
7590
7266
  }
7591
- }
7267
+ }, "changeFileUser")
7592
7268
  });
7593
7269
  }
7594
7270
  /**
@@ -7645,7 +7321,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7645
7321
  if (!this.#states || !this.#objects || this.terminated) {
7646
7322
  return;
7647
7323
  }
7648
- this.#states.subscribe(`system.adapter.${this.namespace}.plugins.*`);
7324
+ this.#states.subscribe(`system.adapter.${this.namespace}.plugins.*`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to plugins: ${e.message}`));
7649
7325
  if (this._options.instance === void 0) {
7650
7326
  if (!adapterConfig || !("common" in adapterConfig) || !adapterConfig.common.enabled) {
7651
7327
  if (adapterConfig && "common" in adapterConfig && adapterConfig.common.enabled !== void 0) {
@@ -7721,13 +7397,12 @@ class AdapterClass extends import_node_events.EventEmitter {
7721
7397
  } else {
7722
7398
  this.stop = (params) => this._stop({ ...params, isPause: false });
7723
7399
  }
7724
- this.#states.subscribe(`${import_constants2.SYSTEM_ADAPTER_PREFIX}*.logging`);
7400
+ this.#states.subscribe(`${import_constants2.SYSTEM_ADAPTER_PREFIX}*.logging`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to logging: ${e.message}`));
7725
7401
  if (typeof this._options.message === "function" && // @ts-expect-error, we should infer correctly that this is an InstanceObject in this case
7726
7402
  !(0, import_utils.isMessageboxSupported)(adapterConfig.common)) {
7727
7403
  this._logger.error(`${this.namespaceLog} : message handler implemented, but messagebox not enabled. Define common.messagebox in io-package.json for adapter or delete message handler.`);
7728
7404
  } else if ((0, import_utils.isMessageboxSupported)(adapterConfig.common)) {
7729
- this.mboxSubscribed = true;
7730
- this.#states.subscribeMessage(`system.adapter.${this.namespace}`);
7405
+ this.#states.subscribeMessage(`system.adapter.${this.namespace}`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to messages: ${e.message}`));
7731
7406
  }
7732
7407
  } else {
7733
7408
  this.name = adapterConfig.name || this.name;
@@ -7739,19 +7414,22 @@ class AdapterClass extends import_node_events.EventEmitter {
7739
7414
  this.host = this.common?.host || import_js_controller_common.tools.getHostName();
7740
7415
  }
7741
7416
  this.adapterConfig = adapterConfig;
7742
- this._utils = new import_validator.Validator(this.#objects, this.#states, this.namespaceLog, this._logger, this.namespace, this._namespaceRegExp);
7417
+ this._utils = new import_validator.Validator(this.#objects, this.namespaceLog, this._logger, this.namespace, this._namespaceRegExp);
7743
7418
  this.log = new import_log.Log(this.namespaceLog, this._config.log.level, this._logger);
7744
7419
  await this._createInstancesObjects(adapterConfig);
7745
7420
  if (this._options.objects) {
7746
7421
  this.oObjects = await this.getAdapterObjectsAsync();
7747
7422
  await this.subscribeObjectsAsync("*");
7748
7423
  }
7749
- await this.getSystemSecret();
7750
- const promises = [];
7424
+ const secret = await this.getSystemSecret();
7751
7425
  if (Array.isArray(adapterConfig.encryptedNative)) {
7426
+ this._decryptedNativeAttributes = new Array();
7752
7427
  for (const attr of adapterConfig.encryptedNative) {
7753
- if (typeof this.config[attr] === "string") {
7754
- promises.push(this.getEncryptedConfig(attr).then((decryptedValue) => (0, import_utils.setObjectAttribute)(this.config, attr, decryptedValue)).catch((e) => this._logger.error(`${this.namespaceLog} Can not decrypt attribute ${attr}: ${e.message}`)));
7428
+ try {
7429
+ (0, import_utils.decryptArray)({ obj: this.config, secret, keys: [attr] });
7430
+ this._decryptedNativeAttributes.push(attr);
7431
+ } catch (e) {
7432
+ this._logger.error(`${this.namespaceLog} Can not decrypt attribute ${attr}: ${e.message}`);
7755
7433
  }
7756
7434
  }
7757
7435
  } else {
@@ -7760,7 +7438,6 @@ class AdapterClass extends import_node_events.EventEmitter {
7760
7438
  this.SUPPORTED_FEATURES.splice(idx, 1);
7761
7439
  }
7762
7440
  }
7763
- await Promise.all(promises);
7764
7441
  if (!this.#states) {
7765
7442
  return;
7766
7443
  }
@@ -7769,7 +7446,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7769
7446
  val: this._config.log.level,
7770
7447
  ack: true,
7771
7448
  from: `system.adapter.${this.namespace}`
7772
- });
7449
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set logLevel state: ${e.message}`));
7773
7450
  try {
7774
7451
  await this.#checkObjectsWarnLimit();
7775
7452
  } catch (e) {
@@ -7792,15 +7469,18 @@ class AdapterClass extends import_node_events.EventEmitter {
7792
7469
  ack: true,
7793
7470
  from: id,
7794
7471
  val: !!this.startedInCompactMode
7795
- });
7472
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set compactMode state: ${e.message}`));
7796
7473
  this.outputCount++;
7797
7474
  if (this.startedInCompactMode) {
7798
- this.#states.setState(`${id}.cpu`, { ack: true, from: id, val: 0 });
7799
- this.#states.setState(`${id}.cputime`, { ack: true, from: id, val: 0 });
7800
- this.#states.setState(`${id}.memRss`, { val: 0, ack: true, from: id });
7801
- this.#states.setState(`${id}.memHeapTotal`, { val: 0, ack: true, from: id });
7802
- this.#states.setState(`${id}.memHeapUsed`, { val: 0, ack: true, from: id });
7803
- this.#states.setState(`${id}.eventLoopLag`, { val: 0, ack: true, from: id });
7475
+ const onErr = /* @__PURE__ */ __name((e) => {
7476
+ this._logger.error(`${this.namespaceLog} Cannot reset compact metric: ${e.message}`);
7477
+ }, "onErr");
7478
+ this.#states.setState(`${id}.cpu`, { ack: true, from: id, val: 0 }).catch(onErr);
7479
+ this.#states.setState(`${id}.cputime`, { ack: true, from: id, val: 0 }).catch(onErr);
7480
+ this.#states.setState(`${id}.memRss`, { val: 0, ack: true, from: id }).catch(onErr);
7481
+ this.#states.setState(`${id}.memHeapTotal`, { val: 0, ack: true, from: id }).catch(onErr);
7482
+ this.#states.setState(`${id}.memHeapUsed`, { val: 0, ack: true, from: id }).catch(onErr);
7483
+ this.#states.setState(`${id}.eventLoopLag`, { val: 0, ack: true, from: id }).catch(onErr);
7804
7484
  this.outputCount += 6;
7805
7485
  } else {
7806
7486
  import_js_controller_common.tools.measureEventLoopLag(1e3, (lag) => {
@@ -7821,7 +7501,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7821
7501
  this._logger.debug(`${this.namespaceLog} Schedule restart: ${adapterConfig.common.restartSchedule}`);
7822
7502
  this._restartScheduleJob = this._schedule.scheduleJob(adapterConfig.common.restartSchedule, () => {
7823
7503
  this._logger.info(`${this.namespaceLog} Scheduled restart.`);
7824
- this._stop({ isPause: false, isScheduled: true });
7504
+ this._stop({ isPause: false, isScheduled: true }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7825
7505
  });
7826
7506
  }
7827
7507
  }
@@ -7849,12 +7529,12 @@ class AdapterClass extends import_node_events.EventEmitter {
7849
7529
  _callReadyHandler() {
7850
7530
  if (this._config.isInstall && (typeof this._options.install === "function" || this.listeners("install").length)) {
7851
7531
  if (typeof this._options.install === "function") {
7852
- this._options.install();
7532
+ Promise.resolve(this._options.install()).catch((e) => this._logger.error(`${this.namespaceLog} Error in install handler: ${e.message}`));
7853
7533
  }
7854
7534
  this.emit("install");
7855
7535
  } else {
7856
7536
  if (typeof this._options.ready === "function") {
7857
- this._options.ready();
7537
+ Promise.resolve(this._options.ready()).catch((e) => this._logger.error(`${this.namespaceLog} Error in ready handler: ${e.message}`));
7858
7538
  }
7859
7539
  this.emit("ready");
7860
7540
  }
@@ -7900,7 +7580,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7900
7580
  isScheduled: false,
7901
7581
  exitCode: import_js_controller_common.EXIT_CODES.UNCAUGHT_EXCEPTION,
7902
7582
  updateAliveState: false
7903
- });
7583
+ }).catch((err2) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${err2.message}`));
7904
7584
  } catch (e) {
7905
7585
  this._logger.error(`${this.namespaceLog} exception by stop: ${e ? e.message : e}`);
7906
7586
  }
@@ -7973,7 +7653,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7973
7653
  });
7974
7654
  }
7975
7655
  return new Promise((resolve) => {
7976
- this._extendObjects(objs, resolve);
7656
+ return this._extendObjects(objs, resolve);
7977
7657
  });
7978
7658
  }
7979
7659
  /**
@@ -8023,7 +7703,7 @@ class AdapterClass extends import_node_events.EventEmitter {
8023
7703
  return this.#states.setState(id, state);
8024
7704
  }
8025
7705
  async _extendObjects(tasks, callback) {
8026
- if (!tasks || !tasks.length) {
7706
+ if (!tasks?.length) {
8027
7707
  return import_js_controller_common.tools.maybeCallback(callback);
8028
7708
  }
8029
7709
  const task = tasks.shift();
@@ -8130,7 +7810,7 @@ class AdapterClass extends import_node_events.EventEmitter {
8130
7810
  * Initializes the adapter
8131
7811
  */
8132
7812
  async _init() {
8133
- const _initDBs = () => {
7813
+ const _initDBs = /* @__PURE__ */ __name(() => {
8134
7814
  this._initObjects(() => {
8135
7815
  if (this.inited) {
8136
7816
  this._logger.warn(`${this.namespaceLog} Reconnection to DB.`);
@@ -8139,7 +7819,7 @@ class AdapterClass extends import_node_events.EventEmitter {
8139
7819
  this.inited = true;
8140
7820
  this._initStates(() => this._prepareInitAdapter());
8141
7821
  });
8142
- };
7822
+ }, "_initDBs");
8143
7823
  if (import_fs_extra.default.existsSync(`${this.adapterDir}/package.json`)) {
8144
7824
  this.pack = import_fs_extra.default.readJSONSync(`${this.adapterDir}/package.json`);
8145
7825
  } else {