@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
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/lib/adapter/managers/MessagingManager.ts"],
4
+ "sourcesContent": ["import type { Client as StatesInRedisClient } from '@iobroker/db-states-redis';\nimport type {\n InternalSendToHostOptions,\n InternalSendToOptions,\n NotificationOptions,\n SendToOptions,\n SendToUserInterfaceClientOptions,\n} from '../../_Types.js';\nimport type { AdapterContext } from '@/lib/adapter/context.js';\nimport { AdapterContextBase } from '@/lib/adapter/managers/AdapterContextBase.js';\nimport { isMessageboxSupported } from '@/lib/adapter/utils.js';\n\n/** Entry in the pending-reply registry for sendTo calls with expectReply=true */\ninterface PendingReply {\n resolve: (msg: any) => void;\n reject: (e: Error) => void;\n timer?: NodeJS.Timeout;\n time: number;\n}\n\n/** Owns the adapter's outbound messaging and the pending-reply registry. */\nexport class MessagingManager extends AdapterContextBase {\n readonly #pending = new Map<number, PendingReply>();\n #callbackId = 1;\n #mboxSubscribed = false;\n\n /**\n * @param ctx Shared adapter context providing live runtime state\n */\n constructor(ctx: AdapterContext) {\n super(ctx);\n }\n\n /**\n * Sends a message to another adapter instance.\n *\n * When `opts.expectReply` is true and the target is a specific instance (not broadcast),\n * the returned promise resolves with the reply message when it arrives, or rejects with\n * `Error('Timeout exceeded')` if `opts.options.timeout` elapses.\n *\n * @param opts Normalized send options\n */\n async sendTo(opts: InternalSendToOptions): Promise<any> {\n const { command, message, callback, options, expectReply } = opts;\n let { instanceName } = opts;\n\n if (!instanceName) {\n throw new Error('No instanceName provided or not a string');\n }\n\n if (!instanceName.startsWith('system.adapter.')) {\n instanceName = `system.adapter.${instanceName}`;\n }\n\n const obj: ioBroker.SendableMessage = {\n command,\n message,\n from: `system.adapter.${this.namespace}`,\n };\n\n const states = this.states;\n\n if (typeof message !== 'object') {\n this.logger.silly(\n `${this.namespaceLog} sendTo \"${command}\" to ${instanceName} from system.adapter.${this.namespace}: ${message}`,\n );\n } else {\n this.logger.silly(\n `${this.namespaceLog} sendTo \"${command}\" to ${instanceName} from system.adapter.${this.namespace}`,\n );\n }\n\n if (!instanceName.match(/\\.[0-9]+$/)) {\n const objects = this.objects;\n\n // Only the instance lookup is best-effort; per-instance push errors must surface.\n const res = await objects\n .getObjectView('system', 'instance', {\n startkey: `${instanceName}.`,\n endkey: `${instanceName}.\\u9999`,\n })\n .catch(() => undefined);\n\n if (res) {\n for (const row of res.rows) {\n await states.pushMessage(row.id, obj);\n }\n }\n return;\n }\n\n if (expectReply) {\n return this.#registerReply(states, instanceName, obj, options);\n }\n\n if (callback) {\n obj.callback = { ...callback, ack: true };\n }\n\n await states.pushMessage(instanceName, obj);\n }\n\n /**\n * Subscribes to this instance's messagebox on demand when the adapter does not advertise\n * messagebox support, so replies to outbound messages are received. Idempotent.\n *\n * @param states the connected states DB client\n */\n #maybeSubscribe(states: StatesInRedisClient): void {\n const common = this.common;\n if (common && !isMessageboxSupported(common) && !this.#mboxSubscribed) {\n this.#mboxSubscribed = true;\n states\n .subscribeMessage(`system.adapter.${this.namespace}`)\n .catch(e => this.logger.error(`${this.namespaceLog} Cannot subscribe to messages: ${e.message}`));\n }\n }\n\n /**\n * Sets a reply callback header on `obj`, registers a pending-reply resolver keyed by its id,\n * subscribes the messagebox on demand, pushes the message and returns a promise that resolves\n * with the reply once `resolveCallback` is invoked for the matching id, or rejects with\n * `Error('Timeout exceeded')` when `options.timeout` elapses.\n *\n * @param states the connected states DB client\n * @param target the recipient id (instance or host) for `pushMessage`\n * @param obj the message to send; its `callback` header is set here\n * @param options additional send options (e.g. timeout)\n */\n async #registerReply(\n states: StatesInRedisClient,\n target: string,\n obj: ioBroker.SendableMessage,\n options?: SendToOptions,\n ): Promise<any> {\n this.#maybeSubscribe(states);\n\n const id = this.#callbackId++;\n if (this.#callbackId >= 0xffffffff) {\n this.#callbackId = 1;\n }\n\n obj.callback = {\n message: obj.message,\n id,\n ack: false,\n time: Date.now(),\n };\n\n let pendingEntry!: PendingReply;\n const replyPromise = new Promise<any>((resolve, reject) => {\n let timer: NodeJS.Timeout | undefined;\n if (options?.timeout) {\n timer = setTimeout(() => {\n if (this.#pending.has(id)) {\n this.#pending.delete(id);\n reject(new Error('Timeout exceeded'));\n }\n }, options.timeout);\n }\n\n pendingEntry = { resolve, reject, timer, time: Date.now() };\n this.#pending.set(id, pendingEntry);\n });\n\n const now = Date.now();\n for (const [_id, entry] of this.#pending) {\n if (now - entry.time > 3_600_000) {\n this.#pending.delete(_id);\n }\n }\n\n try {\n await states.pushMessage(target, obj);\n } catch (e) {\n if (pendingEntry.timer) {\n clearTimeout(pendingEntry.timer);\n }\n this.#pending.delete(id);\n throw e;\n }\n return replyPromise;\n }\n\n /**\n * Sends a message to a host, or broadcasts to all hosts when `hostName` is `null`.\n *\n * When `opts.expectReply` is true and a specific host is targeted, the returned promise\n * resolves with the reply message when it arrives, or rejects with `Error('Timeout exceeded')`\n * if `opts.options.timeout` elapses. Broadcasts (hostName === null) resolve void.\n *\n * @param opts Normalized send options\n */\n async sendToHost(opts: InternalSendToHostOptions): Promise<any> {\n const { command, message, expectReply, options, callback } = opts;\n let { hostName } = opts;\n const obj: ioBroker.SendableMessage = {\n command,\n message,\n from: `system.adapter.${this.namespace}`,\n };\n\n const states = this.states;\n\n if (hostName && !hostName.startsWith('system.host.')) {\n hostName = `system.host.${hostName}`;\n }\n\n if (!hostName) {\n const objects = this.objects;\n\n const res = await objects.getObjectList({ startkey: 'system.host.', endkey: 'system.host.\\u9999' });\n\n if (res?.rows.length) {\n for (const row of res.rows) {\n const parts: string[] = row.id.split('.');\n // ignore system.host.name.alive and so on\n if (parts.length === 3) {\n await states.pushMessage(row.id, obj);\n }\n }\n }\n return;\n }\n\n if (expectReply) {\n return this.#registerReply(states, hostName, obj, options);\n }\n\n if (callback) {\n obj.callback = { ...callback, ack: true };\n }\n\n await states.pushMessage(hostName, obj);\n }\n\n /**\n * Resolves a pending reply promise for an acked messagebox message.\n * Returns true if a pending entry was found and consumed.\n *\n * @param obj incoming message object from the messagebox\n */\n resolveCallback(obj: ioBroker.Message): boolean {\n if (!obj.callback?.ack || !obj.callback.id) {\n return false;\n }\n\n const entry = this.#pending.get(obj.callback.id);\n if (!entry) {\n return false;\n }\n\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n this.#pending.delete(obj.callback.id);\n entry.resolve(obj.message);\n\n const now = Date.now();\n for (const [id, pending] of this.#pending) {\n if (now - pending.time > 3_600_000) {\n this.#pending.delete(id);\n }\n }\n\n return true;\n }\n\n /**\n * Rejects all pending reply promises and clears their timers (used on stop).\n */\n clearPendingCallbacks(): void {\n if (this.#pending.size) {\n const err = new Error('Adapter stopped');\n for (const entry of this.#pending.values()) {\n if (entry.timer) {\n clearTimeout(entry.timer);\n }\n entry.reject(err);\n }\n this.#pending.clear();\n }\n }\n\n /**\n * Sends a message to a single UI client, or broadcasts to all connected UI clients when `clientId` is omitted.\n *\n * @param options clientId and data options\n */\n sendToUI(options: SendToUserInterfaceClientOptions): Promise<void> {\n const states = this.states;\n\n const { clientId, data } = options;\n\n if (clientId === undefined) {\n return this.uiMessagingController.sendToAllClients({\n data,\n states,\n });\n }\n\n return this.uiMessagingController.sendToClient({\n clientId,\n data,\n states,\n });\n }\n\n /**\n * Sends an addNotification command to the host of this adapter instance.\n *\n * @param scope notification scope\n * @param category notification category, or `null` to match by scope regex\n * @param message notification message\n * @param options additional notification options\n */\n async registerNotification(\n scope: string,\n category: string | null,\n message: string,\n options?: NotificationOptions,\n ): Promise<void> {\n const states = this.states;\n\n const obj = {\n command: 'addNotification',\n message: {\n scope,\n category,\n message,\n instance: this.namespace,\n contextData: options?.contextData,\n },\n from: `system.adapter.${this.namespace}`,\n };\n\n await states.pushMessage(`system.host.${this.host}`, obj);\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AASA;;;;;AAAA,gCAAmC;AACnC,mBAAsC;AAWhC,MAAO,yBAAyB,6CAAkB;EAZxD,OAYwD;;;EAC3C,WAAW,oBAAI,IAAG;EAC3B,cAAc;EACd,kBAAkB;;;;EAKlB,YAAY,KAAmB;AAC3B,UAAM,GAAG;EACb;;;;;;;;;;EAWA,MAAM,OAAO,MAA2B;AACpC,UAAM,EAAE,SAAS,SAAS,UAAU,SAAS,YAAW,IAAK;AAC7D,QAAI,EAAE,aAAY,IAAK;AAEvB,QAAI,CAAC,cAAc;AACf,YAAM,IAAI,MAAM,0CAA0C;IAC9D;AAEA,QAAI,CAAC,aAAa,WAAW,iBAAiB,GAAG;AAC7C,qBAAe,kBAAkB,YAAY;IACjD;AAEA,UAAM,MAAgC;MAClC;MACA;MACA,MAAM,kBAAkB,KAAK,SAAS;;AAG1C,UAAM,SAAS,KAAK;AAEpB,QAAI,OAAO,YAAY,UAAU;AAC7B,WAAK,OAAO,MACR,GAAG,KAAK,YAAY,YAAY,OAAO,QAAQ,YAAY,wBAAwB,KAAK,SAAS,KAAK,OAAO,EAAE;IAEvH,OAAO;AACH,WAAK,OAAO,MACR,GAAG,KAAK,YAAY,YAAY,OAAO,QAAQ,YAAY,wBAAwB,KAAK,SAAS,EAAE;IAE3G;AAEA,QAAI,CAAC,aAAa,MAAM,WAAW,GAAG;AAClC,YAAM,UAAU,KAAK;AAGrB,YAAM,MAAM,MAAM,QACb,cAAc,UAAU,YAAY;QACjC,UAAU,GAAG,YAAY;QACzB,QAAQ,GAAG,YAAY;OAC1B,EACA,MAAM,MAAM,MAAS;AAE1B,UAAI,KAAK;AACL,mBAAW,OAAO,IAAI,MAAM;AACxB,gBAAM,OAAO,YAAY,IAAI,IAAI,GAAG;QACxC;MACJ;AACA;IACJ;AAEA,QAAI,aAAa;AACb,aAAO,KAAK,eAAe,QAAQ,cAAc,KAAK,OAAO;IACjE;AAEA,QAAI,UAAU;AACV,UAAI,WAAW,EAAE,GAAG,UAAU,KAAK,KAAI;IAC3C;AAEA,UAAM,OAAO,YAAY,cAAc,GAAG;EAC9C;;;;;;;EAQA,gBAAgB,QAA2B;AACvC,UAAM,SAAS,KAAK;AACpB,QAAI,UAAU,KAAC,oCAAsB,MAAM,KAAK,CAAC,KAAK,iBAAiB;AACnE,WAAK,kBAAkB;AACvB,aACK,iBAAiB,kBAAkB,KAAK,SAAS,EAAE,EACnD,MAAM,OAAK,KAAK,OAAO,MAAM,GAAG,KAAK,YAAY,kCAAkC,EAAE,OAAO,EAAE,CAAC;IACxG;EACJ;;;;;;;;;;;;EAaA,MAAM,eACF,QACA,QACA,KACA,SAAuB;AAEvB,SAAK,gBAAgB,MAAM;AAE3B,UAAM,KAAK,KAAK;AAChB,QAAI,KAAK,eAAe,YAAY;AAChC,WAAK,cAAc;IACvB;AAEA,QAAI,WAAW;MACX,SAAS,IAAI;MACb;MACA,KAAK;MACL,MAAM,KAAK,IAAG;;AAGlB,QAAI;AACJ,UAAM,eAAe,IAAI,QAAa,CAAC,SAAS,WAAU;AACtD,UAAI;AACJ,UAAI,SAAS,SAAS;AAClB,gBAAQ,WAAW,MAAK;AACpB,cAAI,KAAK,SAAS,IAAI,EAAE,GAAG;AACvB,iBAAK,SAAS,OAAO,EAAE;AACvB,mBAAO,IAAI,MAAM,kBAAkB,CAAC;UACxC;QACJ,GAAG,QAAQ,OAAO;MACtB;AAEA,qBAAe,EAAE,SAAS,QAAQ,OAAO,MAAM,KAAK,IAAG,EAAE;AACzD,WAAK,SAAS,IAAI,IAAI,YAAY;IACtC,CAAC;AAED,UAAM,MAAM,KAAK,IAAG;AACpB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,UAAU;AACtC,UAAI,MAAM,MAAM,OAAO,MAAW;AAC9B,aAAK,SAAS,OAAO,GAAG;MAC5B;IACJ;AAEA,QAAI;AACA,YAAM,OAAO,YAAY,QAAQ,GAAG;IACxC,SAAS,GAAG;AACR,UAAI,aAAa,OAAO;AACpB,qBAAa,aAAa,KAAK;MACnC;AACA,WAAK,SAAS,OAAO,EAAE;AACvB,YAAM;IACV;AACA,WAAO;EACX;;;;;;;;;;EAWA,MAAM,WAAW,MAA+B;AAC5C,UAAM,EAAE,SAAS,SAAS,aAAa,SAAS,SAAQ,IAAK;AAC7D,QAAI,EAAE,SAAQ,IAAK;AACnB,UAAM,MAAgC;MAClC;MACA;MACA,MAAM,kBAAkB,KAAK,SAAS;;AAG1C,UAAM,SAAS,KAAK;AAEpB,QAAI,YAAY,CAAC,SAAS,WAAW,cAAc,GAAG;AAClD,iBAAW,eAAe,QAAQ;IACtC;AAEA,QAAI,CAAC,UAAU;AACX,YAAM,UAAU,KAAK;AAErB,YAAM,MAAM,MAAM,QAAQ,cAAc,EAAE,UAAU,gBAAgB,QAAQ,qBAAoB,CAAE;AAElG,UAAI,KAAK,KAAK,QAAQ;AAClB,mBAAW,OAAO,IAAI,MAAM;AACxB,gBAAM,QAAkB,IAAI,GAAG,MAAM,GAAG;AAExC,cAAI,MAAM,WAAW,GAAG;AACpB,kBAAM,OAAO,YAAY,IAAI,IAAI,GAAG;UACxC;QACJ;MACJ;AACA;IACJ;AAEA,QAAI,aAAa;AACb,aAAO,KAAK,eAAe,QAAQ,UAAU,KAAK,OAAO;IAC7D;AAEA,QAAI,UAAU;AACV,UAAI,WAAW,EAAE,GAAG,UAAU,KAAK,KAAI;IAC3C;AAEA,UAAM,OAAO,YAAY,UAAU,GAAG;EAC1C;;;;;;;EAQA,gBAAgB,KAAqB;AACjC,QAAI,CAAC,IAAI,UAAU,OAAO,CAAC,IAAI,SAAS,IAAI;AACxC,aAAO;IACX;AAEA,UAAM,QAAQ,KAAK,SAAS,IAAI,IAAI,SAAS,EAAE;AAC/C,QAAI,CAAC,OAAO;AACR,aAAO;IACX;AAEA,QAAI,MAAM,OAAO;AACb,mBAAa,MAAM,KAAK;IAC5B;AACA,SAAK,SAAS,OAAO,IAAI,SAAS,EAAE;AACpC,UAAM,QAAQ,IAAI,OAAO;AAEzB,UAAM,MAAM,KAAK,IAAG;AACpB,eAAW,CAAC,IAAI,OAAO,KAAK,KAAK,UAAU;AACvC,UAAI,MAAM,QAAQ,OAAO,MAAW;AAChC,aAAK,SAAS,OAAO,EAAE;MAC3B;IACJ;AAEA,WAAO;EACX;;;;EAKA,wBAAqB;AACjB,QAAI,KAAK,SAAS,MAAM;AACpB,YAAM,MAAM,IAAI,MAAM,iBAAiB;AACvC,iBAAW,SAAS,KAAK,SAAS,OAAM,GAAI;AACxC,YAAI,MAAM,OAAO;AACb,uBAAa,MAAM,KAAK;QAC5B;AACA,cAAM,OAAO,GAAG;MACpB;AACA,WAAK,SAAS,MAAK;IACvB;EACJ;;;;;;EAOA,SAAS,SAAyC;AAC9C,UAAM,SAAS,KAAK;AAEpB,UAAM,EAAE,UAAU,KAAI,IAAK;AAE3B,QAAI,aAAa,QAAW;AACxB,aAAO,KAAK,sBAAsB,iBAAiB;QAC/C;QACA;OACH;IACL;AAEA,WAAO,KAAK,sBAAsB,aAAa;MAC3C;MACA;MACA;KACH;EACL;;;;;;;;;EAUA,MAAM,qBACF,OACA,UACA,SACA,SAA6B;AAE7B,UAAM,SAAS,KAAK;AAEpB,UAAM,MAAM;MACR,SAAS;MACT,SAAS;QACL;QACA;QACA;QACA,UAAU,KAAK;QACf,aAAa,SAAS;;MAE1B,MAAM,kBAAkB,KAAK,SAAS;;AAG1C,UAAM,OAAO,YAAY,eAAe,KAAK,IAAI,IAAI,GAAG;EAC5D;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,69 @@
1
+ import type { AdapterContext } from '../../../lib/adapter/context.js';
2
+ import { AdapterContextBase } from '../../../lib/adapter/managers/AdapterContextBase.js';
3
+ import type { MessagingManager } from '../../../lib/adapter/managers/MessagingManager.js';
4
+ /**
5
+ * Owns the adapter's exclusive-resource registry. Register/free requests are forwarded to the host
6
+ * this instance runs on, which keeps `system.host.<hostname>.usedResources.<type>` up to date; reads
7
+ * go straight to those states.
8
+ */
9
+ export declare class ResourceManager extends AdapterContextBase {
10
+ #private;
11
+ /**
12
+ * @param ctx Shared adapter context providing live runtime state
13
+ * @param getMessaging Returns the adapter's messaging manager. Passed as a getter rather than an
14
+ * instance because it is created lazily - and it has to be *the* one, since it owns the map
15
+ * the host's reply is matched against.
16
+ */
17
+ constructor(ctx: AdapterContext, getMessaging: () => MessagingManager);
18
+ /**
19
+ * Registers an exclusive resource as used by this instance by forwarding it to the host.
20
+ *
21
+ * Registering is additive - one call per occupied resource, in any order. The host drops what this
22
+ * instance registered before when it starts, so there is nothing to reset by hand.
23
+ *
24
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
25
+ * @param data payload describing the resource
26
+ * @throws {Error} when the host refuses the registration or does not answer
27
+ */
28
+ registerUsedResource<T extends ioBroker.UsedResourceType>(type: T, data: ioBroker.UsedResourceData<T>): Promise<void>;
29
+ /**
30
+ * Asks the host whether another instance currently holds a resource, without registering anything.
31
+ *
32
+ * Meant to be called *before* the port or the device is opened: afterwards the operating system
33
+ * has already decided the conflict, and all this can add is a better error message.
34
+ *
35
+ * The answer is a hint, not a permission. The registry only knows what adapters declare, so an
36
+ * empty list does not promise the resource is free - something outside ioBroker may hold it.
37
+ *
38
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
39
+ * @param data description of the resource that is about to be used
40
+ * @returns the entries of other instances that currently hold it, newest first
41
+ * @throws {Error} when the host refuses the request or does not answer
42
+ */
43
+ checkUsedResource<T extends ioBroker.UsedResourceType>(type: T, data?: Partial<ioBroker.UsedResourceData<T>>): Promise<ioBroker.RegisteredResource[]>;
44
+ /**
45
+ * Frees all exclusive resources this instance registered, across all types, by forwarding it to the host.
46
+ *
47
+ * @throws {Error} when the host refuses the command or does not answer
48
+ */
49
+ clearUsedResources(): Promise<void>;
50
+ /**
51
+ * Frees previously registered exclusive resources of this instance by forwarding it to the host.
52
+ *
53
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
54
+ * @param data fields identifying the resources to free; if omitted, all resources of `type` are freed
55
+ * @throws {Error} when the host refuses the command or does not answer
56
+ */
57
+ freeUsedResource<T extends ioBroker.UsedResourceType>(type: T, data?: Partial<ioBroker.UsedResourceData<T>>): Promise<void>;
58
+ /**
59
+ * Reads the exclusive resources of the given type currently registered on this instance's host, across
60
+ * all its instances.
61
+ *
62
+ * @param type resource type to read, e.g. "serialPort"
63
+ * @throws {Error} when the host of this instance is unknown
64
+ */
65
+ getHostUsedResources<T extends ioBroker.UsedResourceType>(type: T): Promise<ioBroker.RegisteredResource<T>[]>;
66
+ /** Reads the exclusive resources of every type currently registered on this instance's host. */
67
+ getHostUsedResources(): Promise<ioBroker.RegisteredResource[]>;
68
+ }
69
+ //# sourceMappingURL=ResourceManager.d.ts.map
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var ResourceManager_exports = {};
21
+ __export(ResourceManager_exports, {
22
+ ResourceManager: () => ResourceManager
23
+ });
24
+ module.exports = __toCommonJS(ResourceManager_exports);
25
+ var import_tools = require("@iobroker/js-controller-common-db/tools");
26
+ var import_AdapterContextBase = require("../../../lib/adapter/managers/AdapterContextBase.js");
27
+ const USED_RESOURCES_ID = "usedResources";
28
+ const HOST_REPLY_TIMEOUT = 5e3;
29
+ class ResourceManager extends import_AdapterContextBase.AdapterContextBase {
30
+ static {
31
+ __name(this, "ResourceManager");
32
+ }
33
+ #getMessaging;
34
+ /**
35
+ * @param ctx Shared adapter context providing live runtime state
36
+ * @param getMessaging Returns the adapter's messaging manager. Passed as a getter rather than an
37
+ * instance because it is created lazily - and it has to be *the* one, since it owns the map
38
+ * the host's reply is matched against.
39
+ */
40
+ constructor(ctx, getMessaging) {
41
+ super(ctx);
42
+ this.#getMessaging = getMessaging;
43
+ }
44
+ /**
45
+ * Send a mutating command to the host this instance runs on and wait for its verdict.
46
+ *
47
+ * The host validates every one of these - resource type, payload shape, the sending instance and
48
+ * whether it declares its resources at all - and answers with `{ error }` when it refuses. Without
49
+ * waiting for that answer the adapter would get a resolved promise for a call that did nothing,
50
+ * and the only trace would be a warning in a log the adapter developer does not read.
51
+ *
52
+ * @param command the host command, e.g. "registerUsedResource"
53
+ * @param message the command payload
54
+ * @returns the host's answer
55
+ * @throws {Error} when the host is unknown, does not answer in time, or refuses the command
56
+ */
57
+ async #sendToHost(command, message) {
58
+ if (!this.host) {
59
+ throw new Error(`${command}: host of this instance is unknown`);
60
+ }
61
+ const answer = await this.#getMessaging().sendToHost({
62
+ hostName: this.host,
63
+ command,
64
+ message,
65
+ expectReply: true,
66
+ // without one there is no timer at all, so an older controller which does not know the
67
+ // command would leave this promise pending forever
68
+ options: { timeout: HOST_REPLY_TIMEOUT }
69
+ });
70
+ if (answer?.error) {
71
+ throw new Error(`${command} was refused by the host: ${answer.error}`);
72
+ }
73
+ return answer;
74
+ }
75
+ /**
76
+ * Registers an exclusive resource as used by this instance by forwarding it to the host.
77
+ *
78
+ * Registering is additive - one call per occupied resource, in any order. The host drops what this
79
+ * instance registered before when it starts, so there is nothing to reset by hand.
80
+ *
81
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
82
+ * @param data payload describing the resource
83
+ * @throws {Error} when the host refuses the registration or does not answer
84
+ */
85
+ async registerUsedResource(type, data) {
86
+ await this.#sendToHost("registerUsedResource", { type, data, instance: this.namespace });
87
+ }
88
+ /**
89
+ * Asks the host whether another instance currently holds a resource, without registering anything.
90
+ *
91
+ * Meant to be called *before* the port or the device is opened: afterwards the operating system
92
+ * has already decided the conflict, and all this can add is a better error message.
93
+ *
94
+ * The answer is a hint, not a permission. The registry only knows what adapters declare, so an
95
+ * empty list does not promise the resource is free - something outside ioBroker may hold it.
96
+ *
97
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
98
+ * @param data description of the resource that is about to be used
99
+ * @returns the entries of other instances that currently hold it, newest first
100
+ * @throws {Error} when the host refuses the request or does not answer
101
+ */
102
+ async checkUsedResource(type, data) {
103
+ const answer = await this.#sendToHost("checkUsedResource", { type, data, instance: this.namespace });
104
+ return Array.isArray(answer?.conflicts) ? answer.conflicts : [];
105
+ }
106
+ /**
107
+ * Frees all exclusive resources this instance registered, across all types, by forwarding it to the host.
108
+ *
109
+ * @throws {Error} when the host refuses the command or does not answer
110
+ */
111
+ async clearUsedResources() {
112
+ await this.#sendToHost("clearUsedResources", { instance: this.namespace });
113
+ }
114
+ /**
115
+ * Frees previously registered exclusive resources of this instance by forwarding it to the host.
116
+ *
117
+ * @param type the kind of resource, e.g. "serialPort" or "tcpPort"
118
+ * @param data fields identifying the resources to free; if omitted, all resources of `type` are freed
119
+ * @throws {Error} when the host refuses the command or does not answer
120
+ */
121
+ async freeUsedResource(type, data) {
122
+ await this.#sendToHost("freeUsedResource", { type, data, instance: this.namespace });
123
+ }
124
+ /**
125
+ * @param type resource type to read; if omitted, the resources of every type are read
126
+ */
127
+ async getHostUsedResources(type) {
128
+ if (!this.host) {
129
+ throw new Error("getHostUsedResources: host of this instance is unknown");
130
+ }
131
+ const states = this.states;
132
+ const prefix = `system.host.${this.host}.${USED_RESOURCES_ID}`;
133
+ if (type !== void 0) {
134
+ const state = await states.getState(`${prefix}.${type}`);
135
+ return ResourceManager.#parseResources(state);
136
+ }
137
+ const keys = await states.getKeys(`${prefix}.*`);
138
+ const resources = [];
139
+ if (keys?.length) {
140
+ const values = await states.getStates(keys);
141
+ for (const state of values) {
142
+ resources.push(...ResourceManager.#parseResources(state));
143
+ }
144
+ }
145
+ return resources;
146
+ }
147
+ /**
148
+ * Parses a `usedResources` state value (a JSON-encoded array) into a typed list, ignoring
149
+ * malformed or empty content.
150
+ *
151
+ * @param state the state holding the JSON-encoded resource array, if any
152
+ */
153
+ static #parseResources(state) {
154
+ if (state && typeof state.val === "string" && state.val) {
155
+ try {
156
+ const parsed = JSON.parse(state.val);
157
+ if (Array.isArray(parsed)) {
158
+ return parsed.filter((entry) => (0, import_tools.hasRegisteredResourceShape)(entry));
159
+ }
160
+ } catch {
161
+ }
162
+ }
163
+ return [];
164
+ }
165
+ }
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ ResourceManager
169
+ });
170
+ //# sourceMappingURL=ResourceManager.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/lib/adapter/managers/ResourceManager.ts"],
4
+ "sourcesContent": ["import { hasRegisteredResourceShape } from '@iobroker/js-controller-common-db/tools';\nimport type { AdapterContext } from '@/lib/adapter/context.js';\nimport { AdapterContextBase } from '@/lib/adapter/managers/AdapterContextBase.js';\nimport type { MessagingManager } from '@/lib/adapter/managers/MessagingManager.js';\n\n/** Sub-id under a host holding the exclusive resources registered as used by its instances. */\nconst USED_RESOURCES_ID = 'usedResources';\n/** How long a mutating command waits for the host to answer, in ms */\nconst HOST_REPLY_TIMEOUT = 5_000;\n\n/**\n * Owns the adapter's exclusive-resource registry. Register/free requests are forwarded to the host\n * this instance runs on, which keeps `system.host.<hostname>.usedResources.<type>` up to date; reads\n * go straight to those states.\n */\nexport class ResourceManager extends AdapterContextBase {\n readonly #getMessaging: () => MessagingManager;\n\n /**\n * @param ctx Shared adapter context providing live runtime state\n * @param getMessaging Returns the adapter's messaging manager. Passed as a getter rather than an\n * instance because it is created lazily - and it has to be *the* one, since it owns the map\n * the host's reply is matched against.\n */\n constructor(ctx: AdapterContext, getMessaging: () => MessagingManager) {\n super(ctx);\n this.#getMessaging = getMessaging;\n }\n\n /**\n * Send a mutating command to the host this instance runs on and wait for its verdict.\n *\n * The host validates every one of these - resource type, payload shape, the sending instance and\n * whether it declares its resources at all - and answers with `{ error }` when it refuses. Without\n * waiting for that answer the adapter would get a resolved promise for a call that did nothing,\n * and the only trace would be a warning in a log the adapter developer does not read.\n *\n * @param command the host command, e.g. \"registerUsedResource\"\n * @param message the command payload\n * @returns the host's answer\n * @throws {Error} when the host is unknown, does not answer in time, or refuses the command\n */\n async #sendToHost(command: string, message: Record<string, unknown>): Promise<any> {\n if (!this.host) {\n throw new Error(`${command}: host of this instance is unknown`);\n }\n\n const answer = await this.#getMessaging().sendToHost({\n hostName: this.host,\n command,\n message,\n expectReply: true,\n // without one there is no timer at all, so an older controller which does not know the\n // command would leave this promise pending forever\n options: { timeout: HOST_REPLY_TIMEOUT },\n });\n\n if (answer?.error) {\n throw new Error(`${command} was refused by the host: ${answer.error}`);\n }\n\n return answer;\n }\n\n /**\n * Registers an exclusive resource as used by this instance by forwarding it to the host.\n *\n * Registering is additive - one call per occupied resource, in any order. The host drops what this\n * instance registered before when it starts, so there is nothing to reset by hand.\n *\n * @param type the kind of resource, e.g. \"serialPort\" or \"tcpPort\"\n * @param data payload describing the resource\n * @throws {Error} when the host refuses the registration or does not answer\n */\n async registerUsedResource<T extends ioBroker.UsedResourceType>(\n type: T,\n data: ioBroker.UsedResourceData<T>,\n ): Promise<void> {\n await this.#sendToHost('registerUsedResource', { type, data, instance: this.namespace });\n }\n\n /**\n * Asks the host whether another instance currently holds a resource, without registering anything.\n *\n * Meant to be called *before* the port or the device is opened: afterwards the operating system\n * has already decided the conflict, and all this can add is a better error message.\n *\n * The answer is a hint, not a permission. The registry only knows what adapters declare, so an\n * empty list does not promise the resource is free - something outside ioBroker may hold it.\n *\n * @param type the kind of resource, e.g. \"serialPort\" or \"tcpPort\"\n * @param data description of the resource that is about to be used\n * @returns the entries of other instances that currently hold it, newest first\n * @throws {Error} when the host refuses the request or does not answer\n */\n async checkUsedResource<T extends ioBroker.UsedResourceType>(\n type: T,\n data?: Partial<ioBroker.UsedResourceData<T>>,\n ): Promise<ioBroker.RegisteredResource[]> {\n const answer = await this.#sendToHost('checkUsedResource', { type, data, instance: this.namespace });\n return Array.isArray(answer?.conflicts) ? answer.conflicts : [];\n }\n\n /**\n * Frees all exclusive resources this instance registered, across all types, by forwarding it to the host.\n *\n * @throws {Error} when the host refuses the command or does not answer\n */\n async clearUsedResources(): Promise<void> {\n await this.#sendToHost('clearUsedResources', { instance: this.namespace });\n }\n\n /**\n * Frees previously registered exclusive resources of this instance by forwarding it to the host.\n *\n * @param type the kind of resource, e.g. \"serialPort\" or \"tcpPort\"\n * @param data fields identifying the resources to free; if omitted, all resources of `type` are freed\n * @throws {Error} when the host refuses the command or does not answer\n */\n async freeUsedResource<T extends ioBroker.UsedResourceType>(\n type: T,\n data?: Partial<ioBroker.UsedResourceData<T>>,\n ): Promise<void> {\n await this.#sendToHost('freeUsedResource', { type, data, instance: this.namespace });\n }\n\n /**\n * Reads the exclusive resources of the given type currently registered on this instance's host, across\n * all its instances.\n *\n * @param type resource type to read, e.g. \"serialPort\"\n * @throws {Error} when the host of this instance is unknown\n */\n async getHostUsedResources<T extends ioBroker.UsedResourceType>(type: T): Promise<ioBroker.RegisteredResource<T>[]>;\n /** Reads the exclusive resources of every type currently registered on this instance's host. */\n async getHostUsedResources(): Promise<ioBroker.RegisteredResource[]>;\n\n /**\n * @param type resource type to read; if omitted, the resources of every type are read\n */\n async getHostUsedResources(type?: ioBroker.UsedResourceType): Promise<ioBroker.RegisteredResource[]> {\n if (!this.host) {\n throw new Error('getHostUsedResources: host of this instance is unknown');\n }\n\n const states = this.states;\n const prefix = `system.host.${this.host}.${USED_RESOURCES_ID}`;\n\n if (type !== undefined) {\n const state = await states.getState(`${prefix}.${type}`);\n return ResourceManager.#parseResources<ioBroker.RegisteredResource>(state);\n }\n\n const keys = await states.getKeys(`${prefix}.*`);\n\n const resources: ioBroker.RegisteredResource[] = [];\n if (keys?.length) {\n const values = await states.getStates(keys);\n for (const state of values) {\n resources.push(...ResourceManager.#parseResources<ioBroker.RegisteredResource>(state));\n }\n }\n\n return resources;\n }\n\n /**\n * Parses a `usedResources` state value (a JSON-encoded array) into a typed list, ignoring\n * malformed or empty content.\n *\n * @param state the state holding the JSON-encoded resource array, if any\n */\n static #parseResources<R extends ioBroker.RegisteredResource>(state: ioBroker.State | null | undefined): R[] {\n if (state && typeof state.val === 'string' && state.val) {\n try {\n const parsed: unknown = JSON.parse(state.val);\n if (Array.isArray(parsed)) {\n // The same check the host applies when it reads these states back. They are declared\n // read-only, but nothing enforces that, so an entry that is not a resource at all must not\n // reach the caller as if it were one.\n return parsed.filter(entry => hasRegisteredResourceShape(entry)) as R[];\n }\n } catch {\n // ignore malformed content\n }\n }\n return [];\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;;;;;AAAA,mBAA2C;AAE3C,gCAAmC;AAInC,MAAM,oBAAoB;AAE1B,MAAM,qBAAqB;AAOrB,MAAO,wBAAwB,6CAAkB;EAfvD,OAeuD;;;EAC1C;;;;;;;EAQT,YAAY,KAAqB,cAAoC;AACjE,UAAM,GAAG;AACT,SAAK,gBAAgB;EACzB;;;;;;;;;;;;;;EAeA,MAAM,YAAY,SAAiB,SAAgC;AAC/D,QAAI,CAAC,KAAK,MAAM;AACZ,YAAM,IAAI,MAAM,GAAG,OAAO,oCAAoC;IAClE;AAEA,UAAM,SAAS,MAAM,KAAK,cAAa,EAAG,WAAW;MACjD,UAAU,KAAK;MACf;MACA;MACA,aAAa;;;MAGb,SAAS,EAAE,SAAS,mBAAkB;KACzC;AAED,QAAI,QAAQ,OAAO;AACf,YAAM,IAAI,MAAM,GAAG,OAAO,6BAA6B,OAAO,KAAK,EAAE;IACzE;AAEA,WAAO;EACX;;;;;;;;;;;EAYA,MAAM,qBACF,MACA,MAAkC;AAElC,UAAM,KAAK,YAAY,wBAAwB,EAAE,MAAM,MAAM,UAAU,KAAK,UAAS,CAAE;EAC3F;;;;;;;;;;;;;;;EAgBA,MAAM,kBACF,MACA,MAA4C;AAE5C,UAAM,SAAS,MAAM,KAAK,YAAY,qBAAqB,EAAE,MAAM,MAAM,UAAU,KAAK,UAAS,CAAE;AACnG,WAAO,MAAM,QAAQ,QAAQ,SAAS,IAAI,OAAO,YAAY,CAAA;EACjE;;;;;;EAOA,MAAM,qBAAkB;AACpB,UAAM,KAAK,YAAY,sBAAsB,EAAE,UAAU,KAAK,UAAS,CAAE;EAC7E;;;;;;;;EASA,MAAM,iBACF,MACA,MAA4C;AAE5C,UAAM,KAAK,YAAY,oBAAoB,EAAE,MAAM,MAAM,UAAU,KAAK,UAAS,CAAE;EACvF;;;;EAgBA,MAAM,qBAAqB,MAAgC;AACvD,QAAI,CAAC,KAAK,MAAM;AACZ,YAAM,IAAI,MAAM,wDAAwD;IAC5E;AAEA,UAAM,SAAS,KAAK;AACpB,UAAM,SAAS,eAAe,KAAK,IAAI,IAAI,iBAAiB;AAE5D,QAAI,SAAS,QAAW;AACpB,YAAM,QAAQ,MAAM,OAAO,SAAS,GAAG,MAAM,IAAI,IAAI,EAAE;AACvD,aAAO,gBAAgB,gBAA6C,KAAK;IAC7E;AAEA,UAAM,OAAO,MAAM,OAAO,QAAQ,GAAG,MAAM,IAAI;AAE/C,UAAM,YAA2C,CAAA;AACjD,QAAI,MAAM,QAAQ;AACd,YAAM,SAAS,MAAM,OAAO,UAAU,IAAI;AAC1C,iBAAW,SAAS,QAAQ;AACxB,kBAAU,KAAK,GAAG,gBAAgB,gBAA6C,KAAK,CAAC;MACzF;IACJ;AAEA,WAAO;EACX;;;;;;;EAQA,OAAO,gBAAuD,OAAwC;AAClG,QAAI,SAAS,OAAO,MAAM,QAAQ,YAAY,MAAM,KAAK;AACrD,UAAI;AACA,cAAM,SAAkB,KAAK,MAAM,MAAM,GAAG;AAC5C,YAAI,MAAM,QAAQ,MAAM,GAAG;AAIvB,iBAAO,OAAO,OAAO,eAAS,yCAA2B,KAAK,CAAC;QACnE;MACJ,QAAQ;MAER;IACJ;AACA,WAAO,CAAA;EACX;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,107 @@
1
+ import type { Pattern } from '../../_Types.js';
2
+ import type { AdapterContext } from '../../../lib/adapter/context.js';
3
+ import { AdapterContextBase } from '../../../lib/adapter/managers/AdapterContextBase.js';
4
+ import type { AliasManager } from '../../../lib/adapter/managers/AliasManager.js';
5
+ /** Prefixes an id or pattern with this adapter's namespace unless already namespaced. Bound to the adapter's Validator. */
6
+ export type FixId = (id: string, isPattern?: boolean) => string;
7
+ type SubOptions = {
8
+ user?: ioBroker.ObjectIDs.User;
9
+ } | null | undefined;
10
+ /** Reads the objects matching a pattern, used to discover alias objects during state subscription. */
11
+ export interface ObjectAccess {
12
+ /**
13
+ * Objects matching `pattern`, keyed by id. Bound to the legacy `getForeignObjects(pattern, null, null, options)`
14
+ * call, whose `null` type/enums args clobber `options` — so no type filter and no user-ACL are applied;
15
+ * only `alias.*` ids in the result are consumed. Kept as-is for behavior parity.
16
+ */
17
+ getForeignStateObjects(pattern: string, options?: {
18
+ user?: ioBroker.ObjectIDs.User;
19
+ } | null): Promise<Record<string, ioBroker.AnyObject>>;
20
+ }
21
+ /** Owns object-, file- and state-change subscriptions plus the auto-subscribe bookkeeping. */
22
+ export declare class SubscriptionManager extends AdapterContextBase {
23
+ #private;
24
+ /**
25
+ * @param ctx Shared adapter context providing live runtime state
26
+ * @param fixId Namespace-prefixer bound to the adapter's Validator
27
+ * @param aliasManager Alias subscription cache and bookkeeping
28
+ * @param objectAccess Reader for state-typed objects matching a pattern
29
+ */
30
+ constructor(ctx: AdapterContext, fixId: FixId, aliasManager: AliasManager, objectAccess: ObjectAccess);
31
+ /**
32
+ * Subscribe to object changes within this instance's namespace.
33
+ *
34
+ * @param pattern pattern without namespace, `*` for all own objects, or an array of patterns
35
+ * passed through as-is (not namespaced)
36
+ * @param options optional user context
37
+ */
38
+ subscribeObjects(pattern: Pattern, options?: SubOptions): Promise<void>;
39
+ /**
40
+ * Unsubscribe from object changes within this instance's namespace.
41
+ *
42
+ * @param pattern pattern without namespace, `*` for all own objects, or an array of patterns
43
+ * passed through as-is (not namespaced)
44
+ * @param options optional user context
45
+ */
46
+ unsubscribeObjects(pattern: Pattern, options?: SubOptions): Promise<void>;
47
+ /**
48
+ * Subscribe to object changes in any instance.
49
+ *
50
+ * @param pattern pattern or array of patterns
51
+ * @param options optional user context
52
+ */
53
+ subscribeForeignObjects(pattern: Pattern, options?: SubOptions): Promise<void>;
54
+ /**
55
+ * Unsubscribe from object changes in any instance.
56
+ *
57
+ * @param pattern pattern or array of patterns (defaults to `*`)
58
+ * @param options optional user context
59
+ */
60
+ unsubscribeForeignObjects(pattern: Pattern, options?: SubOptions): Promise<void>;
61
+ /**
62
+ * Subscribe to file changes in a specific instance.
63
+ *
64
+ * @param id adapter id, e.g. `vis-2.0`
65
+ * @param pattern pattern or array of patterns
66
+ * @param options optional user context
67
+ */
68
+ subscribeForeignFiles(id: string, pattern: Pattern, options?: SubOptions): Promise<void>;
69
+ /**
70
+ * Unsubscribe from file changes in a specific instance.
71
+ *
72
+ * @param id adapter id, e.g. `vis-2.0`
73
+ * @param pattern pattern or array of patterns (defaults to `*`)
74
+ * @param options optional user context
75
+ */
76
+ unsubscribeForeignFiles(id: string, pattern: Pattern, options?: SubOptions): Promise<void>;
77
+ /**
78
+ * Register an instance as auto-subscribable (its `subscribes` counter is maintained on subscribe/unsubscribe).
79
+ *
80
+ * @param id instance id, e.g. `pushover.0`
81
+ */
82
+ addSubscribableInstance(id: string): void;
83
+ /**
84
+ * Stop treating an instance as auto-subscribable.
85
+ *
86
+ * @param id instance id, e.g. `pushover.0`
87
+ */
88
+ removeSubscribableInstance(id: string): void;
89
+ /** Populate the auto-subscribe instance list from the objects DB. */
90
+ autoSubscribeOn(): Promise<void>;
91
+ /**
92
+ * Subscribe to state changes in any instance, resolving aliases and maintaining auto-subscribe counters.
93
+ *
94
+ * @param pattern pattern, `*`, an `alias.*` id, or an array of ids/patterns
95
+ * @param options optional user context
96
+ */
97
+ subscribeForeignStates(pattern: Pattern, options?: SubOptions): Promise<void>;
98
+ /**
99
+ * Unsubscribe from state changes in any instance, mirroring {@link subscribeForeignStates}.
100
+ *
101
+ * @param pattern pattern, `*`, an `alias.*` id, or an array of ids/patterns
102
+ * @param options optional user context
103
+ */
104
+ unsubscribeForeignStates(pattern: Pattern, options?: SubOptions): Promise<void>;
105
+ }
106
+ export {};
107
+ //# sourceMappingURL=SubscriptionManager.d.ts.map