@iobroker/js-controller-adapter 7.2.3 → 8.0.0-alpha.2-20260923-99da17fcc

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 (108) 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 +1896 -177
  6. package/build/cjs/lib/adapter/adapter.js +788 -1035
  7. package/build/cjs/lib/adapter/adapter.js.map +2 -2
  8. package/build/cjs/lib/adapter/asyncAdapter.d.ts +167 -0
  9. package/build/cjs/lib/adapter/asyncAdapter.js +252 -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/ResourceManager.d.ts +69 -0
  33. package/build/cjs/lib/adapter/managers/ResourceManager.js +170 -0
  34. package/build/cjs/lib/adapter/managers/ResourceManager.js.map +7 -0
  35. package/build/cjs/lib/adapter/managers/SubscriptionManager.d.ts +107 -0
  36. package/build/cjs/lib/adapter/managers/SubscriptionManager.js +349 -0
  37. package/build/cjs/lib/adapter/managers/SubscriptionManager.js.map +7 -0
  38. package/build/cjs/lib/adapter/userInterfaceMessagingController.d.ts +10 -0
  39. package/build/cjs/lib/adapter/userInterfaceMessagingController.js +9 -2
  40. package/build/cjs/lib/adapter/userInterfaceMessagingController.js.map +2 -2
  41. package/build/cjs/lib/adapter/utils.js +15 -1
  42. package/build/cjs/lib/adapter/utils.js.map +2 -2
  43. package/build/cjs/lib/adapter/validator.d.ts +10 -5
  44. package/build/cjs/lib/adapter/validator.js +6 -5
  45. package/build/cjs/lib/adapter/validator.js.map +2 -2
  46. package/build/esm/index.d.ts +0 -1
  47. package/build/esm/index.d.ts.map +1 -1
  48. package/build/esm/index.js +0 -1
  49. package/build/esm/index.js.map +1 -1
  50. package/build/esm/lib/_Types.d.ts +394 -63
  51. package/build/esm/lib/_Types.d.ts.map +1 -1
  52. package/build/esm/lib/adapter/adapter.d.ts +1896 -177
  53. package/build/esm/lib/adapter/adapter.d.ts.map +1 -1
  54. package/build/esm/lib/adapter/adapter.js +900 -1215
  55. package/build/esm/lib/adapter/adapter.js.map +1 -1
  56. package/build/esm/lib/adapter/asyncAdapter.d.ts +167 -0
  57. package/build/esm/lib/adapter/asyncAdapter.d.ts.map +1 -0
  58. package/build/esm/lib/adapter/asyncAdapter.js +225 -0
  59. package/build/esm/lib/adapter/asyncAdapter.js.map +1 -0
  60. package/build/esm/lib/adapter/context.d.ts +34 -0
  61. package/build/esm/lib/adapter/context.d.ts.map +1 -0
  62. package/build/esm/lib/adapter/context.js +2 -0
  63. package/build/esm/lib/adapter/context.js.map +1 -0
  64. package/build/esm/lib/adapter/defaultObjs.d.ts +5 -0
  65. package/build/esm/lib/adapter/defaultObjs.d.ts.map +1 -1
  66. package/build/esm/lib/adapter/defaultObjs.js +5 -0
  67. package/build/esm/lib/adapter/defaultObjs.js.map +1 -1
  68. package/build/esm/lib/adapter/log.d.ts +25 -0
  69. package/build/esm/lib/adapter/log.d.ts.map +1 -1
  70. package/build/esm/lib/adapter/log.js +25 -0
  71. package/build/esm/lib/adapter/log.js.map +1 -1
  72. package/build/esm/lib/adapter/managers/AdapterContextBase.d.ts +49 -0
  73. package/build/esm/lib/adapter/managers/AdapterContextBase.d.ts.map +1 -0
  74. package/build/esm/lib/adapter/managers/AdapterContextBase.js +77 -0
  75. package/build/esm/lib/adapter/managers/AdapterContextBase.js.map +1 -0
  76. package/build/esm/lib/adapter/managers/AliasManager.d.ts +103 -0
  77. package/build/esm/lib/adapter/managers/AliasManager.d.ts.map +1 -0
  78. package/build/esm/lib/adapter/managers/AliasManager.js +269 -0
  79. package/build/esm/lib/adapter/managers/AliasManager.js.map +1 -0
  80. package/build/esm/lib/adapter/managers/CertificateManager.d.ts +50 -0
  81. package/build/esm/lib/adapter/managers/CertificateManager.d.ts.map +1 -0
  82. package/build/esm/lib/adapter/managers/CertificateManager.js +142 -0
  83. package/build/esm/lib/adapter/managers/CertificateManager.js.map +1 -0
  84. package/build/esm/lib/adapter/managers/MessagingManager.d.ts +58 -0
  85. package/build/esm/lib/adapter/managers/MessagingManager.d.ts.map +1 -0
  86. package/build/esm/lib/adapter/managers/MessagingManager.js +267 -0
  87. package/build/esm/lib/adapter/managers/MessagingManager.js.map +1 -0
  88. package/build/esm/lib/adapter/managers/ResourceManager.d.ts +69 -0
  89. package/build/esm/lib/adapter/managers/ResourceManager.d.ts.map +1 -0
  90. package/build/esm/lib/adapter/managers/ResourceManager.js +151 -0
  91. package/build/esm/lib/adapter/managers/ResourceManager.js.map +1 -0
  92. package/build/esm/lib/adapter/managers/SubscriptionManager.d.ts +107 -0
  93. package/build/esm/lib/adapter/managers/SubscriptionManager.d.ts.map +1 -0
  94. package/build/esm/lib/adapter/managers/SubscriptionManager.js +374 -0
  95. package/build/esm/lib/adapter/managers/SubscriptionManager.js.map +1 -0
  96. package/build/esm/lib/adapter/userInterfaceMessagingController.d.ts +10 -0
  97. package/build/esm/lib/adapter/userInterfaceMessagingController.d.ts.map +1 -1
  98. package/build/esm/lib/adapter/userInterfaceMessagingController.js +8 -2
  99. package/build/esm/lib/adapter/userInterfaceMessagingController.js.map +1 -1
  100. package/build/esm/lib/adapter/utils.d.ts.map +1 -1
  101. package/build/esm/lib/adapter/utils.js +1 -1
  102. package/build/esm/lib/adapter/utils.js.map +1 -1
  103. package/build/esm/lib/adapter/validator.d.ts +10 -5
  104. package/build/esm/lib/adapter/validator.d.ts.map +1 -1
  105. package/build/esm/lib/adapter/validator.js +8 -5
  106. package/build/esm/lib/adapter/validator.js.map +1 -1
  107. package/build/tsconfig.build.tsbuildinfo +1 -1
  108. 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,80 @@ 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);
5000
+ }
5001
+ /**
5002
+ * Register an exclusive resource (serial port, TCP/UDP port, USB device, ...) as used by this instance.
5003
+ *
5004
+ * Exclusive resources are the ones that cannot be occupied by more than one instance at the same time.
5005
+ * The information is forwarded to the host this instance runs on and stored under
5006
+ * `system.host.<hostname>.usedResources.<type>`, so the user gets an overview of the occupied resources
5007
+ * and can pick a free one when configuring a new instance.
5008
+ *
5009
+ * Registering is **additive**: call it once per occupied resource, in any order and from any number of
5010
+ * async init paths. The host drops what this instance registered before whenever the instance starts, so
5011
+ * a stale registration from a previous configuration cannot survive a restart.
5012
+ *
5013
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
5014
+ * @param data the strictly typed payload describing the resource, e.g. `{ port: '/dev/ttyUSB0' }`
5015
+ * @throws {Error} when the host refuses the registration - e.g. because `common.declareUsedResources` is not `true` - or does not answer
5016
+ */
5017
+ async registerUsedResource(type, data) {
5018
+ return this.#async.registerUsedResource(type, data);
5019
+ }
5020
+ /**
5021
+ * Ask whether another instance on this host currently holds an exclusive resource, without
5022
+ * registering anything.
5023
+ *
5024
+ * Call this **before** opening the port or the device - afterwards the operating system has
5025
+ * already decided the conflict and this can only improve the error message.
5026
+ *
5027
+ * The answer is a hint, not a permission: the registry knows what adapters declare, so an empty
5028
+ * result does not promise the resource is free.
5029
+ *
5030
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
5031
+ * @param data description of the resource that is about to be used, e.g. `{ port: 1883 }`
5032
+ * @returns the entries of other instances that currently hold it, newest registration first
5033
+ * @throws {Error} when the host refuses the request or does not answer
5034
+ */
5035
+ async checkUsedResource(type, data) {
5036
+ return this.#async.checkUsedResource(type, data);
5037
+ }
5038
+ /**
5039
+ * Free all exclusive resources this instance registered, across all types.
5040
+ *
5041
+ * This is not needed on start-up (the host already resets the registrations of a starting instance) nor
5042
+ * on shutdown (the host marks them as no longer held). Use it when the instance drops everything it
5043
+ * occupied while it keeps running, e.g. on a reconfiguration.
5044
+ *
5045
+ * @throws {Error} when the host refuses the command or does not answer
5046
+ */
5047
+ async clearUsedResources() {
5048
+ return this.#async.clearUsedResources();
5049
+ }
5050
+ /**
5051
+ * Free previously registered exclusive resources of this instance.
5052
+ *
5053
+ * `data` is a **filter, not the exact payload**: every field it names must match, fields it does not name
5054
+ * are ignored. `freeUsedResource('tcpPort', { port: 8080 })` therefore also frees an entry registered as
5055
+ * `{ port: 8080, bind: '0.0.0.0' }`, and if `data` is omitted, all registered resources of the given
5056
+ * `type` for this instance are freed. The change is forwarded to the host this instance runs on and
5057
+ * reflected in `system.host.<hostname>.usedResources.<type>`; a filter that matches nothing is logged by
5058
+ * the host.
5059
+ *
5060
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
5061
+ * @param data the fields identifying the resources to free; if omitted, all resources of `type` are freed
5062
+ * @throws {Error} when the host refuses the command or does not answer
5063
+ */
5064
+ async freeUsedResource(type, data) {
5065
+ return this.#async.freeUsedResource(type, data);
5066
+ }
5067
+ /**
5068
+ * @param type resource type to read; if omitted, the resources of every type are returned
5069
+ * @returns the list of registered resources (across all instances of this host)
5070
+ */
5071
+ async getHostUsedResources(type) {
5072
+ return type === void 0 ? this.#async.getHostUsedResources() : this.#async.getHostUsedResources(type);
4956
5073
  }
4957
5074
  /**
4958
5075
  * Writes value into states DB.
@@ -5155,8 +5272,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5155
5272
  }
5156
5273
  this.users[options.user] = {
5157
5274
  groups: options.groups,
5158
- // @ts-expect-error TODO: UserCommon has no acl
5159
- acl: userAcl.common?.acl || {}
5275
+ acl: {}
5160
5276
  };
5161
5277
  await this._getGroups(options.groups);
5162
5278
  const user = this.users[options.user];
@@ -5166,71 +5282,71 @@ class AdapterClass extends import_node_events.EventEmitter {
5166
5282
  }
5167
5283
  const group = this.groups[gName];
5168
5284
  if (group.common?.acl?.file) {
5169
- if (!user.acl || !user.acl.file) {
5170
- user.acl = user.acl || {};
5171
- user.acl.file = user.acl.file || {};
5285
+ if (!user.acl?.file) {
5286
+ user.acl ||= {};
5287
+ user.acl.file ||= {};
5172
5288
  user.acl.file.create = group.common.acl.file.create;
5173
5289
  user.acl.file.read = group.common.acl.file.read;
5174
5290
  user.acl.file.write = group.common.acl.file.write;
5175
5291
  user.acl.file.delete = group.common.acl.file.delete;
5176
5292
  user.acl.file.list = group.common.acl.file.list;
5177
5293
  } 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;
5294
+ user.acl.file.create ||= group.common.acl.file.create;
5295
+ user.acl.file.read ||= group.common.acl.file.read;
5296
+ user.acl.file.write ||= group.common.acl.file.write;
5297
+ user.acl.file.delete ||= group.common.acl.file.delete;
5298
+ user.acl.file.list ||= group.common.acl.file.list;
5183
5299
  }
5184
5300
  }
5185
5301
  if (group.common?.acl?.object) {
5186
5302
  if (!user.acl || !user.acl.object) {
5187
- user.acl = user.acl || {};
5188
- user.acl.object = user.acl.object || {};
5303
+ user.acl ||= {};
5304
+ user.acl.object ||= {};
5189
5305
  user.acl.object.create = group.common.acl.object.create;
5190
5306
  user.acl.object.read = group.common.acl.object.read;
5191
5307
  user.acl.object.write = group.common.acl.object.write;
5192
5308
  user.acl.object.delete = group.common.acl.object.delete;
5193
5309
  user.acl.object.list = group.common.acl.object.list;
5194
5310
  } 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;
5311
+ user.acl.object.create ||= group.common.acl.object.create;
5312
+ user.acl.object.read ||= group.common.acl.object.read;
5313
+ user.acl.object.write ||= group.common.acl.object.write;
5314
+ user.acl.object.delete ||= group.common.acl.object.delete;
5315
+ user.acl.object.list ||= group.common.acl.object.list;
5200
5316
  }
5201
5317
  }
5202
5318
  if (group.common?.acl?.users) {
5203
5319
  if (!user.acl || !user.acl.users) {
5204
- user.acl = user.acl || {};
5205
- user.acl.users = user.acl.users || {};
5320
+ user.acl ||= {};
5321
+ user.acl.users ||= {};
5206
5322
  user.acl.users.create = group.common.acl.users.create;
5207
5323
  user.acl.users.read = group.common.acl.users.read;
5208
5324
  user.acl.users.write = group.common.acl.users.write;
5209
5325
  user.acl.users.delete = group.common.acl.users.delete;
5210
5326
  user.acl.users.list = group.common.acl.users.list;
5211
5327
  } 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;
5328
+ user.acl.users.create ||= group.common.acl.users.create;
5329
+ user.acl.users.read ||= group.common.acl.users.read;
5330
+ user.acl.users.write ||= group.common.acl.users.write;
5331
+ user.acl.users.delete ||= group.common.acl.users.delete;
5332
+ user.acl.users.list ||= group.common.acl.users.list;
5217
5333
  }
5218
5334
  }
5219
5335
  if (group.common?.acl?.state) {
5220
5336
  if (!user.acl || !user.acl.state) {
5221
- user.acl = user.acl || {};
5222
- user.acl.state = user.acl.state || {};
5337
+ user.acl ||= {};
5338
+ user.acl.state ||= {};
5223
5339
  user.acl.state.create = group.common.acl.state.create;
5224
5340
  user.acl.state.read = group.common.acl.state.read;
5225
5341
  user.acl.state.write = group.common.acl.state.write;
5226
5342
  user.acl.state.delete = group.common.acl.state.delete;
5227
5343
  user.acl.state.list = group.common.acl.state.list;
5228
5344
  } 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;
5345
+ user.acl.state.create ||= group.common.acl.state.create;
5346
+ user.acl.state.read ||= group.common.acl.state.read;
5347
+ user.acl.state.write ||= group.common.acl.state.write;
5348
+ user.acl.state.delete ||= group.common.acl.state.delete;
5349
+ user.acl.state.list ||= group.common.acl.state.list;
5234
5350
  }
5235
5351
  }
5236
5352
  }
@@ -5238,10 +5354,17 @@ class AdapterClass extends import_node_events.EventEmitter {
5238
5354
  return options;
5239
5355
  }
5240
5356
  _checkState(obj, options, command) {
5357
+ if (options.groups?.includes(import_constants.SYSTEM_ADMIN_GROUP)) {
5358
+ return true;
5359
+ }
5241
5360
  const limitToOwnerRights = options.limitToOwnerRights === true;
5242
5361
  if (obj?.acl) {
5243
- obj.acl.state = obj.acl.state || obj.acl.object;
5362
+ obj.acl.state ||= obj.acl.object;
5244
5363
  if (obj.acl.state) {
5364
+ if (!options.acl) {
5365
+ this._logger.warn(`${this.namespaceLog} Permission error for user "${options.user} on "${obj._id}": ${command}`);
5366
+ return false;
5367
+ }
5245
5368
  if (options.user === obj.acl.owner) {
5246
5369
  if (command === "setState" || command === "delState") {
5247
5370
  if (command === "delState" && !options.acl.state.delete) {
@@ -5262,7 +5385,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5262
5385
  } else {
5263
5386
  this._logger.warn(`${this.namespaceLog} Called unknown command on "${obj._id}": ${command}`);
5264
5387
  }
5265
- } else if (options.groups.includes(obj.acl.ownerGroup) && !limitToOwnerRights) {
5388
+ } else if (options.groups?.includes(obj.acl.ownerGroup) && !limitToOwnerRights) {
5266
5389
  if (command === "setState" || command === "delState") {
5267
5390
  if (command === "delState" && !options.acl.state.delete) {
5268
5391
  this._logger.warn(`${this.namespaceLog} Permission error for user "${options.user} on "${obj._id}": ${command}`);
@@ -5630,7 +5753,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5630
5753
  this.outputCount++;
5631
5754
  this.#states.setState(aliasId, import_js_controller_common.tools.formatAliasValue({
5632
5755
  sourceCommon: obj?.common,
5633
- targetCommon: targetObj && targetObj.common,
5756
+ targetCommon: targetObj?.common,
5634
5757
  state,
5635
5758
  logger: this._logger,
5636
5759
  logNamespace: this.namespaceLog,
@@ -5805,7 +5928,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5805
5928
  * }
5806
5929
  * ```
5807
5930
  *
5808
- * See possible attributes of the state in @setState explanation
5931
+ * See possible attributes of the state in `setState` explanation
5809
5932
  */
5810
5933
  getState(id, options, callback) {
5811
5934
  if (!import_js_controller_common.tools.isObject(id)) {
@@ -5828,7 +5951,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5828
5951
  * }
5829
5952
  * ```
5830
5953
  *
5831
- * See possible attributes of the state in @setState explanation
5954
+ * See possible attributes of the state in `setState` explanation
5832
5955
  */
5833
5956
  getForeignState(id, options, callback) {
5834
5957
  if (typeof options === "function") {
@@ -5918,7 +6041,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5918
6041
  if (this.oStates && this.oStates[id]) {
5919
6042
  return import_js_controller_common.tools.maybeCallbackWithError(callback, null, this.oStates[id]);
5920
6043
  }
5921
- return this.#states.getState(id, callback);
6044
+ return callback ? this.#states.getState(id, callback) : this.#states.getState(id);
5922
6045
  }
5923
6046
  }
5924
6047
  // find out default history instance
@@ -5996,7 +6119,7 @@ class AdapterClass extends import_node_events.EventEmitter {
5996
6119
  * }
5997
6120
  * ```
5998
6121
  *
5999
- * See possible attributes of the state in @setState explanation
6122
+ * See possible attributes of the state in `setState` explanation
6000
6123
  */
6001
6124
  getHistory(id, options, callback) {
6002
6125
  if (typeof options === "function") {
@@ -6019,10 +6142,10 @@ class AdapterClass extends import_node_events.EventEmitter {
6019
6142
  } catch (e) {
6020
6143
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6021
6144
  }
6022
- options = options || {};
6023
- options.end = options.end || Date.now() + 5e6;
6145
+ options ||= {};
6146
+ options.end ||= Date.now() + 5e6;
6024
6147
  if (!options.count && !options.start) {
6025
- options.start = options.start || Date.now() - 6048e5;
6148
+ options.start ||= Date.now() - 6048e5;
6026
6149
  }
6027
6150
  if (!options.instance) {
6028
6151
  if (!this.defaultHistory) {
@@ -6065,7 +6188,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6065
6188
  }
6066
6189
  /**
6067
6190
  * Deletes a state of this instance.
6068
- * The object will NOT be deleted. If you want to delete it too, use @delObject instead.
6191
+ * The object will NOT be deleted. If you want to delete it too, use `delObject` instead.
6069
6192
  *
6070
6193
  * It is not required to provice the adapter namespace, because it will automatically be added.
6071
6194
  * E.g. to delete "adapterName.X.myObject", only "myObject" is required as ID.
@@ -6106,7 +6229,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6106
6229
  }
6107
6230
  /**
6108
6231
  * Deletes a state of any adapter.
6109
- * The object is NOT deleted. If you want to delete it too, use @delForeignObject instead.
6232
+ * The object is NOT deleted. If you want to delete it too, use `delForeignObject` instead.
6110
6233
  *
6111
6234
  * No error is returned if state does not exist.
6112
6235
  *
@@ -6147,7 +6270,11 @@ class AdapterClass extends import_node_events.EventEmitter {
6147
6270
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6148
6271
  }
6149
6272
  }
6150
- await this.#states.delState(id, callback);
6273
+ if (callback) {
6274
+ this.#states.delState(id, callback);
6275
+ } else {
6276
+ await this.#states.delState(id);
6277
+ }
6151
6278
  }
6152
6279
  /**
6153
6280
  * Read all states of this adapter, that pass the pattern
@@ -6181,7 +6308,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6181
6308
  const arr = await this.#states.getStates(keys);
6182
6309
  const result = {};
6183
6310
  for (let i = 0; i < keys.length; i++) {
6184
- const obj = targetObjs && targetObjs[i];
6311
+ const obj = targetObjs?.[i];
6185
6312
  if (obj?.common?.alias && srcObjs) {
6186
6313
  const srcObj = srcObjs[i];
6187
6314
  if (srcObj) {
@@ -6295,7 +6422,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6295
6422
  return import_js_controller_common.tools.maybeCallbackWithError(callback, e);
6296
6423
  }
6297
6424
  } else {
6298
- const res = await this._processStates(pattern, options?._objects);
6425
+ const res = await this._processStates(pattern, options._objects);
6299
6426
  return import_js_controller_common.tools.maybeCallbackWithError(callback, null, res);
6300
6427
  }
6301
6428
  } else {
@@ -6354,76 +6481,6 @@ class AdapterClass extends import_node_events.EventEmitter {
6354
6481
  }
6355
6482
  }
6356
6483
  }
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
6484
  /**
6428
6485
  * Subscribe for changes on all states of all adapters (and system states), that pass the pattern
6429
6486
  *
@@ -6450,136 +6507,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6450
6507
  import_validator.Validator.assertObject(options, "options");
6451
6508
  }
6452
6509
  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
- }
6510
+ const cb = callback;
6511
+ this.#subscriptions.subscribeForeignStates(pattern, options).then(() => cb?.(), (err) => cb?.(err));
6583
6512
  }
6584
6513
  /**
6585
6514
  * Unsubscribe for changes for given pattern
@@ -6612,85 +6541,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6612
6541
  if (options !== null && options !== void 0) {
6613
6542
  import_validator.Validator.assertObject(options, "options");
6614
6543
  }
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);
6544
+ const cb = callback;
6545
+ this.#subscriptions.unsubscribeForeignStates(pattern, options).then(() => cb?.(), (err) => cb?.(err));
6694
6546
  }
6695
6547
  /**
6696
6548
  * Subscribe for changes on all states of this instance, that pass the pattern
@@ -6714,11 +6566,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6714
6566
  if (options !== null && options !== void 0) {
6715
6567
  import_validator.Validator.assertObject(options, "options");
6716
6568
  }
6717
- return this._subscribeForeignStates({
6718
- pattern: Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true),
6719
- options,
6720
- callback
6721
- });
6569
+ const cb = callback;
6570
+ this.#subscriptions.subscribeForeignStates(Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true), options).then(() => cb?.(), (err) => cb?.(err));
6722
6571
  }
6723
6572
  /**
6724
6573
  * Unsubscribe for changes for given pattern for own states.
@@ -6744,11 +6593,8 @@ class AdapterClass extends import_node_events.EventEmitter {
6744
6593
  if (options !== null && options !== void 0) {
6745
6594
  import_validator.Validator.assertObject(options, "options");
6746
6595
  }
6747
- return this._unsubscribeForeignStates({
6748
- pattern: Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true),
6749
- options,
6750
- callback
6751
- });
6596
+ const cb = callback;
6597
+ this.#subscriptions.unsubscribeForeignStates(Array.isArray(pattern) ? pattern : this._utils.fixId(pattern, true), options).then(() => cb?.(), (err) => cb?.(err));
6752
6598
  }
6753
6599
  /**
6754
6600
  * Return plugin instance
@@ -6776,27 +6622,6 @@ class AdapterClass extends import_node_events.EventEmitter {
6776
6622
  import_validator.Validator.assertString(name, "name");
6777
6623
  return this.pluginHandler.getPluginConfig(name);
6778
6624
  }
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
6625
  /**
6801
6626
  * This method returns the list of license that can be used by this adapter
6802
6627
  *
@@ -6902,7 +6727,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6902
6727
  ack: true,
6903
6728
  expire: reportStatusExpirySec,
6904
6729
  from: id
6905
- });
6730
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set alive state: ${e.message}`));
6906
6731
  this.outputCount++;
6907
6732
  if (this.connected) {
6908
6733
  this.#states.setState(`${id}.connected`, {
@@ -6910,24 +6735,24 @@ class AdapterClass extends import_node_events.EventEmitter {
6910
6735
  ack: true,
6911
6736
  expire: reportStatusExpirySec,
6912
6737
  from: id
6913
- });
6738
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set connected state: ${e.message}`));
6914
6739
  this.outputCount++;
6915
6740
  }
6916
6741
  if (!this.startedInCompactMode) {
6917
6742
  (0, import_pidusage.default)(process.pid, (err, stats) => {
6918
- if (!err && this && this.#states && this.#states.setState && stats) {
6743
+ if (!err && this && this.#states && this.#states.setState && stats && !this.terminated) {
6919
6744
  this.#states.setState(`${id}.cpu`, {
6920
6745
  ack: true,
6921
6746
  from: id,
6922
6747
  val: Math.round(100 * stats.cpu) / 100,
6923
6748
  expire: reportStatusExpirySec
6924
- });
6749
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set cpu state: ${e.message}`));
6925
6750
  this.#states.setState(`${id}.cputime`, {
6926
6751
  ack: true,
6927
6752
  from: id,
6928
6753
  val: stats.ctime / 1e3,
6929
6754
  expire: reportStatusExpirySec
6930
- });
6755
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set cputime state: ${e.message}`));
6931
6756
  this.outputCount += 2;
6932
6757
  }
6933
6758
  });
@@ -6938,19 +6763,19 @@ class AdapterClass extends import_node_events.EventEmitter {
6938
6763
  ack: true,
6939
6764
  from: id,
6940
6765
  expire: reportStatusExpirySec
6941
- });
6766
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set memRss state: ${e.message}`));
6942
6767
  this.#states.setState(`${id}.memHeapTotal`, {
6943
6768
  val: parseFloat((mem.heapTotal / 1048576).toFixed(2)),
6944
6769
  ack: true,
6945
6770
  from: id,
6946
6771
  expire: reportStatusExpirySec
6947
- });
6772
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set memHeapTotal state: ${e.message}`));
6948
6773
  this.#states.setState(`${id}.memHeapUsed`, {
6949
6774
  val: parseFloat((mem.heapUsed / 1048576).toFixed(2)),
6950
6775
  ack: true,
6951
6776
  from: id,
6952
6777
  expire: reportStatusExpirySec
6953
- });
6778
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set memHeapUsed state: ${e.message}`));
6954
6779
  } catch (e) {
6955
6780
  this._logger.warn(`${this.namespaceLog} Could not query used process memory: ${e.message}`);
6956
6781
  }
@@ -6962,7 +6787,7 @@ class AdapterClass extends import_node_events.EventEmitter {
6962
6787
  ack: true,
6963
6788
  from: id,
6964
6789
  expire: reportStatusExpirySec
6965
- });
6790
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set eventLoopLag state: ${e.message}`));
6966
6791
  this.eventLoopLags = [];
6967
6792
  this.outputCount++;
6968
6793
  }
@@ -6973,19 +6798,19 @@ class AdapterClass extends import_node_events.EventEmitter {
6973
6798
  ack: true,
6974
6799
  from: id,
6975
6800
  expire: reportStatusExpirySec
6976
- });
6801
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set uptime state: ${e.message}`));
6977
6802
  this.#states.setState(`${id}.inputCount`, {
6978
6803
  val: this.inputCount,
6979
6804
  ack: true,
6980
6805
  from: id,
6981
6806
  expire: reportStatusExpirySec
6982
- });
6807
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set inputCount state: ${e.message}`));
6983
6808
  this.#states.setState(`${id}.outputCount`, {
6984
6809
  val: this.outputCount,
6985
6810
  ack: true,
6986
6811
  from: id,
6987
6812
  expire: reportStatusExpirySec
6988
- });
6813
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set outputCount state: ${e.message}`));
6989
6814
  this.inputCount = 0;
6990
6815
  this.outputCount = 0;
6991
6816
  }
@@ -7053,7 +6878,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7053
6878
  }
7054
6879
  } else if (this.#states?.pushLog) {
7055
6880
  for (const instanceId of this.logList) {
7056
- this.#states.pushLog(instanceId, info);
6881
+ this.#states.pushLog(instanceId, info).catch((e) => this._logger.error(`${this.namespaceLog} Cannot push log: ${e.message}`));
7057
6882
  }
7058
6883
  }
7059
6884
  });
@@ -7077,7 +6902,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7077
6902
  if (this.logList.size && messages?.length && this.#states) {
7078
6903
  for (const message of messages) {
7079
6904
  for (const instanceId of this.logList) {
7080
- this.#states.pushLog(instanceId, message);
6905
+ this.#states.pushLog(instanceId, message).catch((e) => this._logger.error(`${this.namespaceLog} Cannot push log: ${e.message}`));
7081
6906
  }
7082
6907
  }
7083
6908
  }
@@ -7139,7 +6964,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7139
6964
  this.emit("log", msg);
7140
6965
  }
7141
6966
  };
7142
- this.#states.subscribeLog(`system.adapter.${this.namespace}`);
6967
+ this.#states.subscribeLog(`system.adapter.${this.namespace}`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to log: ${e.message}`));
7143
6968
  } else {
7144
6969
  this.requireLog = (isActive) => {
7145
6970
  if (isActive) {
@@ -7168,7 +6993,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7168
6993
  this.#states = new this.States({
7169
6994
  namespace: this.namespaceLog,
7170
6995
  connection: this._config.states,
7171
- connected: async () => {
6996
+ connected: /* @__PURE__ */ __name(async () => {
7172
6997
  if (!this.#states) {
7173
6998
  return;
7174
6999
  }
@@ -7179,11 +7004,11 @@ class AdapterClass extends import_node_events.EventEmitter {
7179
7004
  this._initializeTimeout = null;
7180
7005
  }
7181
7006
  if (!this._config.isInstall) {
7182
- this.#states.subscribe(`system.adapter.${this.namespace}.sigKill`);
7183
- this.#states.subscribe(`system.adapter.${this.namespace}.logLevel`);
7007
+ this.#states.subscribe(`system.adapter.${this.namespace}.sigKill`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to sigKill: ${e.message}`));
7008
+ this.#states.subscribe(`system.adapter.${this.namespace}.logLevel`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to logLevel: ${e.message}`));
7184
7009
  }
7185
7010
  if (this._options.subscribable) {
7186
- this.#states.subscribe(`system.adapter.${this.namespace}.subscribes`);
7011
+ this.#states.subscribe(`system.adapter.${this.namespace}.subscribes`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to subscribes: ${e.message}`));
7187
7012
  let state;
7188
7013
  try {
7189
7014
  state = await this.#states.getStateAsync(`system.adapter.${this.namespace}.subscribes`);
@@ -7202,9 +7027,9 @@ class AdapterClass extends import_node_events.EventEmitter {
7202
7027
  return import_js_controller_common.tools.maybeCallback(cb);
7203
7028
  }
7204
7029
  return import_js_controller_common.tools.maybeCallback(cb);
7205
- },
7030
+ }, "connected"),
7206
7031
  logger: this._logger,
7207
- change: async (id, stateOrMessage) => {
7032
+ change: /* @__PURE__ */ __name(async (id, stateOrMessage) => {
7208
7033
  this.inputCount++;
7209
7034
  const state = stateOrMessage;
7210
7035
  if (!id || typeof id !== "string") {
@@ -7225,7 +7050,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7225
7050
  isScheduled: false,
7226
7051
  exitCode: import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION,
7227
7052
  updateAliveState: false
7228
- });
7053
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7229
7054
  }
7230
7055
  }
7231
7056
  }
@@ -7236,12 +7061,9 @@ class AdapterClass extends import_node_events.EventEmitter {
7236
7061
  if (state.val && state.val !== currentLevel && (0, import_tools.isLogLevel)(newLogLevel)) {
7237
7062
  this.overwriteLogLevel = true;
7238
7063
  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;
7064
+ for (const transport of this._logger.transports) {
7065
+ if (!transport._defaultConfigLoglevel) {
7066
+ transport.level = newLogLevel;
7245
7067
  }
7246
7068
  }
7247
7069
  this._logger.info(`${this.namespaceLog} Loglevel changed from "${currentLevel}" to "${state.val}"`);
@@ -7254,7 +7076,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7254
7076
  val: currentLevel,
7255
7077
  ack: true,
7256
7078
  from: `system.adapter.${this.namespace}`
7257
- });
7079
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set logLevel state: ${e.message}`));
7258
7080
  }
7259
7081
  }
7260
7082
  if (id === `system.adapter.${this.namespace}.checkLogging`) {
@@ -7286,25 +7108,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7286
7108
  } else if (id === `messagebox.system.adapter.${this.namespace}` && state) {
7287
7109
  const obj = state;
7288
7110
  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) {
7111
+ if (!this.#async.resolveReply(obj) && !this._stopInProgress) {
7308
7112
  if (obj.command === "clientSubscribe") {
7309
7113
  const res = await this.uiMessagingController.registerClientSubscribeByMessage(obj);
7310
7114
  this.sendTo(obj.from, obj.command, res, obj.callback);
@@ -7314,7 +7118,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7314
7118
  return this.uiMessagingController.removeClientSubscribeByMessage(obj);
7315
7119
  }
7316
7120
  if (this._options.message) {
7317
- this._options.message(obj);
7121
+ Promise.resolve(this._options.message(obj)).catch((e) => this._logger.error(`${this.namespaceLog} Error in message handler: ${e.message}`));
7318
7122
  }
7319
7123
  this.emit("message", obj);
7320
7124
  }
@@ -7345,36 +7149,17 @@ class AdapterClass extends import_node_events.EventEmitter {
7345
7149
  }
7346
7150
  }
7347
7151
  }
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
- }
7152
+ } else if (!this._stopInProgress && this.adapterReady && this.#alias.hasSource(id)) {
7153
+ for (const { targetId, state: aState } of this.#alias.resolveSourceChange(id, state)) {
7154
+ if (typeof this._options.stateChange === "function") {
7155
+ Promise.resolve(this._options.stateChange(targetId, aState)).catch((e) => this._logger.error(`${this.namespaceLog} Error in stateChange handler: ${e.message}`));
7156
+ } else {
7157
+ setImmediate(() => this.emit("stateChange", targetId, aState));
7373
7158
  }
7374
7159
  }
7375
7160
  }
7376
- },
7377
- changeUser: (id, state) => {
7161
+ }, "change"),
7162
+ changeUser: /* @__PURE__ */ __name((id, state) => {
7378
7163
  this.inputCount++;
7379
7164
  if (!id || typeof id !== "string") {
7380
7165
  this._logger.warn(`${this.namespaceLog} Invalid id on state change: ${JSON.stringify(id)}`);
@@ -7396,17 +7181,17 @@ class AdapterClass extends import_node_events.EventEmitter {
7396
7181
  }
7397
7182
  }
7398
7183
  }
7399
- },
7400
- disconnected: () => {
7184
+ }, "changeUser"),
7185
+ disconnected: /* @__PURE__ */ __name(() => {
7401
7186
  this.connected = false;
7402
7187
  !this.terminated && setTimeout(() => {
7403
7188
  if (this.connected) {
7404
7189
  return;
7405
7190
  }
7406
7191
  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 });
7192
+ 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
7193
  }, 5e3);
7409
- }
7194
+ }, "disconnected")
7410
7195
  });
7411
7196
  }
7412
7197
  _initObjects(cb) {
@@ -7427,7 +7212,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7427
7212
  namespace: this.namespaceLog,
7428
7213
  connection: this._config.objects,
7429
7214
  logger: this._logger,
7430
- connected: async () => {
7215
+ connected: /* @__PURE__ */ __name(async () => {
7431
7216
  this.connected = true;
7432
7217
  if (this._initializeTimeout) {
7433
7218
  clearTimeout(this._initializeTimeout);
@@ -7457,25 +7242,31 @@ class AdapterClass extends import_node_events.EventEmitter {
7457
7242
  } else {
7458
7243
  return import_js_controller_common.tools.maybeCallback(cb);
7459
7244
  }
7460
- },
7461
- disconnected: () => {
7245
+ }, "connected"),
7246
+ disconnected: /* @__PURE__ */ __name(() => {
7462
7247
  this.connected = false;
7463
7248
  !this.terminated && setTimeout(() => {
7464
7249
  if (this.connected) {
7465
7250
  return;
7466
7251
  }
7467
7252
  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 });
7253
+ 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
7254
  }, 4e3);
7470
- },
7471
- change: async (id, obj) => {
7255
+ }, "disconnected"),
7256
+ change: /* @__PURE__ */ __name(async (id, obj) => {
7472
7257
  if (!id) {
7473
7258
  this._logger.error(`${this.namespaceLog} change ID is empty: ${JSON.stringify(obj)}`);
7474
7259
  return;
7475
7260
  }
7476
7261
  if (id === `system.adapter.${this.namespace}` && obj?.common?.enabled === false) {
7477
7262
  this._logger.info(`${this.namespaceLog} Adapter is disabled => stop`);
7478
- this._stop();
7263
+ this._stop().catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7264
+ return;
7265
+ }
7266
+ if (id === import_CertificateManager.CERTIFICATES_OBJECT_ID) {
7267
+ if (this.#async.hasRelevantCertificateChange(obj)) {
7268
+ this.#scheduleCertificateRestart("Changed certificate detected");
7269
+ }
7479
7270
  return;
7480
7271
  }
7481
7272
  if (id === "system.config" && obj?.common && (this._options.useFormatDate || this.defaultHistory !== void 0)) {
@@ -7487,57 +7278,15 @@ class AdapterClass extends import_node_events.EventEmitter {
7487
7278
  this.defaultHistory = obj.common.defaultHistory;
7488
7279
  }
7489
7280
  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
- }
7281
+ await this.#alias.handleAliasObjectChange(id, obj);
7528
7282
  }
7529
7283
  if (id.startsWith("system.adapter.")) {
7530
7284
  if (obj?.common?.subscribable) {
7531
7285
  const _id = id.substring(15);
7532
7286
  if (obj.common.enabled) {
7533
- if (!this.autoSubscribe.includes(_id)) {
7534
- this.autoSubscribe.push(_id);
7535
- }
7287
+ this.#subscriptions.addSubscribableInstance(_id);
7536
7288
  } else {
7537
- const pos = this.autoSubscribe.indexOf(_id);
7538
- if (pos !== -1) {
7539
- this.autoSubscribe.splice(pos, 1);
7540
- }
7289
+ this.#subscriptions.removeSubscribableInstance(_id);
7541
7290
  }
7542
7291
  }
7543
7292
  }
@@ -7553,8 +7302,8 @@ class AdapterClass extends import_node_events.EventEmitter {
7553
7302
  this.enums[id] = obj;
7554
7303
  }
7555
7304
  }
7556
- },
7557
- changeUser: (id, obj) => {
7305
+ }, "change"),
7306
+ changeUser: /* @__PURE__ */ __name((id, obj) => {
7558
7307
  if (!id) {
7559
7308
  this._logger.error(`${this.namespaceLog} change ID is empty: ${JSON.stringify(obj)}`);
7560
7309
  return;
@@ -7578,8 +7327,8 @@ class AdapterClass extends import_node_events.EventEmitter {
7578
7327
  setImmediate(() => this.emit("objectChange", id, obj));
7579
7328
  }
7580
7329
  }
7581
- },
7582
- changeFileUser: (id, fileName, size) => {
7330
+ }, "changeUser"),
7331
+ changeFileUser: /* @__PURE__ */ __name((id, fileName, size) => {
7583
7332
  if (!id) {
7584
7333
  this._logger.error(`${this.namespaceLog} change file name is empty`);
7585
7334
  return;
@@ -7588,7 +7337,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7588
7337
  typeof this._options.fileChange === "function" && setImmediate(() => this._options.fileChange(id, fileName, size));
7589
7338
  setImmediate(() => this.emit("fileChange", id, fileName, size));
7590
7339
  }
7591
- }
7340
+ }, "changeFileUser")
7592
7341
  });
7593
7342
  }
7594
7343
  /**
@@ -7645,7 +7394,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7645
7394
  if (!this.#states || !this.#objects || this.terminated) {
7646
7395
  return;
7647
7396
  }
7648
- this.#states.subscribe(`system.adapter.${this.namespace}.plugins.*`);
7397
+ this.#states.subscribe(`system.adapter.${this.namespace}.plugins.*`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to plugins: ${e.message}`));
7649
7398
  if (this._options.instance === void 0) {
7650
7399
  if (!adapterConfig || !("common" in adapterConfig) || !adapterConfig.common.enabled) {
7651
7400
  if (adapterConfig && "common" in adapterConfig && adapterConfig.common.enabled !== void 0) {
@@ -7721,13 +7470,12 @@ class AdapterClass extends import_node_events.EventEmitter {
7721
7470
  } else {
7722
7471
  this.stop = (params) => this._stop({ ...params, isPause: false });
7723
7472
  }
7724
- this.#states.subscribe(`${import_constants2.SYSTEM_ADAPTER_PREFIX}*.logging`);
7473
+ this.#states.subscribe(`${import_constants2.SYSTEM_ADAPTER_PREFIX}*.logging`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to logging: ${e.message}`));
7725
7474
  if (typeof this._options.message === "function" && // @ts-expect-error, we should infer correctly that this is an InstanceObject in this case
7726
7475
  !(0, import_utils.isMessageboxSupported)(adapterConfig.common)) {
7727
7476
  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
7477
  } else if ((0, import_utils.isMessageboxSupported)(adapterConfig.common)) {
7729
- this.mboxSubscribed = true;
7730
- this.#states.subscribeMessage(`system.adapter.${this.namespace}`);
7478
+ this.#states.subscribeMessage(`system.adapter.${this.namespace}`).catch((e) => this._logger.error(`${this.namespaceLog} Cannot subscribe to messages: ${e.message}`));
7731
7479
  }
7732
7480
  } else {
7733
7481
  this.name = adapterConfig.name || this.name;
@@ -7739,19 +7487,22 @@ class AdapterClass extends import_node_events.EventEmitter {
7739
7487
  this.host = this.common?.host || import_js_controller_common.tools.getHostName();
7740
7488
  }
7741
7489
  this.adapterConfig = adapterConfig;
7742
- this._utils = new import_validator.Validator(this.#objects, this.#states, this.namespaceLog, this._logger, this.namespace, this._namespaceRegExp);
7490
+ this._utils = new import_validator.Validator(this.#objects, this.namespaceLog, this._logger, this.namespace, this._namespaceRegExp);
7743
7491
  this.log = new import_log.Log(this.namespaceLog, this._config.log.level, this._logger);
7744
7492
  await this._createInstancesObjects(adapterConfig);
7745
7493
  if (this._options.objects) {
7746
7494
  this.oObjects = await this.getAdapterObjectsAsync();
7747
7495
  await this.subscribeObjectsAsync("*");
7748
7496
  }
7749
- await this.getSystemSecret();
7750
- const promises = [];
7497
+ const secret = await this.getSystemSecret();
7751
7498
  if (Array.isArray(adapterConfig.encryptedNative)) {
7499
+ this._decryptedNativeAttributes = new Array();
7752
7500
  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}`)));
7501
+ try {
7502
+ (0, import_utils.decryptArray)({ obj: this.config, secret, keys: [attr] });
7503
+ this._decryptedNativeAttributes.push(attr);
7504
+ } catch (e) {
7505
+ this._logger.error(`${this.namespaceLog} Can not decrypt attribute ${attr}: ${e.message}`);
7755
7506
  }
7756
7507
  }
7757
7508
  } else {
@@ -7760,7 +7511,6 @@ class AdapterClass extends import_node_events.EventEmitter {
7760
7511
  this.SUPPORTED_FEATURES.splice(idx, 1);
7761
7512
  }
7762
7513
  }
7763
- await Promise.all(promises);
7764
7514
  if (!this.#states) {
7765
7515
  return;
7766
7516
  }
@@ -7769,7 +7519,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7769
7519
  val: this._config.log.level,
7770
7520
  ack: true,
7771
7521
  from: `system.adapter.${this.namespace}`
7772
- });
7522
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set logLevel state: ${e.message}`));
7773
7523
  try {
7774
7524
  await this.#checkObjectsWarnLimit();
7775
7525
  } catch (e) {
@@ -7792,15 +7542,18 @@ class AdapterClass extends import_node_events.EventEmitter {
7792
7542
  ack: true,
7793
7543
  from: id,
7794
7544
  val: !!this.startedInCompactMode
7795
- });
7545
+ }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot set compactMode state: ${e.message}`));
7796
7546
  this.outputCount++;
7797
7547
  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 });
7548
+ const onErr = /* @__PURE__ */ __name((e) => {
7549
+ this._logger.error(`${this.namespaceLog} Cannot reset compact metric: ${e.message}`);
7550
+ }, "onErr");
7551
+ this.#states.setState(`${id}.cpu`, { ack: true, from: id, val: 0 }).catch(onErr);
7552
+ this.#states.setState(`${id}.cputime`, { ack: true, from: id, val: 0 }).catch(onErr);
7553
+ this.#states.setState(`${id}.memRss`, { val: 0, ack: true, from: id }).catch(onErr);
7554
+ this.#states.setState(`${id}.memHeapTotal`, { val: 0, ack: true, from: id }).catch(onErr);
7555
+ this.#states.setState(`${id}.memHeapUsed`, { val: 0, ack: true, from: id }).catch(onErr);
7556
+ this.#states.setState(`${id}.eventLoopLag`, { val: 0, ack: true, from: id }).catch(onErr);
7804
7557
  this.outputCount += 6;
7805
7558
  } else {
7806
7559
  import_js_controller_common.tools.measureEventLoopLag(1e3, (lag) => {
@@ -7821,7 +7574,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7821
7574
  this._logger.debug(`${this.namespaceLog} Schedule restart: ${adapterConfig.common.restartSchedule}`);
7822
7575
  this._restartScheduleJob = this._schedule.scheduleJob(adapterConfig.common.restartSchedule, () => {
7823
7576
  this._logger.info(`${this.namespaceLog} Scheduled restart.`);
7824
- this._stop({ isPause: false, isScheduled: true });
7577
+ this._stop({ isPause: false, isScheduled: true }).catch((e) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${e.message}`));
7825
7578
  });
7826
7579
  }
7827
7580
  }
@@ -7849,12 +7602,12 @@ class AdapterClass extends import_node_events.EventEmitter {
7849
7602
  _callReadyHandler() {
7850
7603
  if (this._config.isInstall && (typeof this._options.install === "function" || this.listeners("install").length)) {
7851
7604
  if (typeof this._options.install === "function") {
7852
- this._options.install();
7605
+ Promise.resolve(this._options.install()).catch((e) => this._logger.error(`${this.namespaceLog} Error in install handler: ${e.message}`));
7853
7606
  }
7854
7607
  this.emit("install");
7855
7608
  } else {
7856
7609
  if (typeof this._options.ready === "function") {
7857
- this._options.ready();
7610
+ Promise.resolve(this._options.ready()).catch((e) => this._logger.error(`${this.namespaceLog} Error in ready handler: ${e.message}`));
7858
7611
  }
7859
7612
  this.emit("ready");
7860
7613
  }
@@ -7900,7 +7653,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7900
7653
  isScheduled: false,
7901
7654
  exitCode: import_js_controller_common.EXIT_CODES.UNCAUGHT_EXCEPTION,
7902
7655
  updateAliveState: false
7903
- });
7656
+ }).catch((err2) => this._logger.error(`${this.namespaceLog} Cannot stop adapter: ${err2.message}`));
7904
7657
  } catch (e) {
7905
7658
  this._logger.error(`${this.namespaceLog} exception by stop: ${e ? e.message : e}`);
7906
7659
  }
@@ -7973,7 +7726,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7973
7726
  });
7974
7727
  }
7975
7728
  return new Promise((resolve) => {
7976
- this._extendObjects(objs, resolve);
7729
+ return this._extendObjects(objs, resolve);
7977
7730
  });
7978
7731
  }
7979
7732
  /**
@@ -8023,7 +7776,7 @@ class AdapterClass extends import_node_events.EventEmitter {
8023
7776
  return this.#states.setState(id, state);
8024
7777
  }
8025
7778
  async _extendObjects(tasks, callback) {
8026
- if (!tasks || !tasks.length) {
7779
+ if (!tasks?.length) {
8027
7780
  return import_js_controller_common.tools.maybeCallback(callback);
8028
7781
  }
8029
7782
  const task = tasks.shift();
@@ -8130,7 +7883,7 @@ class AdapterClass extends import_node_events.EventEmitter {
8130
7883
  * Initializes the adapter
8131
7884
  */
8132
7885
  async _init() {
8133
- const _initDBs = () => {
7886
+ const _initDBs = /* @__PURE__ */ __name(() => {
8134
7887
  this._initObjects(() => {
8135
7888
  if (this.inited) {
8136
7889
  this._logger.warn(`${this.namespaceLog} Reconnection to DB.`);
@@ -8139,7 +7892,7 @@ class AdapterClass extends import_node_events.EventEmitter {
8139
7892
  this.inited = true;
8140
7893
  this._initStates(() => this._prepareInitAdapter());
8141
7894
  });
8142
- };
7895
+ }, "_initDBs");
8143
7896
  if (import_fs_extra.default.existsSync(`${this.adapterDir}/package.json`)) {
8144
7897
  this.pack = import_fs_extra.default.readJSONSync(`${this.adapterDir}/package.json`);
8145
7898
  } else {