@uns-kit/core 3.0.31 → 3.0.33

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 (49) hide show
  1. package/MIGRATIONS.md +43 -0
  2. package/dist/config/app-config.d.ts +1 -0
  3. package/dist/config/app-config.d.ts.map +1 -1
  4. package/dist/config/app-config.js.map +1 -1
  5. package/dist/runtime/mqtt-drain.d.ts +29 -0
  6. package/dist/runtime/mqtt-drain.d.ts.map +1 -0
  7. package/dist/runtime/mqtt-drain.js +70 -0
  8. package/dist/runtime/mqtt-drain.js.map +1 -0
  9. package/dist/runtime/mqtt-output-state-contract.d.ts.map +1 -1
  10. package/dist/runtime/mqtt-output-state-contract.js +2 -0
  11. package/dist/runtime/mqtt-output-state-contract.js.map +1 -1
  12. package/dist/runtime/mqtt-output-state-program.d.mts +4 -0
  13. package/dist/runtime/mqtt-output-state-program.mjs +51 -0
  14. package/dist/runtime/process-group-configured-upgrade.d.ts +1 -0
  15. package/dist/runtime/process-group-configured-upgrade.d.ts.map +1 -1
  16. package/dist/runtime/process-group-configured-upgrade.js +21 -4
  17. package/dist/runtime/process-group-configured-upgrade.js.map +1 -1
  18. package/dist/runtime/process-group-mqtt-output.d.ts +63 -0
  19. package/dist/runtime/process-group-mqtt-output.d.ts.map +1 -0
  20. package/dist/runtime/process-group-mqtt-output.js +89 -0
  21. package/dist/runtime/process-group-mqtt-output.js.map +1 -0
  22. package/dist/runtime/process-group-upgrade.d.ts +85 -2
  23. package/dist/runtime/process-group-upgrade.d.ts.map +1 -1
  24. package/dist/runtime/process-group-upgrade.js +74 -9
  25. package/dist/runtime/process-group-upgrade.js.map +1 -1
  26. package/dist/uns/uns-proxy-process.d.ts +8 -4
  27. package/dist/uns/uns-proxy-process.d.ts.map +1 -1
  28. package/dist/uns/uns-proxy-process.js +41 -5
  29. package/dist/uns/uns-proxy-process.js.map +1 -1
  30. package/dist/uns-config/config-schema.d.ts +1 -0
  31. package/dist/uns-config/config-schema.d.ts.map +1 -1
  32. package/dist/uns-config/uns-core-schema.d.ts +2 -0
  33. package/dist/uns-config/uns-core-schema.d.ts.map +1 -1
  34. package/dist/uns-mqtt/disabled-publish-queue.d.ts +6 -0
  35. package/dist/uns-mqtt/disabled-publish-queue.d.ts.map +1 -0
  36. package/dist/uns-mqtt/disabled-publish-queue.js +64 -0
  37. package/dist/uns-mqtt/disabled-publish-queue.js.map +1 -0
  38. package/dist/uns-mqtt/publish-queue-contract.d.ts +11 -0
  39. package/dist/uns-mqtt/publish-queue-contract.d.ts.map +1 -1
  40. package/dist/uns-mqtt/publish-queue-contract.js +16 -0
  41. package/dist/uns-mqtt/publish-queue-contract.js.map +1 -1
  42. package/dist/uns-mqtt/publish-queue.d.ts.map +1 -1
  43. package/dist/uns-mqtt/publish-queue.js +2 -0
  44. package/dist/uns-mqtt/publish-queue.js.map +1 -1
  45. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +3 -0
  46. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts.map +1 -1
  47. package/dist/uns-mqtt/uns-mqtt-proxy.js +19 -8
  48. package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
  49. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { MQTT_DRAIN_HANDLER, MQTT_DRAIN_READY_EVENT, drainMqttForMigration } from "../runtime/mqtt-drain.js";
1
2
  import { randomBytes } from "crypto";
2
3
  import logger from "../logger.js";
3
4
  import MqttProxy from "../uns-mqtt/mqtt-proxy.js";
@@ -24,6 +25,8 @@ class UnsProxyProcess {
24
25
  statusMonitor;
25
26
  serviceMetadataTopic;
26
27
  shutdownPromise = null;
28
+ migrationDrainPromise = null;
29
+ migrationDrainHandler;
27
30
  // Plugin
28
31
  static pluginApiVersion = 1;
29
32
  static registered = new Set();
@@ -149,7 +152,7 @@ class UnsProxyProcess {
149
152
  * Creates a new UNS proxy instance and stores it for future management.
150
153
  */
151
154
  async createUnsMqttProxy(mqttHost, instanceName, instanceMode, handover, unsParameters) {
152
- if (unsParameters?.publishQueue && handover) {
155
+ if (unsParameters?.publishQueue && unsParameters.publishQueue.enabled !== false && handover) {
153
156
  throw new Error("Persistent MQTT output requires handover=false and one owner; legacy RAM handover does not transfer an outbox");
154
157
  }
155
158
  // Wait until the MQTT connection is established before proceeding.
@@ -200,10 +203,37 @@ class UnsProxyProcess {
200
203
  await this.processMqttProxy.publish(this.serviceMetadataTopic, JSON.stringify(resolved), { retain: true });
201
204
  return resolved;
202
205
  }
203
- /**
204
- * Shuts down the process by clearing intervals, timeouts, and removing
205
- * MQTT event listeners, and stopping the StatusMonitor.
206
- */
206
+ /** Call after application input handlers and shutdown hooks are prepared. */
207
+ enableMigrationDrain() {
208
+ const registry = globalThis;
209
+ if (this.migrationDrainHandler)
210
+ return;
211
+ if (registry[MQTT_DRAIN_HANDLER])
212
+ throw Error("One migration drain owner is allowed per process");
213
+ this.migrationDrainHandler = () => this.drainForMigration();
214
+ registry[MQTT_DRAIN_HANDLER] = this.migrationDrainHandler;
215
+ process.emit(MQTT_DRAIN_READY_EVENT, { protocol: 1 });
216
+ }
217
+ /** Works without a Controller too; success means confirmed empty output and closed owners. */
218
+ drainForMigration(timeoutMs = this.handoverShutdown?.timeoutMs ?? 30_000) {
219
+ if (this.migrationDrainPromise)
220
+ return this.migrationDrainPromise;
221
+ this.migrationDrainPromise = (async () => {
222
+ const receipt = await drainMqttForMigration({
223
+ quiesce: async () => {
224
+ this.handoverShutdown?.onRelease?.();
225
+ await Promise.all(this.unsMqttProxies.map(proxy => proxy.setSubscriberPassiveAndDrainQueue()));
226
+ },
227
+ finishAccepted: async () => { await this.handoverShutdown?.drain(); },
228
+ outputs: this.unsMqttProxies,
229
+ timeoutMs,
230
+ });
231
+ await this.shutdown({ drain: true, timeoutMs });
232
+ return receipt;
233
+ })().catch(error => { this.migrationDrainPromise = null; throw error; });
234
+ return this.migrationDrainPromise;
235
+ }
236
+ /** Stop process timers, status publication and all owned MQTT proxies. */
207
237
  shutdown(options = {}) {
208
238
  if (this.shutdownPromise) {
209
239
  return this.shutdownPromise;
@@ -254,6 +284,12 @@ class UnsProxyProcess {
254
284
  if (shutdownErrors.length > 0) {
255
285
  throw new AggregateError(shutdownErrors, `${this.processName} - Shutdown completed with errors.`);
256
286
  }
287
+ if (this.migrationDrainHandler) {
288
+ const registry = globalThis;
289
+ if (registry[MQTT_DRAIN_HANDLER] === this.migrationDrainHandler)
290
+ delete registry[MQTT_DRAIN_HANDLER];
291
+ process.channel?.unref();
292
+ }
257
293
  logger.info(`${this.processName} - Shutdown complete.`);
258
294
  }
259
295
  }
@@ -1 +1 @@
1
- {"version":3,"file":"uns-proxy-process.js","sourceRoot":"","sources":["../../src/uns/uns-proxy-process.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"crypto\";\n\nimport logger from \"../logger.js\";\nimport { IMqttParameters } from \"../uns-mqtt/mqtt-interfaces.js\";\nimport MqttProxy from \"../uns-mqtt/mqtt-proxy.js\";\nimport { MqttTopicBuilder } from \"../uns-mqtt/mqtt-topic-builder.js\";\nimport UnsMqttProxy from \"../uns-mqtt/uns-mqtt-proxy.js\";\nimport type { UnsMqttProxyStopOptions } from \"../uns-mqtt/uns-mqtt-proxy.js\";\nimport { HandoverManager } from \"./handover-manager.js\";\nimport { validateHandoverShutdown, type HandoverShutdownHooks } from \"./handover-shutdown.js\";\n// Import configuration and initialization modules.\nimport { MQTT_UPDATE_INTERVAL, PACKAGE_INFO } from \"./process-config.js\";\nimport { type UnsServiceMetadata, type UnsServiceMetadataInput, buildUnsServiceMetadata } from \"./service-metadata.js\";\nimport { StatusMonitor } from \"./status-monitor.js\";\nimport { IUnsMessage, IUnsParameters, IUnsProcessParameters, UnsEvents } from \"./uns-interfaces.js\";\nimport { UnsPacket } from \"./uns-packet.js\";\n\n/**\n * UnsProxyProcess is responsible for managing the process lifecycle,\n * configuring MQTT (subscriptions and publishing for status updates), and\n * handling UNS proxy instances.\n *\n * It leverages HandoverManager for handover events and StatusMonitor for health reporting.\n */\nexport type UnsProxyProcessPluginMethod = (this: UnsProxyProcess, ...args: unknown[]) => unknown;\n\nexport type UnsProxyProcessPluginMethods = Record<string, UnsProxyProcessPluginMethod>;\n\nexport interface UnsProxyProcessPluginApi {\n version: number;\n define(methods: UnsProxyProcessPluginMethods): void;\n UnsProxyProcess: typeof UnsProxyProcess;\n}\n\nexport type UnsProxyProcessPlugin = (api: UnsProxyProcessPluginApi) => void;\n\nclass UnsProxyProcess {\n private active: boolean = false;\n private processStatusTopic: string;\n private processName: string;\n private processId: string;\n private handoverId: string | undefined;\n private handoverShutdown: HandoverShutdownHooks | undefined;\n private unsMqttProxies: UnsMqttProxy[];\n private unsApiProxies: unknown[];\n private processMqttProxy: MqttProxy;\n private handoverManager: HandoverManager;\n private statusMonitor: StatusMonitor;\n private serviceMetadataTopic: string;\n private shutdownPromise: Promise<void> | null = null;\n\n // Plugin\n static pluginApiVersion = 1;\n private static registered = new Set<UnsProxyProcessPlugin>();\n private static registeredMethodNames = new Set<string>();\n private static applied = false;\n\n static use(plugin: UnsProxyProcessPlugin) {\n if (this.registered.has(plugin)) return this;\n this.registered.add(plugin);\n if (this.applied) this.applyPlugin(plugin);\n return this;\n }\n\n private static applyPlugin(plugin: UnsProxyProcessPlugin) {\n const define: UnsProxyProcessPluginApi[\"define\"] = (methods) => {\n for (const [name, fn] of Object.entries(methods)) {\n if (typeof fn !== \"function\") {\n throw new TypeError(`UnsProxyProcess plugin attempted to register non-function member \\\"${name}\\\".`);\n }\n if (this.registeredMethodNames.has(name) || Reflect.has(this.prototype, name)) {\n throw new Error(`UnsProxyProcess plugin attempted to overwrite existing member \\\"${name}\\\".`);\n }\n Object.defineProperty(this.prototype, name, {\n value: fn,\n writable: true,\n configurable: true,\n enumerable: false,\n });\n this.registeredMethodNames.add(name);\n }\n };\n\n plugin({\n define,\n version: this.pluginApiVersion,\n UnsProxyProcess: this,\n });\n }\n\n private static applyAll() {\n if (this.applied) return;\n this.applied = true;\n for (const p of this.registered) this.applyPlugin(p);\n }\n\n // References for cleanup.\n private mqttInputHandler: (event: any) => void;\n\n constructor(mqttHost: string, unsProxyProcessParameters: IUnsProcessParameters) {\n (this.constructor as typeof UnsProxyProcess).applyAll(); // Activate all the plugins\n\n this.unsMqttProxies = [];\n this.unsApiProxies = [];\n if (!unsProxyProcessParameters?.processName) {\n throw new Error(\"UnsProxyProcess requires a processName in configuration.\");\n }\n validateHandoverShutdown(unsProxyProcessParameters.handoverShutdown);\n this.handoverShutdown = unsProxyProcessParameters.handoverShutdown\n ? { ...unsProxyProcessParameters.handoverShutdown } : undefined;\n this.processName = unsProxyProcessParameters.processName;\n this.processId = randomBytes(16).toString(\"hex\");\n this.handoverId = unsProxyProcessParameters.handoverId ?? process.env[\"UNS_HANDOVER_ID\"];\n const { name: packageName, version } = PACKAGE_INFO;\n\n // Instantiate the topic builder.\n const topicBuilder = new MqttTopicBuilder(\n `uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageName)}/${MqttTopicBuilder.sanitizeTopicPart(version)}/${MqttTopicBuilder.sanitizeTopicPart(this.processName)}/`,\n );\n\n // Generate topics.\n const processStatusTopic = topicBuilder.getProcessStatusTopic();\n const handoverTopic = topicBuilder.getHandoverTopic();\n const wildcardActiveTopic = topicBuilder.getWildcardActiveTopic();\n const serviceMetadataTopic = topicBuilder.getServiceMetadataTopic();\n\n this.processStatusTopic = processStatusTopic;\n this.serviceMetadataTopic = serviceMetadataTopic;\n\n // Configure MQTT topics for subscription.\n const mqttSubToTopics = unsProxyProcessParameters?.mqttSubToTopics ?? [wildcardActiveTopic, handoverTopic];\n const mqttParameters: IMqttParameters = {\n mqttSubToTopics,\n username: unsProxyProcessParameters?.username ?? \"\",\n password: unsProxyProcessParameters?.password ?? \"\",\n mqttSSL: unsProxyProcessParameters?.mqttSSL ?? false,\n statusTopic: this.processStatusTopic,\n clientId: unsProxyProcessParameters?.clientId ?? `${this.processName}-${this.processId}`,\n hosts: unsProxyProcessParameters?.hosts,\n servers: unsProxyProcessParameters?.servers,\n port: unsProxyProcessParameters?.port,\n protocol: unsProxyProcessParameters?.protocol,\n keepalive: unsProxyProcessParameters?.keepalive,\n clean: unsProxyProcessParameters?.clean,\n connectTimeout: unsProxyProcessParameters?.connectTimeout,\n reconnectPeriod: unsProxyProcessParameters?.reconnectPeriod,\n reconnectOnConnackError: unsProxyProcessParameters?.reconnectOnConnackError,\n resubscribe: unsProxyProcessParameters?.resubscribe,\n queueQoSZero: unsProxyProcessParameters?.queueQoSZero,\n rejectUnauthorized: unsProxyProcessParameters?.rejectUnauthorized ?? false,\n properties: unsProxyProcessParameters?.properties,\n ca: unsProxyProcessParameters?.ca,\n cert: unsProxyProcessParameters?.cert,\n key: unsProxyProcessParameters?.key,\n servername: unsProxyProcessParameters?.servername,\n };\n\n // Initialize MQTT proxy and start connection.\n this.processMqttProxy = new MqttProxy(mqttHost, this.processName, mqttParameters);\n this.processMqttProxy.start();\n\n // Instantiate and start the StatusMonitor for memory and status updates.\n this.statusMonitor = new StatusMonitor(\n this.processMqttProxy,\n this.processStatusTopic,\n () => this.active,\n MQTT_UPDATE_INTERVAL,\n MQTT_UPDATE_INTERVAL,\n { processName: this.processName, processId: this.processId },\n );\n this.statusMonitor.start();\n }\n\n /**\n * Initializes the HandoverManager instance and sets up event listeners for handover and MQTT input events.\n * Determines handover and force start modes based on process arguments.\n */\n private initHandoverManager(instanceMode: string, handover: boolean, handoverId?: string) {\n const handoverRequestEnabled = instanceMode == \"handover\" ? true : false;\n const forceStartEnabled = instanceMode == \"force\" ? true : false;\n\n this.handoverManager = new HandoverManager(\n this.processName,\n this.processId,\n this.processMqttProxy,\n this.unsMqttProxies,\n handoverRequestEnabled,\n handover ?? true,\n forceStartEnabled,\n handoverId,\n this.handoverShutdown,\n );\n\n // Listen for handover events.\n this.handoverManager.event.on(\"handoverManager\", (event) => {\n this.active = event.active;\n });\n\n // Delegate MQTT events to the HandoverManager.\n this.mqttInputHandler = async (event: UnsEvents[\"input\"]) => {\n await this.handoverManager.handleMqttMessage(event);\n };\n this.processMqttProxy.event.on(\"input\", this.mqttInputHandler);\n }\n\n /**\n * Creates a new UNS proxy instance and stores it for future management.\n */\n public async createUnsMqttProxy(\n mqttHost: string,\n instanceName: string,\n instanceMode: string,\n handover: boolean,\n unsParameters?: IUnsParameters,\n ): Promise<UnsMqttProxy> {\n if (unsParameters?.publishQueue && handover) {\n throw new Error(\"Persistent MQTT output requires handover=false and one owner; legacy RAM handover does not transfer an outbox\");\n }\n // Wait until the MQTT connection is established before proceeding.\n await this.waitForProcessConnection();\n\n // Currently handover manager can handle only mqtt events\n if (!this.handoverManager) {\n this.initHandoverManager(\n instanceMode,\n handover,\n this.handoverId,\n );\n }\n\n const resolvedUnsParameters: IUnsParameters = {\n ...(unsParameters ?? {}),\n clientId: unsParameters?.clientId ?? `${this.processName}-${instanceName}-${this.processId}`,\n };\n const unsMqttProxy = new UnsMqttProxy(mqttHost, this.processName, instanceName, resolvedUnsParameters);\n\n // Listen for UNS proxy producing topics and publish them via MQTT.\n unsMqttProxy.event.on(\"unsProxyProducedTopics\", (event) => {\n this.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedTopics));\n });\n\n // Listen for UNS proxy status events and publish them via MQTT.\n unsMqttProxy.event.on(\"mqttProxyStatus\", (event) => {\n const time = UnsPacket.formatToISO8601(new Date());\n const unsMessage: IUnsMessage = { data: { time, value: event.value, uom: event.uom } };\n UnsPacket.unsPacketFromUnsMessage(unsMessage).then((packet) => {\n this.processMqttProxy.publish(event.statusTopic, JSON.stringify(packet));\n });\n });\n\n this.unsMqttProxies.push(unsMqttProxy);\n return unsMqttProxy;\n }\n\n public async waitForProcessConnection(): Promise<void> {\n while (!this.processMqttProxy?.isConnected) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n\n /**\n * Publishes retained product/system service metadata for controller discovery.\n *\n * The payload is intentionally separate from the volatile active/alive status\n * topics. Controllers can combine this retained identity/capability metadata\n * with live process status to decide whether a service is currently healthy.\n */\n public async publishServiceMetadata(metadata: UnsServiceMetadataInput): Promise<UnsServiceMetadata> {\n await this.waitForProcessConnection();\n const resolved = buildUnsServiceMetadata({\n processName: this.processName,\n processId: this.processId,\n metadata,\n });\n await this.processMqttProxy.publish(this.serviceMetadataTopic, JSON.stringify(resolved), { retain: true });\n return resolved;\n }\n\n /**\n * Shuts down the process by clearing intervals, timeouts, and removing\n * MQTT event listeners, and stopping the StatusMonitor.\n */\n public shutdown(options: UnsMqttProxyStopOptions = {}): Promise<void> {\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = this.performShutdown(options);\n return this.shutdownPromise;\n }\n\n private async performShutdown(options: UnsMqttProxyStopOptions): Promise<void> {\n logger.info(`${this.processName} - Shutting down UnsProxyProcess...`);\n const shutdownErrors: Error[] = [];\n\n try {\n this.statusMonitor.stop();\n await this.statusMonitor.publishInactiveStatus();\n } catch (e: any) {\n const reason = e instanceof Error ? e : new Error(String(e));\n logger.error(`${this.processName} - Error stopping StatusMonitor or publishing passive state: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n\n if (this.mqttInputHandler) {\n try {\n this.processMqttProxy.event.off(\"input\", this.mqttInputHandler);\n } catch (e: any) {\n const reason = e instanceof Error ? e : new Error(String(e));\n logger.error(`${this.processName} - Error removing MQTT input handler: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n }\n\n const proxyStopResults = await Promise.allSettled(this.unsMqttProxies.map((proxy) => proxy.stop(options)));\n for (const result of proxyStopResults) {\n if (result.status === \"rejected\") {\n const reason = result.reason instanceof Error ? result.reason : new Error(String(result.reason));\n logger.error(`${this.processName} - Error stopping UNS MQTT proxy: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n }\n\n try {\n if (typeof this.processMqttProxy.stop === \"function\") {\n await this.processMqttProxy.stop();\n }\n } catch (e: any) {\n const reason = e instanceof Error ? e : new Error(String(e));\n logger.error(`${this.processName} - Error stopping MQTT proxy: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n\n if (shutdownErrors.length > 0) {\n throw new AggregateError(shutdownErrors, `${this.processName} - Shutdown completed with errors.`);\n }\n\n logger.info(`${this.processName} - Shutdown complete.`);\n }\n}\n\ninterface UnsProxyProcess {}\n\nexport default UnsProxyProcess;\nexport type { UnsServiceMetadata, UnsServiceMetadataInput };\nexport { UnsProxyProcess };\n"]}
1
+ {"version":3,"file":"uns-proxy-process.js","sourceRoot":"","sources":["../../src/uns/uns-proxy-process.ts"],"names":[],"mappings":"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","sourcesContent":["import { MQTT_DRAIN_HANDLER, MQTT_DRAIN_READY_EVENT, drainMqttForMigration, type MqttDrainReceipt } from \"../runtime/mqtt-drain.js\";\nimport { randomBytes } from \"crypto\";\n\nimport logger from \"../logger.js\";\nimport { IMqttParameters } from \"../uns-mqtt/mqtt-interfaces.js\";\nimport MqttProxy from \"../uns-mqtt/mqtt-proxy.js\";\nimport { MqttTopicBuilder } from \"../uns-mqtt/mqtt-topic-builder.js\";\nimport UnsMqttProxy from \"../uns-mqtt/uns-mqtt-proxy.js\";\nimport type { UnsMqttProxyStopOptions } from \"../uns-mqtt/uns-mqtt-proxy.js\";\nimport { HandoverManager } from \"./handover-manager.js\";\nimport { validateHandoverShutdown, type HandoverShutdownHooks } from \"./handover-shutdown.js\";\n// Import configuration and initialization modules.\nimport { MQTT_UPDATE_INTERVAL, PACKAGE_INFO } from \"./process-config.js\";\nimport { type UnsServiceMetadata, type UnsServiceMetadataInput, buildUnsServiceMetadata } from \"./service-metadata.js\";\nimport { StatusMonitor } from \"./status-monitor.js\";\nimport { IUnsMessage, IUnsParameters, IUnsProcessParameters, UnsEvents } from \"./uns-interfaces.js\";\nimport { UnsPacket } from \"./uns-packet.js\";\n\n/**\n * UnsProxyProcess is responsible for managing the process lifecycle,\n * configuring MQTT (subscriptions and publishing for status updates), and\n * handling UNS proxy instances.\n *\n * It leverages HandoverManager for handover events and StatusMonitor for health reporting.\n */\nexport type UnsProxyProcessPluginMethod = (this: UnsProxyProcess, ...args: unknown[]) => unknown;\n\nexport type UnsProxyProcessPluginMethods = Record<string, UnsProxyProcessPluginMethod>;\n\nexport interface UnsProxyProcessPluginApi {\n version: number;\n define(methods: UnsProxyProcessPluginMethods): void;\n UnsProxyProcess: typeof UnsProxyProcess;\n}\n\nexport type UnsProxyProcessPlugin = (api: UnsProxyProcessPluginApi) => void;\n\nclass UnsProxyProcess {\n private active: boolean = false;\n private processStatusTopic: string;\n private processName: string;\n private processId: string;\n private handoverId: string | undefined;\n private handoverShutdown: HandoverShutdownHooks | undefined;\n private unsMqttProxies: UnsMqttProxy[];\n private unsApiProxies: unknown[];\n private processMqttProxy: MqttProxy;\n private handoverManager: HandoverManager;\n private statusMonitor: StatusMonitor;\n private serviceMetadataTopic: string;\n private shutdownPromise: Promise<void> | null = null;\n private migrationDrainPromise: Promise<MqttDrainReceipt> | null = null;\n private migrationDrainHandler?: () => Promise<MqttDrainReceipt>;\n\n // Plugin\n static pluginApiVersion = 1;\n private static registered = new Set<UnsProxyProcessPlugin>();\n private static registeredMethodNames = new Set<string>();\n private static applied = false;\n\n static use(plugin: UnsProxyProcessPlugin) {\n if (this.registered.has(plugin)) return this;\n this.registered.add(plugin);\n if (this.applied) this.applyPlugin(plugin);\n return this;\n }\n\n private static applyPlugin(plugin: UnsProxyProcessPlugin) {\n const define: UnsProxyProcessPluginApi[\"define\"] = (methods) => {\n for (const [name, fn] of Object.entries(methods)) {\n if (typeof fn !== \"function\") {\n throw new TypeError(`UnsProxyProcess plugin attempted to register non-function member \\\"${name}\\\".`);\n }\n if (this.registeredMethodNames.has(name) || Reflect.has(this.prototype, name)) {\n throw new Error(`UnsProxyProcess plugin attempted to overwrite existing member \\\"${name}\\\".`);\n }\n Object.defineProperty(this.prototype, name, {\n value: fn,\n writable: true,\n configurable: true,\n enumerable: false,\n });\n this.registeredMethodNames.add(name);\n }\n };\n\n plugin({\n define,\n version: this.pluginApiVersion,\n UnsProxyProcess: this,\n });\n }\n\n private static applyAll() {\n if (this.applied) return;\n this.applied = true;\n for (const p of this.registered) this.applyPlugin(p);\n }\n\n // References for cleanup.\n private mqttInputHandler: (event: any) => void;\n\n constructor(mqttHost: string, unsProxyProcessParameters: IUnsProcessParameters) {\n (this.constructor as typeof UnsProxyProcess).applyAll(); // Activate all the plugins\n\n this.unsMqttProxies = [];\n this.unsApiProxies = [];\n if (!unsProxyProcessParameters?.processName) {\n throw new Error(\"UnsProxyProcess requires a processName in configuration.\");\n }\n validateHandoverShutdown(unsProxyProcessParameters.handoverShutdown);\n this.handoverShutdown = unsProxyProcessParameters.handoverShutdown\n ? { ...unsProxyProcessParameters.handoverShutdown } : undefined;\n this.processName = unsProxyProcessParameters.processName;\n this.processId = randomBytes(16).toString(\"hex\");\n this.handoverId = unsProxyProcessParameters.handoverId ?? process.env[\"UNS_HANDOVER_ID\"];\n const { name: packageName, version } = PACKAGE_INFO;\n\n // Instantiate the topic builder.\n const topicBuilder = new MqttTopicBuilder(\n `uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageName)}/${MqttTopicBuilder.sanitizeTopicPart(version)}/${MqttTopicBuilder.sanitizeTopicPart(this.processName)}/`,\n );\n\n // Generate topics.\n const processStatusTopic = topicBuilder.getProcessStatusTopic();\n const handoverTopic = topicBuilder.getHandoverTopic();\n const wildcardActiveTopic = topicBuilder.getWildcardActiveTopic();\n const serviceMetadataTopic = topicBuilder.getServiceMetadataTopic();\n\n this.processStatusTopic = processStatusTopic;\n this.serviceMetadataTopic = serviceMetadataTopic;\n\n // Configure MQTT topics for subscription.\n const mqttSubToTopics = unsProxyProcessParameters?.mqttSubToTopics ?? [wildcardActiveTopic, handoverTopic];\n const mqttParameters: IMqttParameters = {\n mqttSubToTopics,\n username: unsProxyProcessParameters?.username ?? \"\",\n password: unsProxyProcessParameters?.password ?? \"\",\n mqttSSL: unsProxyProcessParameters?.mqttSSL ?? false,\n statusTopic: this.processStatusTopic,\n clientId: unsProxyProcessParameters?.clientId ?? `${this.processName}-${this.processId}`,\n hosts: unsProxyProcessParameters?.hosts,\n servers: unsProxyProcessParameters?.servers,\n port: unsProxyProcessParameters?.port,\n protocol: unsProxyProcessParameters?.protocol,\n keepalive: unsProxyProcessParameters?.keepalive,\n clean: unsProxyProcessParameters?.clean,\n connectTimeout: unsProxyProcessParameters?.connectTimeout,\n reconnectPeriod: unsProxyProcessParameters?.reconnectPeriod,\n reconnectOnConnackError: unsProxyProcessParameters?.reconnectOnConnackError,\n resubscribe: unsProxyProcessParameters?.resubscribe,\n queueQoSZero: unsProxyProcessParameters?.queueQoSZero,\n rejectUnauthorized: unsProxyProcessParameters?.rejectUnauthorized ?? false,\n properties: unsProxyProcessParameters?.properties,\n ca: unsProxyProcessParameters?.ca,\n cert: unsProxyProcessParameters?.cert,\n key: unsProxyProcessParameters?.key,\n servername: unsProxyProcessParameters?.servername,\n };\n\n // Initialize MQTT proxy and start connection.\n this.processMqttProxy = new MqttProxy(mqttHost, this.processName, mqttParameters);\n this.processMqttProxy.start();\n\n // Instantiate and start the StatusMonitor for memory and status updates.\n this.statusMonitor = new StatusMonitor(\n this.processMqttProxy,\n this.processStatusTopic,\n () => this.active,\n MQTT_UPDATE_INTERVAL,\n MQTT_UPDATE_INTERVAL,\n { processName: this.processName, processId: this.processId },\n );\n this.statusMonitor.start();\n }\n\n /**\n * Initializes the HandoverManager instance and sets up event listeners for handover and MQTT input events.\n * Determines handover and force start modes based on process arguments.\n */\n private initHandoverManager(instanceMode: string, handover: boolean, handoverId?: string) {\n const handoverRequestEnabled = instanceMode == \"handover\" ? true : false;\n const forceStartEnabled = instanceMode == \"force\" ? true : false;\n\n this.handoverManager = new HandoverManager(\n this.processName,\n this.processId,\n this.processMqttProxy,\n this.unsMqttProxies,\n handoverRequestEnabled,\n handover ?? true,\n forceStartEnabled,\n handoverId,\n this.handoverShutdown,\n );\n\n // Listen for handover events.\n this.handoverManager.event.on(\"handoverManager\", (event) => {\n this.active = event.active;\n });\n\n // Delegate MQTT events to the HandoverManager.\n this.mqttInputHandler = async (event: UnsEvents[\"input\"]) => {\n await this.handoverManager.handleMqttMessage(event);\n };\n this.processMqttProxy.event.on(\"input\", this.mqttInputHandler);\n }\n\n /**\n * Creates a new UNS proxy instance and stores it for future management.\n */\n public async createUnsMqttProxy(\n mqttHost: string,\n instanceName: string,\n instanceMode: string,\n handover: boolean,\n unsParameters?: IUnsParameters,\n ): Promise<UnsMqttProxy> {\n if (unsParameters?.publishQueue && unsParameters.publishQueue.enabled !== false && handover) {\n throw new Error(\"Persistent MQTT output requires handover=false and one owner; legacy RAM handover does not transfer an outbox\");\n }\n // Wait until the MQTT connection is established before proceeding.\n await this.waitForProcessConnection();\n\n // Currently handover manager can handle only mqtt events\n if (!this.handoverManager) {\n this.initHandoverManager(\n instanceMode,\n handover,\n this.handoverId,\n );\n }\n\n const resolvedUnsParameters: IUnsParameters = {\n ...(unsParameters ?? {}),\n clientId: unsParameters?.clientId ?? `${this.processName}-${instanceName}-${this.processId}`,\n };\n const unsMqttProxy = new UnsMqttProxy(mqttHost, this.processName, instanceName, resolvedUnsParameters);\n\n // Listen for UNS proxy producing topics and publish them via MQTT.\n unsMqttProxy.event.on(\"unsProxyProducedTopics\", (event) => {\n this.processMqttProxy.publish(event.statusTopic, JSON.stringify(event.producedTopics));\n });\n\n // Listen for UNS proxy status events and publish them via MQTT.\n unsMqttProxy.event.on(\"mqttProxyStatus\", (event) => {\n const time = UnsPacket.formatToISO8601(new Date());\n const unsMessage: IUnsMessage = { data: { time, value: event.value, uom: event.uom } };\n UnsPacket.unsPacketFromUnsMessage(unsMessage).then((packet) => {\n this.processMqttProxy.publish(event.statusTopic, JSON.stringify(packet));\n });\n });\n\n this.unsMqttProxies.push(unsMqttProxy);\n return unsMqttProxy;\n }\n\n public async waitForProcessConnection(): Promise<void> {\n while (!this.processMqttProxy?.isConnected) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n\n /**\n * Publishes retained product/system service metadata for controller discovery.\n *\n * The payload is intentionally separate from the volatile active/alive status\n * topics. Controllers can combine this retained identity/capability metadata\n * with live process status to decide whether a service is currently healthy.\n */\n public async publishServiceMetadata(metadata: UnsServiceMetadataInput): Promise<UnsServiceMetadata> {\n await this.waitForProcessConnection();\n const resolved = buildUnsServiceMetadata({\n processName: this.processName,\n processId: this.processId,\n metadata,\n });\n await this.processMqttProxy.publish(this.serviceMetadataTopic, JSON.stringify(resolved), { retain: true });\n return resolved;\n }\n\n /** Call after application input handlers and shutdown hooks are prepared. */\n public enableMigrationDrain(): void {\n const registry = globalThis as unknown as Record<symbol, unknown>;\n if (this.migrationDrainHandler) return;\n if (registry[MQTT_DRAIN_HANDLER]) throw Error(\"One migration drain owner is allowed per process\");\n this.migrationDrainHandler = () => this.drainForMigration();\n registry[MQTT_DRAIN_HANDLER] = this.migrationDrainHandler;\n (process as unknown as { emit(event: string, value: unknown): boolean }).emit(MQTT_DRAIN_READY_EVENT, { protocol: 1 });\n }\n\n /** Works without a Controller too; success means confirmed empty output and closed owners. */\n public drainForMigration(timeoutMs = this.handoverShutdown?.timeoutMs ?? 30_000): Promise<MqttDrainReceipt> {\n if (this.migrationDrainPromise) return this.migrationDrainPromise;\n this.migrationDrainPromise = (async () => {\n const receipt = await drainMqttForMigration({\n quiesce: async () => {\n this.handoverShutdown?.onRelease?.();\n await Promise.all(this.unsMqttProxies.map(proxy => proxy.setSubscriberPassiveAndDrainQueue()));\n },\n finishAccepted: async () => { await this.handoverShutdown?.drain(); },\n outputs: this.unsMqttProxies,\n timeoutMs,\n });\n await this.shutdown({ drain: true, timeoutMs });\n return receipt;\n })().catch(error => { this.migrationDrainPromise = null; throw error; });\n return this.migrationDrainPromise;\n }\n\n /** Stop process timers, status publication and all owned MQTT proxies. */\n public shutdown(options: UnsMqttProxyStopOptions = {}): Promise<void> {\n if (this.shutdownPromise) {\n return this.shutdownPromise;\n }\n\n this.shutdownPromise = this.performShutdown(options);\n return this.shutdownPromise;\n }\n\n private async performShutdown(options: UnsMqttProxyStopOptions): Promise<void> {\n logger.info(`${this.processName} - Shutting down UnsProxyProcess...`);\n const shutdownErrors: Error[] = [];\n\n try {\n this.statusMonitor.stop();\n await this.statusMonitor.publishInactiveStatus();\n } catch (e: any) {\n const reason = e instanceof Error ? e : new Error(String(e));\n logger.error(`${this.processName} - Error stopping StatusMonitor or publishing passive state: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n\n if (this.mqttInputHandler) {\n try {\n this.processMqttProxy.event.off(\"input\", this.mqttInputHandler);\n } catch (e: any) {\n const reason = e instanceof Error ? e : new Error(String(e));\n logger.error(`${this.processName} - Error removing MQTT input handler: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n }\n\n const proxyStopResults = await Promise.allSettled(this.unsMqttProxies.map((proxy) => proxy.stop(options)));\n for (const result of proxyStopResults) {\n if (result.status === \"rejected\") {\n const reason = result.reason instanceof Error ? result.reason : new Error(String(result.reason));\n logger.error(`${this.processName} - Error stopping UNS MQTT proxy: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n }\n\n try {\n if (typeof this.processMqttProxy.stop === \"function\") {\n await this.processMqttProxy.stop();\n }\n } catch (e: any) {\n const reason = e instanceof Error ? e : new Error(String(e));\n logger.error(`${this.processName} - Error stopping MQTT proxy: ${reason.message}`);\n shutdownErrors.push(reason);\n }\n\n if (shutdownErrors.length > 0) {\n throw new AggregateError(shutdownErrors, `${this.processName} - Shutdown completed with errors.`);\n }\n\n if (this.migrationDrainHandler) {\n const registry = globalThis as unknown as Record<symbol, unknown>;\n if (registry[MQTT_DRAIN_HANDLER] === this.migrationDrainHandler) delete registry[MQTT_DRAIN_HANDLER];\n process.channel?.unref();\n }\n logger.info(`${this.processName} - Shutdown complete.`);\n }\n}\n\ninterface UnsProxyProcess {}\n\nexport default UnsProxyProcess;\nexport type { UnsServiceMetadata, UnsServiceMetadataInput };\nexport { UnsProxyProcess };\n"]}
@@ -293,6 +293,7 @@ export declare const baseSchema: z.ZodObject<{
293
293
  key: z.ZodOptional<z.ZodString>;
294
294
  servername: z.ZodOptional<z.ZodString>;
295
295
  publishQueue: z.ZodOptional<z.ZodObject<{
296
+ enabled: z.ZodDefault<z.ZodBoolean>;
296
297
  mode: z.ZodEnum<{
297
298
  buffered: "buffered";
298
299
  durable: "durable";
@@ -1 +1 @@
1
- {"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../src/uns-config/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8CAAmE,CAAC;AAG3F,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../src/uns-config/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8CAAmE,CAAC;AAG3F,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
@@ -208,6 +208,7 @@ export declare const mqttOutputChannelSchema: z.ZodObject<{
208
208
  key: z.ZodOptional<z.ZodString>;
209
209
  servername: z.ZodOptional<z.ZodString>;
210
210
  publishQueue: z.ZodOptional<z.ZodObject<{
211
+ enabled: z.ZodDefault<z.ZodBoolean>;
211
212
  mode: z.ZodEnum<{
212
213
  buffered: "buffered";
213
214
  durable: "durable";
@@ -522,6 +523,7 @@ export declare const unsCoreSchema: z.ZodObject<{
522
523
  key: z.ZodOptional<z.ZodString>;
523
524
  servername: z.ZodOptional<z.ZodString>;
524
525
  publishQueue: z.ZodOptional<z.ZodObject<{
526
+ enabled: z.ZodDefault<z.ZodBoolean>;
525
527
  mode: z.ZodEnum<{
526
528
  buffered: "buffered";
527
529
  durable: "durable";
@@ -1 +1 @@
1
- {"version":3,"file":"uns-core-schema.d.ts","sourceRoot":"","sources":["../../src/uns-config/uns-core-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2DxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgC3B,CAAC;AAEJ,wFAAwF;AACxF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAEzB,CAAC;AAEZ,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0Cf,CAAC;AAEZ,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
1
+ {"version":3,"file":"uns-core-schema.d.ts","sourceRoot":"","sources":["../../src/uns-config/uns-core-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2DxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgC3B,CAAC;AAEJ,wFAAwF;AACxF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAEzB,CAAC;AAEZ,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0Cf,CAAC;AAEZ,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { MqttPublishQueueOptions } from "./publish-queue-contract.js";
2
+ /** Disabling persistence is not permission to hide retained output or a live owner. */
3
+ export declare function assertDisabledPublishQueueEmpty(config: MqttPublishQueueOptions, identity: string): void;
4
+ /** Host preflight may prove emptiness; the launching SDK still verifies its exact identity. */
5
+ export declare function assertRetainedPublishQueueEmpty(config: MqttPublishQueueOptions, identity?: string): void;
6
+ //# sourceMappingURL=disabled-publish-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled-publish-queue.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/disabled-publish-queue.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAE3E,uFAAuF;AACvF,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGvG;AAED,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,uBAAuB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAmCxG"}
@@ -0,0 +1,64 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createRequire } from "node:module";
3
+ import { lstatSync, readdirSync } from "node:fs";
4
+ import path from "node:path";
5
+ /** Disabling persistence is not permission to hide retained output or a live owner. */
6
+ export function assertDisabledPublishQueueEmpty(config, identity) {
7
+ if (config.enabled !== false)
8
+ return;
9
+ assertRetainedPublishQueueEmpty(config, identity);
10
+ }
11
+ /** Host preflight may prove emptiness; the launching SDK still verifies its exact identity. */
12
+ export function assertRetainedPublishQueueEmpty(config, identity) {
13
+ if (!path.isAbsolute(config.directory) || path.parse(config.directory).root === config.directory)
14
+ throw Error("Disabled MQTT queue still requires a dedicated absolute directory");
15
+ for (let p = config.directory; p !== path.dirname(p); p = path.dirname(p)) {
16
+ try {
17
+ if (lstatSync(p).isSymbolicLink())
18
+ throw Error("Unsafe disabled MQTT queue path");
19
+ }
20
+ catch (e) {
21
+ if (e.code !== "ENOENT")
22
+ throw e;
23
+ }
24
+ }
25
+ let entries;
26
+ try {
27
+ const s = lstatSync(config.directory);
28
+ if (!s.isDirectory() || s.mode & 0o077 || (process.getuid && s.uid !== process.getuid()))
29
+ throw Error("Retained disabled MQTT queue directory is unsafe");
30
+ entries = readdirSync(config.directory);
31
+ }
32
+ catch (e) {
33
+ if (e.code === "ENOENT")
34
+ return;
35
+ throw e;
36
+ }
37
+ if (!entries.length)
38
+ return;
39
+ const allowed = new Set(["mqtt-outbox.sqlite", "mqtt-outbox.sqlite-wal", "mqtt-outbox.sqlite-shm", "mqtt-outbox-owner.sqlite", "mqtt-outbox-owner.sqlite-journal"]);
40
+ if (entries.some(name => !allowed.has(name)) || !entries.includes("mqtt-outbox.sqlite") || !entries.includes("mqtt-outbox-owner.sqlite"))
41
+ throw Error("Unknown retained MQTT state; disabling is blocked");
42
+ for (const name of entries) {
43
+ const s = lstatSync(path.join(config.directory, name));
44
+ if (!s.isFile() || s.isSymbolicLink() || s.nlink !== 1 || s.mode & 0o077 || (process.getuid && s.uid !== process.getuid()))
45
+ throw Error("Unsafe retained MQTT output file");
46
+ }
47
+ const { DatabaseSync: Sqlite } = createRequire(import.meta.url)("node:sqlite");
48
+ let lease, db;
49
+ try {
50
+ lease = new Sqlite(path.join(config.directory, "mqtt-outbox-owner.sqlite"), { readOnly: true });
51
+ lease.exec("PRAGMA busy_timeout=0; BEGIN EXCLUSIVE");
52
+ db = new Sqlite(path.join(config.directory, "mqtt-outbox.sqlite"), { readOnly: true });
53
+ const metadata = db.prepare("SELECT value FROM metadata WHERE key=?");
54
+ if (!["1", "2"].includes(String(metadata.get("schema")?.value)) || (identity !== undefined ? metadata.get("identity")?.value !== createHash("sha256").update(identity).digest("hex") : !/^[a-f0-9]{64}$/.test(String(metadata.get("identity")?.value))))
55
+ throw Error("Retained MQTT output identity differs; disabling is blocked");
56
+ if (Number(db.prepare("SELECT COUNT(*) AS n FROM pending").get()?.n) !== 0)
57
+ throw Error("Retained MQTT output is not empty; drain it with its original owner before disabling");
58
+ }
59
+ finally {
60
+ db?.close();
61
+ lease?.close();
62
+ }
63
+ }
64
+ //# sourceMappingURL=disabled-publish-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disabled-publish-queue.js","sourceRoot":"","sources":["../../src/uns-mqtt/disabled-publish-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport { lstatSync, readdirSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport type { MqttPublishQueueOptions } from \"./publish-queue-contract.js\";\n\n/** Disabling persistence is not permission to hide retained output or a live owner. */\nexport function assertDisabledPublishQueueEmpty(config: MqttPublishQueueOptions, identity: string): void {\n if (config.enabled !== false) return;\n assertRetainedPublishQueueEmpty(config, identity);\n}\n\n/** Host preflight may prove emptiness; the launching SDK still verifies its exact identity. */\nexport function assertRetainedPublishQueueEmpty(config: MqttPublishQueueOptions, identity?: string): void {\n if (!path.isAbsolute(config.directory) || path.parse(config.directory).root === config.directory)\n throw Error(\"Disabled MQTT queue still requires a dedicated absolute directory\");\n for (let p = config.directory; p !== path.dirname(p); p = path.dirname(p)) {\n try { if (lstatSync(p).isSymbolicLink()) throw Error(\"Unsafe disabled MQTT queue path\"); }\n catch (e) { if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e; }\n }\n let entries: string[];\n try {\n const s = lstatSync(config.directory);\n if (!s.isDirectory() || s.mode & 0o077 || (process.getuid && s.uid !== process.getuid()))\n throw Error(\"Retained disabled MQTT queue directory is unsafe\");\n entries = readdirSync(config.directory);\n } catch (e) { if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return; throw e; }\n if (!entries.length) return;\n const allowed = new Set([\"mqtt-outbox.sqlite\", \"mqtt-outbox.sqlite-wal\", \"mqtt-outbox.sqlite-shm\", \"mqtt-outbox-owner.sqlite\", \"mqtt-outbox-owner.sqlite-journal\"]);\n if (entries.some(name => !allowed.has(name)) || !entries.includes(\"mqtt-outbox.sqlite\") || !entries.includes(\"mqtt-outbox-owner.sqlite\"))\n throw Error(\"Unknown retained MQTT state; disabling is blocked\");\n for (const name of entries) {\n const s = lstatSync(path.join(config.directory, name));\n if (!s.isFile() || s.isSymbolicLink() || s.nlink !== 1 || s.mode & 0o077 || (process.getuid && s.uid !== process.getuid()))\n throw Error(\"Unsafe retained MQTT output file\");\n }\n const { DatabaseSync: Sqlite } = createRequire(import.meta.url)(\"node:sqlite\") as typeof import(\"node:sqlite\");\n let lease: DatabaseSync | undefined, db: DatabaseSync | undefined;\n try {\n lease = new Sqlite(path.join(config.directory, \"mqtt-outbox-owner.sqlite\"), { readOnly: true });\n lease.exec(\"PRAGMA busy_timeout=0; BEGIN EXCLUSIVE\");\n db = new Sqlite(path.join(config.directory, \"mqtt-outbox.sqlite\"), { readOnly: true });\n const metadata = db.prepare(\"SELECT value FROM metadata WHERE key=?\");\n if (![\"1\", \"2\"].includes(String(metadata.get(\"schema\")?.value)) || (identity !== undefined ? metadata.get(\"identity\")?.value !== createHash(\"sha256\").update(identity).digest(\"hex\") : !/^[a-f0-9]{64}$/.test(String(metadata.get(\"identity\")?.value))))\n throw Error(\"Retained MQTT output identity differs; disabling is blocked\");\n if (Number(db.prepare(\"SELECT COUNT(*) AS n FROM pending\").get()?.n) !== 0)\n throw Error(\"Retained MQTT output is not empty; drain it with its original owner before disabling\");\n } finally { db?.close(); lease?.close(); }\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  /** Opt-in output buffering; absence preserves the issued MQTT publisher. */
3
3
  export declare const mqttPublishQueueSchema: z.ZodObject<{
4
+ enabled: z.ZodDefault<z.ZodBoolean>;
4
5
  mode: z.ZodEnum<{
5
6
  buffered: "buffered";
6
7
  durable: "durable";
@@ -34,4 +35,14 @@ export type MqttPublishQueueStatus = {
34
35
  retries: number;
35
36
  lastError: string | null;
36
37
  };
38
+ export declare function isMqttPublishQueueEnabled(value: MqttPublishQueueOptions | undefined): boolean;
39
+ /** Stable queue owner/destination. Keep byte-compatible with issued schema-2 outboxes. */
40
+ export declare function mqttPublishQueueIdentity(packageName: string, owner: string, channel: {
41
+ host: string;
42
+ port?: number | undefined;
43
+ protocol?: string | undefined;
44
+ mqttSSL?: boolean | undefined;
45
+ hosts?: unknown;
46
+ servers?: unknown;
47
+ }): string;
37
48
  //# sourceMappingURL=publish-queue-contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"publish-queue-contract.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4EAA4E;AAC5E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;kBAexB,CAAC;AACZ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC7E,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC"}
1
+ {"version":3,"file":"publish-queue-contract.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4EAA4E;AAC5E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;kBAgBxB,CAAC;AACZ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC7E,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9D,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAE7F;AAED,0FAA0F;AAC1F,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,MAAM,CAUR"}
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  /** Opt-in output buffering; absence preserves the issued MQTT publisher. */
3
3
  export const mqttPublishQueueSchema = z
4
4
  .object({
5
+ enabled: z.boolean().default(true),
5
6
  mode: z.enum(["buffered", "durable"]),
6
7
  storage: z.enum(["local", "runtime"]).default("local"),
7
8
  directory: z.string().min(1),
@@ -16,4 +17,19 @@ export const mqttPublishQueueSchema = z
16
17
  publishTimeoutMs: z.number().int().min(10).max(60000).default(10000),
17
18
  })
18
19
  .strict();
20
+ export function isMqttPublishQueueEnabled(value) {
21
+ return value !== undefined && value.enabled !== false;
22
+ }
23
+ /** Stable queue owner/destination. Keep byte-compatible with issued schema-2 outboxes. */
24
+ export function mqttPublishQueueIdentity(packageName, owner, channel) {
25
+ return JSON.stringify({
26
+ package: packageName,
27
+ owner,
28
+ host: channel.host,
29
+ port: channel.port ?? (channel.mqttSSL ? 8883 : 1883),
30
+ protocol: channel.protocol ?? (channel.mqttSSL ? "mqtts" : "mqtt"),
31
+ hosts: channel.hosts ?? null,
32
+ servers: channel.servers ?? null,
33
+ });
34
+ }
19
35
  //# sourceMappingURL=publish-queue-contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"publish-queue-contract.js","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC9D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAClE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAC9D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACnE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACrE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC9E,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACvE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;CACrE,CAAC;KACD,MAAM,EAAE,CAAC","sourcesContent":["import { z } from \"zod\";\n\n/** Opt-in output buffering; absence preserves the issued MQTT publisher. */\nexport const mqttPublishQueueSchema = z\n .object({\n mode: z.enum([\"buffered\", \"durable\"]),\n storage: z.enum([\"local\", \"runtime\"]).default(\"local\"),\n directory: z.string().min(1),\n maxRecords: z.number().int().min(1).max(100000).default(10000),\n maxBytes: z.number().int().min(1).max(536870912).default(67108864),\n memoryRecords: z.number().int().min(0).max(10000).default(256),\n memoryBytes: z.number().int().min(0).max(67108864).default(4194304),\n maxMessageBytes: z.number().int().min(1).max(1048576).default(524288),\n maxDiskBytes: z.number().int().min(1048576).max(1073741824).default(268435456),\n minFreeBytes: z.number().int().min(0).max(1073741824).default(16777216),\n retryIntervalMs: z.number().int().min(10).max(60000).default(1000),\n publishTimeoutMs: z.number().int().min(10).max(60000).default(10000),\n })\n .strict();\nexport type MqttPublishQueueOptions = z.input<typeof mqttPublishQueueSchema>;\nexport type ResolvedMqttPublishQueueOptions = z.output<typeof mqttPublishQueueSchema>;\nexport type MqttPublishQueueStatus = {\n mode: \"buffered\" | \"durable\";\n state: \"idle\" | \"pending\" | \"retrying\" | \"blocked\" | \"closed\";\n pendingRecords: number;\n pendingBytes: number;\n memoryRecords: number;\n diskRecords: number;\n inFlight: boolean;\n delivered: number;\n retries: number;\n lastError: string | null;\n};\n"]}
1
+ {"version":3,"file":"publish-queue-contract.js","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC9D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAClE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAC9D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACnE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACrE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC9E,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACvE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;CACrE,CAAC;KACD,MAAM,EAAE,CAAC;AAgBZ,MAAM,UAAU,yBAAyB,CAAC,KAA0C;IAClF,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC;AACxD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,KAAa,EACb,OAOC;IAED,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,OAAO,EAAE,WAAW;QACpB,KAAK;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACrD,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAClE,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;KACjC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { z } from \"zod\";\n\n/** Opt-in output buffering; absence preserves the issued MQTT publisher. */\nexport const mqttPublishQueueSchema = z\n .object({\n enabled: z.boolean().default(true),\n mode: z.enum([\"buffered\", \"durable\"]),\n storage: z.enum([\"local\", \"runtime\"]).default(\"local\"),\n directory: z.string().min(1),\n maxRecords: z.number().int().min(1).max(100000).default(10000),\n maxBytes: z.number().int().min(1).max(536870912).default(67108864),\n memoryRecords: z.number().int().min(0).max(10000).default(256),\n memoryBytes: z.number().int().min(0).max(67108864).default(4194304),\n maxMessageBytes: z.number().int().min(1).max(1048576).default(524288),\n maxDiskBytes: z.number().int().min(1048576).max(1073741824).default(268435456),\n minFreeBytes: z.number().int().min(0).max(1073741824).default(16777216),\n retryIntervalMs: z.number().int().min(10).max(60000).default(1000),\n publishTimeoutMs: z.number().int().min(10).max(60000).default(10000),\n })\n .strict();\nexport type MqttPublishQueueOptions = z.input<typeof mqttPublishQueueSchema>;\nexport type ResolvedMqttPublishQueueOptions = z.output<typeof mqttPublishQueueSchema>;\nexport type MqttPublishQueueStatus = {\n mode: \"buffered\" | \"durable\";\n state: \"idle\" | \"pending\" | \"retrying\" | \"blocked\" | \"closed\";\n pendingRecords: number;\n pendingBytes: number;\n memoryRecords: number;\n diskRecords: number;\n inFlight: boolean;\n delivered: number;\n retries: number;\n lastError: string | null;\n};\n\nexport function isMqttPublishQueueEnabled(value: MqttPublishQueueOptions | undefined): boolean {\n return value !== undefined && value.enabled !== false;\n}\n\n/** Stable queue owner/destination. Keep byte-compatible with issued schema-2 outboxes. */\nexport function mqttPublishQueueIdentity(\n packageName: string,\n owner: string,\n channel: {\n host: string;\n port?: number | undefined;\n protocol?: string | undefined;\n mqttSSL?: boolean | undefined;\n hosts?: unknown;\n servers?: unknown;\n },\n): string {\n return JSON.stringify({\n package: packageName,\n owner,\n host: channel.host,\n port: channel.port ?? (channel.mqttSSL ? 8883 : 1883),\n protocol: channel.protocol ?? (channel.mqttSSL ? \"mqtts\" : \"mqtt\"),\n hosts: channel.hosts ?? null,\n servers: channel.servers ?? null,\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"publish-queue.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,MAAM,CAAC;AAElD,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAA0B,MAAM,6BAA6B,CAAC;AAChI,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAErF,iGAAiG;AACjG,qBAAa,gBAAgB;IAmBzB,OAAO,CAAC,IAAI;IAEZ,OAAO,CAAC,OAAO;IApBjB,OAAO,CAAC,MAAM,CAAC;IACf,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAA8E;IACjG,OAAO,CAAC,OAAO,CAA4G;IAC3H,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,UAAU,CAA4C;IAC9D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAoB;gBAGjC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,MAAM,EACR,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,EACtD,MAAM,UAAO,EACL,OAAO,GAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAe;IActE,sFAAsF;IACtF,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmC1G,QAAQ,IAAI,sBAAsB;IAuBlC,QAAQ,IAAI,OAAO;IAGnB,YAAY,CAAC,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKvE,aAAa,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAUvF,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C,kFAAkF;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B,OAAO,CAAC,QAAQ;YAcF,GAAG;IAiCjB,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,IAAI;CAUb"}
1
+ {"version":3,"file":"publish-queue.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,MAAM,CAAC;AAElD,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAA0B,MAAM,6BAA6B,CAAC;AAChI,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAErF,iGAAiG;AACjG,qBAAa,gBAAgB;IAmBzB,OAAO,CAAC,IAAI;IAEZ,OAAO,CAAC,OAAO;IApBjB,OAAO,CAAC,MAAM,CAAC;IACf,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAA8E;IACjG,OAAO,CAAC,OAAO,CAA4G;IAC3H,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,UAAU,CAA4C;IAC9D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAoB;gBAGjC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,MAAM,EACR,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,EACtD,MAAM,UAAO,EACL,OAAO,GAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAe;IAetE,sFAAsF;IACtF,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmC1G,QAAQ,IAAI,sBAAsB;IAuBlC,QAAQ,IAAI,OAAO;IAGnB,YAAY,CAAC,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKvE,aAAa,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAUvF,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C,kFAAkF;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B,OAAO,CAAC,QAAQ;YAcF,GAAG;IAiCjB,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,IAAI;CAUb"}
@@ -22,6 +22,8 @@ export class MqttPublishQueue {
22
22
  this.send = send;
23
23
  this.changed = changed;
24
24
  this.config = mqttPublishQueueSchema.parse(options);
25
+ if (!this.config.enabled)
26
+ throw Error("Disabled MQTT persistence must be resolved before constructing an outbox");
25
27
  this.store = new MqttPublishQueueStore(this.config, identity);
26
28
  const saved = this.store.summary();
27
29
  if (saved.records > this.config.maxRecords || saved.bytes > this.config.maxBytes) {
@@ -1 +1 @@
1
- {"version":3,"file":"publish-queue.js","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IClientPublishOptions } from \"mqtt\";\n\nimport { type MqttPublishQueueOptions, type MqttPublishQueueStatus, mqttPublishQueueSchema } from \"./publish-queue-contract.js\";\nimport { MqttPublishQueueStore, type PublishRecord } from \"./publish-queue-store.js\";\n\n/** MQTT output queue only. Input acknowledgement and business transforms remain caller-owned. */\nexport class MqttPublishQueue {\n private config;\n private store: MqttPublishQueueStore;\n private memory: PublishRecord[] = [];\n private completions = new Map<string, { resolve: () => void; reject: (error: Error) => void }>();\n private waiters = new Set<{ resolve: () => void; reject: (error: Error) => void; timer: ReturnType<typeof setTimeout> }>();\n private seq: number;\n private active: boolean;\n private closed = false;\n private processing: Promise<void> | undefined;\n private retryTimer: ReturnType<typeof setTimeout> | undefined;\n private delivered = 0;\n private retries = 0;\n private lastError: string | null = null;\n private blocked: Error | undefined;\n\n constructor(\n options: MqttPublishQueueOptions,\n identity: string,\n private send: (record: PublishRecord) => Promise<void>,\n active = true,\n private changed: (status: MqttPublishQueueStatus) => void = () => {},\n ) {\n this.config = mqttPublishQueueSchema.parse(options);\n this.store = new MqttPublishQueueStore(this.config, identity);\n const saved = this.store.summary();\n if (saved.records > this.config.maxRecords || saved.bytes > this.config.maxBytes) {\n this.store.close();\n throw Error(\"Retained MQTT outbox exceeds configured limits; preserve and review it\");\n }\n this.seq = saved.lastSeq;\n this.active = active;\n this.schedule();\n }\n\n /** Returns only after RAM admission, or (durable mode) after a FULL SQLite commit. */\n enqueueOrThrow(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n if (this.closed || this.blocked) throw this.blocked ?? Error(\"MQTT publish queue is closed\");\n if (this.completions.has(id)) throw Error(\"Duplicate MQTT queue admission id\");\n if (\n !topic ||\n topic.includes(\"\\0\") ||\n /[+#]/.test(topic) ||\n Buffer.byteLength(topic) > 65535 ||\n typeof message !== \"string\" ||\n !id ||\n id.length > 200\n )\n throw Error(\"Invalid MQTT publish envelope\");\n if (options && Object.keys(options).some((key) => ![\"qos\", \"retain\"].includes(key)))\n throw Error(\"Persistent MQTT output currently supports only qos and retain publish options\");\n const qos = options?.qos ?? 1;\n if (qos !== 1 && qos !== 2) throw Error(\"Persistent MQTT output requires QoS 1 or 2 broker acknowledgement\");\n const bytes = Buffer.byteLength(topic) + Buffer.byteLength(message) + 256;\n if (bytes > this.config.maxMessageBytes) throw Error(\"MQTT publish exceeds maxMessageBytes\");\n const total = this.snapshot();\n if (total.pendingRecords >= this.config.maxRecords || total.pendingBytes + bytes > this.config.maxBytes)\n throw Error(\"MQTT publish queue capacity reached; admission rejected\");\n const record: PublishRecord = { seq: ++this.seq, id, topic, message, options: { qos, retain: options?.retain ?? false }, bytes };\n if (\n this.config.mode === \"durable\" ||\n this.memory.length >= this.config.memoryRecords ||\n this.memory.reduce((sum, r) => sum + r.bytes, 0) + bytes > this.config.memoryBytes\n )\n this.store.put(record);\n else this.memory.push(record);\n const delivered = new Promise<void>((resolve, reject) => this.completions.set(id, { resolve, reject }));\n this.emit();\n this.schedule();\n return delivered;\n }\n snapshot(): MqttPublishQueueStatus {\n const disk = this.store.summary();\n return {\n mode: this.config.mode,\n state: this.closed\n ? \"closed\"\n : this.blocked\n ? \"blocked\"\n : this.retryTimer\n ? \"retrying\"\n : disk.records + this.memory.length\n ? \"pending\"\n : \"idle\",\n pendingRecords: disk.records + this.memory.length,\n pendingBytes: disk.bytes + this.memory.reduce((sum, r) => sum + r.bytes, 0),\n memoryRecords: this.memory.length,\n diskRecords: disk.records,\n inFlight: !!this.processing,\n delivered: this.delivered,\n retries: this.retries,\n lastError: this.lastError,\n };\n }\n getState(): boolean {\n return this.active;\n }\n becomeActive(snapshot?: { batchSize?: number; referenceHash?: string }): void {\n if (snapshot?.batchSize) throw Error(\"Persistent MQTT output cannot discard work using legacy handover hashes\");\n this.active = true;\n this.schedule();\n }\n async becomePassive(_n?: number): Promise<{ batchSize: number; referenceHash: string }> {\n this.active = false;\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n await this.processing;\n this.emit();\n return { batchSize: 0, referenceHash: \"\" };\n }\n waitForIdle(timeoutMs: number): Promise<void> {\n if (this.blocked) return Promise.reject(this.blocked);\n if (!this.snapshot().pendingRecords && !this.processing) return Promise.resolve();\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return Promise.reject(Error(\"MQTT drain timeout must be positive and finite\"));\n return new Promise((resolve, reject) => {\n const waiter = {\n resolve,\n reject,\n timer: setTimeout(() => {\n this.waiters.delete(waiter);\n reject(Error(\"MQTT publish queue drain timed out; pending work retained\"));\n }, timeoutMs),\n };\n this.waiters.add(waiter);\n });\n }\n /** Caller must stop its MQTT transport first to release any in-flight publish. */\n async close(): Promise<void> {\n if (this.closed) return;\n this.active = false;\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n await this.processing;\n // Persist all buffered work before releasing the storage lease. Failure leaves it open.\n while (this.memory.length) {\n this.store.put(this.memory[0]);\n this.memory.shift();\n }\n this.closed = true;\n const stopped = Error(\"MQTT output stopped; undelivered work retained on disk\");\n for (const completion of this.completions.values()) completion.reject(stopped);\n this.completions.clear();\n for (const waiter of this.waiters) {\n clearTimeout(waiter.timer);\n waiter.reject(stopped);\n }\n this.waiters.clear();\n this.emit();\n this.store.close();\n }\n private schedule(): void {\n if (!this.active || this.closed || this.blocked || this.processing || this.retryTimer) return;\n // Defer so enqueue acceptance is visible before the delivery callback.\n this.processing = Promise.resolve()\n .then(() => this.run())\n .catch((error) => this.fail(error))\n .finally(() => {\n this.processing = undefined;\n if (!this.closed) {\n this.emit();\n if (this.snapshot().pendingRecords) this.schedule();\n }\n });\n }\n private async run(): Promise<void> {\n while (this.active && !this.closed && !this.blocked) {\n const disk = this.store.head();\n const memory = this.memory[0];\n const record = !memory || (disk && disk.seq < memory.seq) ? disk : memory;\n if (!record) return;\n try {\n await this.send(record);\n } catch {\n // A lost acknowledgement remains uncertain; persist and replay, never mark success.\n // After an observed outage, move all already accepted RAM work to disk.\n while (this.memory.length) {\n this.store.put(this.memory[0]);\n this.memory.shift();\n }\n this.retries++;\n this.lastError = \"MQTT delivery unconfirmed; retained for retry\";\n if (this.active)\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined;\n this.schedule();\n }, this.config.retryIntervalMs);\n return;\n }\n if (record === memory) this.memory.shift();\n else this.store.complete(record);\n this.delivered++;\n this.lastError = null;\n this.completions.get(record.id)?.resolve();\n this.completions.delete(record.id);\n this.emit();\n }\n }\n private fail(reason: unknown): void {\n this.blocked = reason instanceof Error ? reason : Error(\"MQTT outbox storage failed\");\n this.lastError = \"MQTT outbox blocked; preserve storage and inspect local error\";\n for (const waiter of this.waiters) {\n clearTimeout(waiter.timer);\n waiter.reject(this.blocked);\n }\n this.waiters.clear();\n this.emit();\n }\n private emit(): void {\n this.changed(this.snapshot());\n if (!this.snapshot().pendingRecords && !this.processing) {\n for (const waiter of this.waiters) {\n clearTimeout(waiter.timer);\n waiter.resolve();\n }\n this.waiters.clear();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"publish-queue.js","sourceRoot":"","sources":["../../src/uns-mqtt/publish-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IClientPublishOptions } from \"mqtt\";\n\nimport { type MqttPublishQueueOptions, type MqttPublishQueueStatus, mqttPublishQueueSchema } from \"./publish-queue-contract.js\";\nimport { MqttPublishQueueStore, type PublishRecord } from \"./publish-queue-store.js\";\n\n/** MQTT output queue only. Input acknowledgement and business transforms remain caller-owned. */\nexport class MqttPublishQueue {\n private config;\n private store: MqttPublishQueueStore;\n private memory: PublishRecord[] = [];\n private completions = new Map<string, { resolve: () => void; reject: (error: Error) => void }>();\n private waiters = new Set<{ resolve: () => void; reject: (error: Error) => void; timer: ReturnType<typeof setTimeout> }>();\n private seq: number;\n private active: boolean;\n private closed = false;\n private processing: Promise<void> | undefined;\n private retryTimer: ReturnType<typeof setTimeout> | undefined;\n private delivered = 0;\n private retries = 0;\n private lastError: string | null = null;\n private blocked: Error | undefined;\n\n constructor(\n options: MqttPublishQueueOptions,\n identity: string,\n private send: (record: PublishRecord) => Promise<void>,\n active = true,\n private changed: (status: MqttPublishQueueStatus) => void = () => {},\n ) {\n this.config = mqttPublishQueueSchema.parse(options);\n if (!this.config.enabled) throw Error(\"Disabled MQTT persistence must be resolved before constructing an outbox\");\n this.store = new MqttPublishQueueStore(this.config, identity);\n const saved = this.store.summary();\n if (saved.records > this.config.maxRecords || saved.bytes > this.config.maxBytes) {\n this.store.close();\n throw Error(\"Retained MQTT outbox exceeds configured limits; preserve and review it\");\n }\n this.seq = saved.lastSeq;\n this.active = active;\n this.schedule();\n }\n\n /** Returns only after RAM admission, or (durable mode) after a FULL SQLite commit. */\n enqueueOrThrow(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n if (this.closed || this.blocked) throw this.blocked ?? Error(\"MQTT publish queue is closed\");\n if (this.completions.has(id)) throw Error(\"Duplicate MQTT queue admission id\");\n if (\n !topic ||\n topic.includes(\"\\0\") ||\n /[+#]/.test(topic) ||\n Buffer.byteLength(topic) > 65535 ||\n typeof message !== \"string\" ||\n !id ||\n id.length > 200\n )\n throw Error(\"Invalid MQTT publish envelope\");\n if (options && Object.keys(options).some((key) => ![\"qos\", \"retain\"].includes(key)))\n throw Error(\"Persistent MQTT output currently supports only qos and retain publish options\");\n const qos = options?.qos ?? 1;\n if (qos !== 1 && qos !== 2) throw Error(\"Persistent MQTT output requires QoS 1 or 2 broker acknowledgement\");\n const bytes = Buffer.byteLength(topic) + Buffer.byteLength(message) + 256;\n if (bytes > this.config.maxMessageBytes) throw Error(\"MQTT publish exceeds maxMessageBytes\");\n const total = this.snapshot();\n if (total.pendingRecords >= this.config.maxRecords || total.pendingBytes + bytes > this.config.maxBytes)\n throw Error(\"MQTT publish queue capacity reached; admission rejected\");\n const record: PublishRecord = { seq: ++this.seq, id, topic, message, options: { qos, retain: options?.retain ?? false }, bytes };\n if (\n this.config.mode === \"durable\" ||\n this.memory.length >= this.config.memoryRecords ||\n this.memory.reduce((sum, r) => sum + r.bytes, 0) + bytes > this.config.memoryBytes\n )\n this.store.put(record);\n else this.memory.push(record);\n const delivered = new Promise<void>((resolve, reject) => this.completions.set(id, { resolve, reject }));\n this.emit();\n this.schedule();\n return delivered;\n }\n snapshot(): MqttPublishQueueStatus {\n const disk = this.store.summary();\n return {\n mode: this.config.mode,\n state: this.closed\n ? \"closed\"\n : this.blocked\n ? \"blocked\"\n : this.retryTimer\n ? \"retrying\"\n : disk.records + this.memory.length\n ? \"pending\"\n : \"idle\",\n pendingRecords: disk.records + this.memory.length,\n pendingBytes: disk.bytes + this.memory.reduce((sum, r) => sum + r.bytes, 0),\n memoryRecords: this.memory.length,\n diskRecords: disk.records,\n inFlight: !!this.processing,\n delivered: this.delivered,\n retries: this.retries,\n lastError: this.lastError,\n };\n }\n getState(): boolean {\n return this.active;\n }\n becomeActive(snapshot?: { batchSize?: number; referenceHash?: string }): void {\n if (snapshot?.batchSize) throw Error(\"Persistent MQTT output cannot discard work using legacy handover hashes\");\n this.active = true;\n this.schedule();\n }\n async becomePassive(_n?: number): Promise<{ batchSize: number; referenceHash: string }> {\n this.active = false;\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n await this.processing;\n this.emit();\n return { batchSize: 0, referenceHash: \"\" };\n }\n waitForIdle(timeoutMs: number): Promise<void> {\n if (this.blocked) return Promise.reject(this.blocked);\n if (!this.snapshot().pendingRecords && !this.processing) return Promise.resolve();\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return Promise.reject(Error(\"MQTT drain timeout must be positive and finite\"));\n return new Promise((resolve, reject) => {\n const waiter = {\n resolve,\n reject,\n timer: setTimeout(() => {\n this.waiters.delete(waiter);\n reject(Error(\"MQTT publish queue drain timed out; pending work retained\"));\n }, timeoutMs),\n };\n this.waiters.add(waiter);\n });\n }\n /** Caller must stop its MQTT transport first to release any in-flight publish. */\n async close(): Promise<void> {\n if (this.closed) return;\n this.active = false;\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = undefined;\n }\n await this.processing;\n // Persist all buffered work before releasing the storage lease. Failure leaves it open.\n while (this.memory.length) {\n this.store.put(this.memory[0]);\n this.memory.shift();\n }\n this.closed = true;\n const stopped = Error(\"MQTT output stopped; undelivered work retained on disk\");\n for (const completion of this.completions.values()) completion.reject(stopped);\n this.completions.clear();\n for (const waiter of this.waiters) {\n clearTimeout(waiter.timer);\n waiter.reject(stopped);\n }\n this.waiters.clear();\n this.emit();\n this.store.close();\n }\n private schedule(): void {\n if (!this.active || this.closed || this.blocked || this.processing || this.retryTimer) return;\n // Defer so enqueue acceptance is visible before the delivery callback.\n this.processing = Promise.resolve()\n .then(() => this.run())\n .catch((error) => this.fail(error))\n .finally(() => {\n this.processing = undefined;\n if (!this.closed) {\n this.emit();\n if (this.snapshot().pendingRecords) this.schedule();\n }\n });\n }\n private async run(): Promise<void> {\n while (this.active && !this.closed && !this.blocked) {\n const disk = this.store.head();\n const memory = this.memory[0];\n const record = !memory || (disk && disk.seq < memory.seq) ? disk : memory;\n if (!record) return;\n try {\n await this.send(record);\n } catch {\n // A lost acknowledgement remains uncertain; persist and replay, never mark success.\n // After an observed outage, move all already accepted RAM work to disk.\n while (this.memory.length) {\n this.store.put(this.memory[0]);\n this.memory.shift();\n }\n this.retries++;\n this.lastError = \"MQTT delivery unconfirmed; retained for retry\";\n if (this.active)\n this.retryTimer = setTimeout(() => {\n this.retryTimer = undefined;\n this.schedule();\n }, this.config.retryIntervalMs);\n return;\n }\n if (record === memory) this.memory.shift();\n else this.store.complete(record);\n this.delivered++;\n this.lastError = null;\n this.completions.get(record.id)?.resolve();\n this.completions.delete(record.id);\n this.emit();\n }\n }\n private fail(reason: unknown): void {\n this.blocked = reason instanceof Error ? reason : Error(\"MQTT outbox storage failed\");\n this.lastError = \"MQTT outbox blocked; preserve storage and inspect local error\";\n for (const waiter of this.waiters) {\n clearTimeout(waiter.timer);\n waiter.reject(this.blocked);\n }\n this.waiters.clear();\n this.emit();\n }\n private emit(): void {\n this.changed(this.snapshot());\n if (!this.snapshot().pendingRecords && !this.processing) {\n for (const waiter of this.waiters) {\n clearTimeout(waiter.timer);\n waiter.resolve();\n }\n this.waiters.clear();\n }\n }\n}\n"]}
@@ -37,6 +37,7 @@ export default class UnsMqttProxy extends UnsProxy {
37
37
  private stopPromise;
38
38
  private expectedWorkerExit;
39
39
  private publishQueueStatus?;
40
+ private publishesSealed;
40
41
  private admissionBytes;
41
42
  private pendingAdmissionBytes;
42
43
  private queueRequests;
@@ -145,6 +146,8 @@ export default class UnsMqttProxy extends UnsProxy {
145
146
  */
146
147
  stop(options?: UnsMqttProxyStopOptions): Promise<void>;
147
148
  private performStop;
149
+ /** A completed migration owns this fence until the original process exits. */
150
+ sealPublishes(): void;
148
151
  getPublishQueueStatus(): MqttPublishQueueStatus | undefined;
149
152
  private requestPublishQueue;
150
153
  private failPendingPublishes;
@@ -1 +1 @@
1
- {"version":3,"file":"uns-mqtt-proxy.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/uns-mqtt-proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"uns-mqtt-proxy.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/uns-mqtt-proxy.ts"],"names":[],"mappings":"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"}