@uns-kit/core 3.0.34 → 3.0.35

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 (37) hide show
  1. package/MIGRATIONS.md +25 -0
  2. package/dist/config/app-config.d.ts +1 -1
  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-handover-state.d.ts +48 -0
  6. package/dist/runtime/mqtt-handover-state.d.ts.map +1 -0
  7. package/dist/runtime/mqtt-handover-state.js +61 -0
  8. package/dist/runtime/mqtt-handover-state.js.map +1 -0
  9. package/dist/uns/handover-manager.d.ts +10 -1
  10. package/dist/uns/handover-manager.d.ts.map +1 -1
  11. package/dist/uns/handover-manager.js +113 -5
  12. package/dist/uns/handover-manager.js.map +1 -1
  13. package/dist/uns/uns-interfaces.d.ts +4 -0
  14. package/dist/uns/uns-interfaces.d.ts.map +1 -1
  15. package/dist/uns/uns-interfaces.js.map +1 -1
  16. package/dist/uns/uns-proxy-process.d.ts +1 -0
  17. package/dist/uns/uns-proxy-process.d.ts.map +1 -1
  18. package/dist/uns/uns-proxy-process.js +6 -2
  19. package/dist/uns/uns-proxy-process.js.map +1 -1
  20. package/dist/uns-config/config-schema.d.ts +4 -1
  21. package/dist/uns-config/config-schema.d.ts.map +1 -1
  22. package/dist/uns-config/uns-core-schema.d.ts +4 -1
  23. package/dist/uns-config/uns-core-schema.d.ts.map +1 -1
  24. package/dist/uns-config/uns-core-schema.js +1 -1
  25. package/dist/uns-config/uns-core-schema.js.map +1 -1
  26. package/dist/uns-mqtt/mqtt-worker.d.ts.map +1 -1
  27. package/dist/uns-mqtt/mqtt-worker.js +13 -1
  28. package/dist/uns-mqtt/mqtt-worker.js.map +1 -1
  29. package/dist/uns-mqtt/throttled-queue.d.ts +8 -1
  30. package/dist/uns-mqtt/throttled-queue.d.ts.map +1 -1
  31. package/dist/uns-mqtt/throttled-queue.js +32 -4
  32. package/dist/uns-mqtt/throttled-queue.js.map +1 -1
  33. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +20 -2
  34. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts.map +1 -1
  35. package/dist/uns-mqtt/uns-mqtt-proxy.js +68 -6
  36. package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
  37. package/package.json +1 -1
package/MIGRATIONS.md CHANGED
@@ -9,6 +9,31 @@ Agents must inspect the application's existing ownership and shutdown flow
9
9
  before editing it. The examples below describe the intended behavior, not a
10
10
  mechanical search-and-replace operation.
11
11
 
12
+ ## 3.0.35 - Opt-in state-preserving MQTT handover
13
+
14
+ When crossing `<3.0.35` to `>=3.0.35`, existing applications keep their current
15
+ handover behavior. State continuity is opt-in: declare `mqttHandover` protocol2
16
+ and `mqttDrain` protocol1, pass `uns.handoverProtocol: "correlated-v2"` to
17
+ `UnsProxyProcess`, declare each proxy's semantic `handoverStateContract`, and
18
+ register migration drain after installing application input handlers.
19
+
20
+ Use an updated host that understands this capability and its bound drain/exit
21
+ receipt. Both peers must support the protocol; persistent output and other
22
+ runtime-owned state remain separate reviewed transfers. No package-name logic
23
+ or application callbacks may be executed by the host to inspect compatibility.
24
+
25
+ The SDK transfers its counter baselines and publication sequence state only after
26
+ accepted work and output flush. The target advertises compatibility before the
27
+ source freezes. Different destination/subscriptions/proxy sets/semantic revisions
28
+ block the handover while the source remains active. New paths start fresh;
29
+ removed paths do not erase history; changed unit/type must not reuse arithmetic
30
+ baselines. Matching path strings alone are not a compatibility guarantee.
31
+
32
+ Unknown outcomes must be reconciled under the same operation. Return ownership
33
+ with a fresh reverse handover from the current owner, never by restarting stale
34
+ RAM. This is not crash durability or universal exactly-once MQTT delivery.
35
+ See [example, protocol and limits](https://github.com/uns-openhub/uns-kit/blob/master/docs/mqtt-stateful-handover.md).
36
+
12
37
  ## 3.0.34 - Optional paired-input retirement to one direct process
13
38
 
14
39
  When crossing `<3.0.34` to `>=3.0.34`, ordinary applications require no change.
@@ -13,7 +13,7 @@ export interface ProjectAppConfig {
13
13
  processName: string;
14
14
  handover?: boolean;
15
15
  /** Opt-in controller-correlated MQTT handover protocol. */
16
- handoverProtocol?: "correlated-v1" | undefined;
16
+ handoverProtocol?: ("correlated-v1" | "correlated-v2") | undefined;
17
17
  /** Optional PM2/controller supervisor guard settings for this RTT instance. */
18
18
  supervisor?: {
19
19
  /** Enable controller/PM2 supervisor handling for this RTT instance. */
@@ -1 +1 @@
1
- {"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"","sourcesContent":["/* Auto-generated. Do not edit by hand. */\nexport interface ProjectAppConfig {\n uns: {\n graphql: string;\n rest: string;\n /** Bearer token used for service-to-service access to the UNS instance. */\n token?: string | undefined;\n /** Email used when authenticating to graphql endpoint of the UNS instance. */\n email?: string | undefined;\n /** Password or secret value paired with the UNS email. */\n password?: string | undefined;\n instanceMode?: \"wait\" | \"force\" | \"handover\";\n /** Process name used in MQTT topics and logs. */\n processName: string;\n handover?: boolean;\n /** Opt-in controller-correlated MQTT handover protocol. */\n handoverProtocol?: \"correlated-v1\" | undefined;\n /** Optional PM2/controller supervisor guard settings for this RTT instance. */\n supervisor?: {\n /** Enable controller/PM2 supervisor handling for this RTT instance. */\n enabled?: boolean;\n /** Let PM2 restart the process when it exits unexpectedly. */\n restartOnExit?: boolean;\n /** Optional PM2 memory restart limit in megabytes. */\n maxMemoryMb?: number | undefined;\n /** Let the controller auto-start this instance when required system-service runtime signals are absent. */\n restartOnUnhealthy?: boolean;\n /** How long runtime signals must stay unhealthy before the controller supervisor can act. */\n unhealthyAfterMs?: number;\n /** Minimum time between controller supervisor restart attempts for this instance. */\n restartCooldownMs?: number;\n } | undefined;\n jwksWellKnownUrl?: string | undefined;\n kidWellKnownUrl?: string | undefined;\n env?: \"dev\" | \"staging\" | \"test\" | \"prod\";\n };\n logging?: {\n adapter?: string;\n host: string;\n port?: number;\n level?: \"error\" | \"warn\" | \"info\" | \"http\" | \"verbose\" | \"debug\" | \"silly\";\n } | undefined;\n input?: {\n host?: string | undefined;\n hosts?: string[] | undefined;\n servers?: {\n host: string;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n }[] | undefined;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n username?: string | undefined;\n password?: string | undefined;\n clientId?: string | undefined;\n clean?: boolean | undefined;\n keepalive?: number | undefined;\n connectTimeout?: number | undefined;\n reconnectPeriod?: number | undefined;\n reconnectOnConnackError?: boolean | undefined;\n resubscribe?: boolean | undefined;\n queueQoSZero?: boolean | undefined;\n rejectUnauthorized?: boolean | undefined;\n properties?: {\n sessionExpiryInterval?: number | undefined;\n receiveMaximum?: number | undefined;\n maximumPacketSize?: number | undefined;\n topicAliasMaximum?: number | undefined;\n requestResponseInformation?: boolean | undefined;\n requestProblemInformation?: boolean | undefined;\n userProperties?: {\n [x: string]: string;\n } | undefined;\n } | undefined;\n ca?: string | undefined;\n cert?: string | undefined;\n key?: string | undefined;\n servername?: string | undefined;\n } | undefined;\n output?: {\n host?: string | undefined;\n hosts?: string[] | undefined;\n servers?: {\n host: string;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n }[] | undefined;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n username?: string | undefined;\n password?: string | undefined;\n clientId?: string | undefined;\n clean?: boolean | undefined;\n keepalive?: number | undefined;\n connectTimeout?: number | undefined;\n reconnectPeriod?: number | undefined;\n reconnectOnConnackError?: boolean | undefined;\n resubscribe?: boolean | undefined;\n queueQoSZero?: boolean | undefined;\n rejectUnauthorized?: boolean | undefined;\n properties?: {\n sessionExpiryInterval?: number | undefined;\n receiveMaximum?: number | undefined;\n maximumPacketSize?: number | undefined;\n topicAliasMaximum?: number | undefined;\n requestResponseInformation?: boolean | undefined;\n requestProblemInformation?: boolean | undefined;\n userProperties?: {\n [x: string]: string;\n } | undefined;\n } | undefined;\n ca?: string | undefined;\n cert?: string | undefined;\n key?: string | undefined;\n servername?: string | undefined;\n /** Opt-in MQTT output persistence; does not persist input subscriptions. */\n publishQueue?: {\n enabled?: boolean;\n mode: \"buffered\" | \"durable\";\n storage?: \"local\" | \"runtime\";\n directory: string;\n maxRecords?: number;\n maxBytes?: number;\n memoryRecords?: number;\n memoryBytes?: number;\n maxMessageBytes?: number;\n maxDiskBytes?: number;\n minFreeBytes?: number;\n retryIntervalMs?: number;\n publishTimeoutMs?: number;\n } | undefined;\n } | undefined;\n infra: {\n host?: string | undefined;\n hosts?: string[] | undefined;\n servers?: {\n host: string;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n }[] | undefined;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n username?: string | undefined;\n password?: string | undefined;\n clientId?: string | undefined;\n clean?: boolean | undefined;\n keepalive?: number | undefined;\n connectTimeout?: number | undefined;\n reconnectPeriod?: number | undefined;\n reconnectOnConnackError?: boolean | undefined;\n resubscribe?: boolean | undefined;\n queueQoSZero?: boolean | undefined;\n rejectUnauthorized?: boolean | undefined;\n properties?: {\n sessionExpiryInterval?: number | undefined;\n receiveMaximum?: number | undefined;\n maximumPacketSize?: number | undefined;\n topicAliasMaximum?: number | undefined;\n requestResponseInformation?: boolean | undefined;\n requestProblemInformation?: boolean | undefined;\n userProperties?: {\n [x: string]: string;\n } | undefined;\n } | undefined;\n ca?: string | undefined;\n cert?: string | undefined;\n key?: string | undefined;\n servername?: string | undefined;\n };\n devops?: {\n provider?: \"azure-devops\";\n organization: string;\n project?: string | undefined;\n } | undefined;\n}\n\nexport interface AppConfig extends ProjectAppConfig {}\n"]}
1
+ {"version":3,"file":"app-config.js","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"","sourcesContent":["/* Auto-generated. Do not edit by hand. */\nexport interface ProjectAppConfig {\n uns: {\n graphql: string;\n rest: string;\n /** Bearer token used for service-to-service access to the UNS instance. */\n token?: string | undefined;\n /** Email used when authenticating to graphql endpoint of the UNS instance. */\n email?: string | undefined;\n /** Password or secret value paired with the UNS email. */\n password?: string | undefined;\n instanceMode?: \"wait\" | \"force\" | \"handover\";\n /** Process name used in MQTT topics and logs. */\n processName: string;\n handover?: boolean;\n /** Opt-in controller-correlated MQTT handover protocol. */\n handoverProtocol?: (\"correlated-v1\" | \"correlated-v2\") | undefined;\n /** Optional PM2/controller supervisor guard settings for this RTT instance. */\n supervisor?: {\n /** Enable controller/PM2 supervisor handling for this RTT instance. */\n enabled?: boolean;\n /** Let PM2 restart the process when it exits unexpectedly. */\n restartOnExit?: boolean;\n /** Optional PM2 memory restart limit in megabytes. */\n maxMemoryMb?: number | undefined;\n /** Let the controller auto-start this instance when required system-service runtime signals are absent. */\n restartOnUnhealthy?: boolean;\n /** How long runtime signals must stay unhealthy before the controller supervisor can act. */\n unhealthyAfterMs?: number;\n /** Minimum time between controller supervisor restart attempts for this instance. */\n restartCooldownMs?: number;\n } | undefined;\n jwksWellKnownUrl?: string | undefined;\n kidWellKnownUrl?: string | undefined;\n env?: \"dev\" | \"staging\" | \"test\" | \"prod\";\n };\n logging?: {\n adapter?: string;\n host: string;\n port?: number;\n level?: \"error\" | \"warn\" | \"info\" | \"http\" | \"verbose\" | \"debug\" | \"silly\";\n } | undefined;\n input?: {\n host?: string | undefined;\n hosts?: string[] | undefined;\n servers?: {\n host: string;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n }[] | undefined;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n username?: string | undefined;\n password?: string | undefined;\n clientId?: string | undefined;\n clean?: boolean | undefined;\n keepalive?: number | undefined;\n connectTimeout?: number | undefined;\n reconnectPeriod?: number | undefined;\n reconnectOnConnackError?: boolean | undefined;\n resubscribe?: boolean | undefined;\n queueQoSZero?: boolean | undefined;\n rejectUnauthorized?: boolean | undefined;\n properties?: {\n sessionExpiryInterval?: number | undefined;\n receiveMaximum?: number | undefined;\n maximumPacketSize?: number | undefined;\n topicAliasMaximum?: number | undefined;\n requestResponseInformation?: boolean | undefined;\n requestProblemInformation?: boolean | undefined;\n userProperties?: {\n [x: string]: string;\n } | undefined;\n } | undefined;\n ca?: string | undefined;\n cert?: string | undefined;\n key?: string | undefined;\n servername?: string | undefined;\n } | undefined;\n output?: {\n host?: string | undefined;\n hosts?: string[] | undefined;\n servers?: {\n host: string;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n }[] | undefined;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n username?: string | undefined;\n password?: string | undefined;\n clientId?: string | undefined;\n clean?: boolean | undefined;\n keepalive?: number | undefined;\n connectTimeout?: number | undefined;\n reconnectPeriod?: number | undefined;\n reconnectOnConnackError?: boolean | undefined;\n resubscribe?: boolean | undefined;\n queueQoSZero?: boolean | undefined;\n rejectUnauthorized?: boolean | undefined;\n properties?: {\n sessionExpiryInterval?: number | undefined;\n receiveMaximum?: number | undefined;\n maximumPacketSize?: number | undefined;\n topicAliasMaximum?: number | undefined;\n requestResponseInformation?: boolean | undefined;\n requestProblemInformation?: boolean | undefined;\n userProperties?: {\n [x: string]: string;\n } | undefined;\n } | undefined;\n ca?: string | undefined;\n cert?: string | undefined;\n key?: string | undefined;\n servername?: string | undefined;\n /** Opt-in MQTT output persistence; does not persist input subscriptions. */\n publishQueue?: {\n enabled?: boolean;\n mode: \"buffered\" | \"durable\";\n storage?: \"local\" | \"runtime\";\n directory: string;\n maxRecords?: number;\n maxBytes?: number;\n memoryRecords?: number;\n memoryBytes?: number;\n maxMessageBytes?: number;\n maxDiskBytes?: number;\n minFreeBytes?: number;\n retryIntervalMs?: number;\n publishTimeoutMs?: number;\n } | undefined;\n } | undefined;\n infra: {\n host?: string | undefined;\n hosts?: string[] | undefined;\n servers?: {\n host: string;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n }[] | undefined;\n port?: number | undefined;\n protocol?: (\"mqtt\" | \"mqtts\" | \"ws\" | \"wss\" | \"tcp\" | \"ssl\") | undefined;\n username?: string | undefined;\n password?: string | undefined;\n clientId?: string | undefined;\n clean?: boolean | undefined;\n keepalive?: number | undefined;\n connectTimeout?: number | undefined;\n reconnectPeriod?: number | undefined;\n reconnectOnConnackError?: boolean | undefined;\n resubscribe?: boolean | undefined;\n queueQoSZero?: boolean | undefined;\n rejectUnauthorized?: boolean | undefined;\n properties?: {\n sessionExpiryInterval?: number | undefined;\n receiveMaximum?: number | undefined;\n maximumPacketSize?: number | undefined;\n topicAliasMaximum?: number | undefined;\n requestResponseInformation?: boolean | undefined;\n requestProblemInformation?: boolean | undefined;\n userProperties?: {\n [x: string]: string;\n } | undefined;\n } | undefined;\n ca?: string | undefined;\n cert?: string | undefined;\n key?: string | undefined;\n servername?: string | undefined;\n };\n devops?: {\n provider?: \"azure-devops\";\n organization: string;\n project?: string | undefined;\n } | undefined;\n}\n\nexport interface AppConfig extends ProjectAppConfig {}\n"]}
@@ -0,0 +1,48 @@
1
+ import { z } from 'zod';
2
+ export declare const MQTT_HANDOVER_STATE_MAX_BYTES: number;
3
+ export declare const mqttHandoverOfferSchema: z.ZodArray<z.ZodObject<{
4
+ instanceName: z.ZodString;
5
+ compatibility: z.ZodString;
6
+ }, z.core.$strict>>;
7
+ export declare const mqttProxyHandoverStateSchema: z.ZodObject<{
8
+ instanceName: z.ZodString;
9
+ compatibility: z.ZodString;
10
+ values: z.ZodArray<z.ZodObject<{
11
+ topic: z.ZodString;
12
+ value: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>]>;
13
+ uom: z.ZodString;
14
+ timestamp: z.ZodString;
15
+ }, z.core.$strict>>;
16
+ sequences: z.ZodArray<z.ZodTuple<[z.ZodString, z.ZodNumber], null>>;
17
+ cursor: z.ZodObject<{
18
+ batchSize: z.ZodNumber;
19
+ referenceHash: z.ZodString;
20
+ }, z.core.$strict>;
21
+ }, z.core.$strict>;
22
+ export declare const mqttHandoverStateSchema: z.ZodObject<{
23
+ protocol: z.ZodLiteral<1>;
24
+ proxies: z.ZodArray<z.ZodObject<{
25
+ instanceName: z.ZodString;
26
+ compatibility: z.ZodString;
27
+ values: z.ZodArray<z.ZodObject<{
28
+ topic: z.ZodString;
29
+ value: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>]>;
30
+ uom: z.ZodString;
31
+ timestamp: z.ZodString;
32
+ }, z.core.$strict>>;
33
+ sequences: z.ZodArray<z.ZodTuple<[z.ZodString, z.ZodNumber], null>>;
34
+ cursor: z.ZodObject<{
35
+ batchSize: z.ZodNumber;
36
+ referenceHash: z.ZodString;
37
+ }, z.core.$strict>;
38
+ }, z.core.$strict>>;
39
+ }, z.core.$strict>;
40
+ export type MqttProxyHandoverState = z.infer<typeof mqttProxyHandoverStateSchema>;
41
+ export type MqttHandoverState = z.infer<typeof mqttHandoverStateSchema>;
42
+ export declare function parseMqttHandoverState(input: unknown): MqttHandoverState;
43
+ export declare function mqttHandoverStateDigest(state: MqttHandoverState): string;
44
+ export declare const mqttHandoverCapabilitySchema: z.ZodObject<{
45
+ protocolVersion: z.ZodLiteral<2>;
46
+ }, z.core.$strict>;
47
+ export declare function readMqttHandoverCapability(packageRoot: string): 2 | undefined;
48
+ //# sourceMappingURL=mqtt-handover-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mqtt-handover-state.d.ts","sourceRoot":"","sources":["../../src/runtime/mqtt-handover-state.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,6BAA6B,QAAc,CAAC;AAIzD,eAAO,MAAM,uBAAuB;;;mBAG8E,CAAC;AACnH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;kBASvC,CAAC;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;kBAMlC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAClF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAIxE;AACD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAExE;AACD,eAAO,MAAM,4BAA4B;;kBAAoD,CAAC;AAC9F,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAS7E"}
@@ -0,0 +1,61 @@
1
+ import { createHash } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { z } from 'zod';
5
+ // Same contract for every SDK MQTT consumer. No application/profile selectors.
6
+ export const MQTT_HANDOVER_STATE_MAX_BYTES = 1024 * 1024;
7
+ const text = z.string().min(1).max(65535).refine(v => !v.includes('\0'));
8
+ const scalar = z.union([z.number().finite(), z.string().max(65535)]);
9
+ const value = z.union([scalar, z.array(scalar).max(4096)]);
10
+ export const mqttHandoverOfferSchema = z.array(z.strictObject({
11
+ instanceName: z.string().min(1).max(256),
12
+ compatibility: z.string().regex(/^[a-f0-9]{64}$/),
13
+ })).max(64).refine(offer => new Set(offer.map(p => p.instanceName)).size === offer.length, 'Duplicate MQTT proxy');
14
+ export const mqttProxyHandoverStateSchema = z.strictObject({
15
+ instanceName: z.string().min(1).max(256),
16
+ compatibility: z.string().regex(/^[a-f0-9]{64}$/),
17
+ values: z.array(z.strictObject({ topic: text, value, uom: z.string().max(256), timestamp: z.string().datetime() })).max(10000),
18
+ sequences: z.array(z.tuple([text, z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER)])).max(10000),
19
+ cursor: z.strictObject({ batchSize: z.number().int().min(0).max(100), referenceHash: z.string().regex(/^[a-f0-9]{64}$/) }),
20
+ }).superRefine((state, ctx) => {
21
+ for (const keys of [state.values.map(v => v.topic), state.sequences.map(v => v[0])])
22
+ if (new Set(keys).size !== keys.length)
23
+ ctx.addIssue({ code: 'custom', message: 'Duplicate MQTT state key' });
24
+ });
25
+ export const mqttHandoverStateSchema = z.strictObject({
26
+ protocol: z.literal(1),
27
+ proxies: z.array(mqttProxyHandoverStateSchema).max(64),
28
+ }).superRefine((state, ctx) => {
29
+ if (new Set(state.proxies.map(p => p.instanceName)).size !== state.proxies.length)
30
+ ctx.addIssue({ code: 'custom', message: 'Duplicate MQTT proxy' });
31
+ });
32
+ export function parseMqttHandoverState(input) {
33
+ const json = JSON.stringify(input);
34
+ if (!json || Buffer.byteLength(json) > MQTT_HANDOVER_STATE_MAX_BYTES)
35
+ throw Error('MQTT handover state exceeds its bound');
36
+ return mqttHandoverStateSchema.parse(input);
37
+ }
38
+ export function mqttHandoverStateDigest(state) {
39
+ return createHash('sha256').update(JSON.stringify(parseMqttHandoverState(state))).digest('hex');
40
+ }
41
+ export const mqttHandoverCapabilitySchema = z.strictObject({ protocolVersion: z.literal(2) });
42
+ export function readMqttHandoverCapability(packageRoot) {
43
+ const file = path.join(packageRoot, 'package.json');
44
+ let stat;
45
+ try {
46
+ stat = fs.lstatSync(file);
47
+ }
48
+ catch (error) {
49
+ if (error.code === 'ENOENT')
50
+ return undefined;
51
+ throw error;
52
+ }
53
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1048576)
54
+ throw Error('Unsafe MQTT handover descriptor');
55
+ const descriptor = JSON.parse(fs.readFileSync(file, 'utf8'))?.unsDatahub?.mqttHandover;
56
+ if (descriptor === undefined)
57
+ return undefined;
58
+ mqttHandoverCapabilitySchema.parse(descriptor);
59
+ return 2;
60
+ }
61
+ //# sourceMappingURL=mqtt-handover-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mqtt-handover-state.js","sourceRoot":"","sources":["../../src/runtime/mqtt-handover-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { z } from 'zod';\n\n// Same contract for every SDK MQTT consumer. No application/profile selectors.\nexport const MQTT_HANDOVER_STATE_MAX_BYTES = 1024 * 1024;\nconst text = z.string().min(1).max(65535).refine(v => !v.includes('\\0'));\nconst scalar = z.union([z.number().finite(), z.string().max(65535)]);\nconst value = z.union([scalar, z.array(scalar).max(4096)]);\nexport const mqttHandoverOfferSchema = z.array(z.strictObject({\n instanceName: z.string().min(1).max(256),\n compatibility: z.string().regex(/^[a-f0-9]{64}$/),\n})).max(64).refine(offer => new Set(offer.map(p => p.instanceName)).size === offer.length, 'Duplicate MQTT proxy');\nexport const mqttProxyHandoverStateSchema = z.strictObject({\n instanceName: z.string().min(1).max(256),\n compatibility: z.string().regex(/^[a-f0-9]{64}$/),\n values: z.array(z.strictObject({ topic: text, value, uom: z.string().max(256), timestamp: z.string().datetime() })).max(10000),\n sequences: z.array(z.tuple([text, z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER)])).max(10000),\n cursor: z.strictObject({ batchSize: z.number().int().min(0).max(100), referenceHash: z.string().regex(/^[a-f0-9]{64}$/) }),\n}).superRefine((state, ctx) => {\n for (const keys of [state.values.map(v => v.topic), state.sequences.map(v => v[0])])\n if (new Set(keys).size !== keys.length) ctx.addIssue({ code: 'custom', message: 'Duplicate MQTT state key' });\n});\nexport const mqttHandoverStateSchema = z.strictObject({\n protocol: z.literal(1),\n proxies: z.array(mqttProxyHandoverStateSchema).max(64),\n}).superRefine((state, ctx) => {\n if (new Set(state.proxies.map(p => p.instanceName)).size !== state.proxies.length)\n ctx.addIssue({ code: 'custom', message: 'Duplicate MQTT proxy' });\n});\nexport type MqttProxyHandoverState = z.infer<typeof mqttProxyHandoverStateSchema>;\nexport type MqttHandoverState = z.infer<typeof mqttHandoverStateSchema>;\nexport function parseMqttHandoverState(input: unknown): MqttHandoverState {\n const json = JSON.stringify(input);\n if (!json || Buffer.byteLength(json) > MQTT_HANDOVER_STATE_MAX_BYTES) throw Error('MQTT handover state exceeds its bound');\n return mqttHandoverStateSchema.parse(input);\n}\nexport function mqttHandoverStateDigest(state: MqttHandoverState): string {\n return createHash('sha256').update(JSON.stringify(parseMqttHandoverState(state))).digest('hex');\n}\nexport const mqttHandoverCapabilitySchema = z.strictObject({ protocolVersion: z.literal(2) });\nexport function readMqttHandoverCapability(packageRoot: string): 2 | undefined {\n const file = path.join(packageRoot, 'package.json');\n let stat: fs.Stats;\n try { stat = fs.lstatSync(file); } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined; throw error; }\n if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1048576) throw Error('Unsafe MQTT handover descriptor');\n const descriptor = JSON.parse(fs.readFileSync(file, 'utf8'))?.unsDatahub?.mqttHandover;\n if (descriptor === undefined) return undefined;\n mqttHandoverCapabilitySchema.parse(descriptor);\n return 2;\n}\n"]}
@@ -10,6 +10,7 @@ import { UnsEvents } from "./uns-interfaces.js";
10
10
  * and processing handover responses.
11
11
  */
12
12
  export declare class HandoverManager {
13
+ private readonly statefulHandover;
13
14
  event: HandoverManagerEventEmitter<HandoverManagerEvents>;
14
15
  private processName;
15
16
  private processId;
@@ -26,10 +27,16 @@ export declare class HandoverManager {
26
27
  private sourcePreparation;
27
28
  private sourceExit;
28
29
  private readonly shutdownHooks;
30
+ private expectedSourceId;
31
+ private preparedState;
32
+ private stateDigest;
33
+ private acceptedStateDigest;
34
+ private targetPreparation;
35
+ private finRetry;
29
36
  handoverRequestEnabled: boolean;
30
37
  handoverEnabled: boolean;
31
38
  forceStartEnabled: boolean;
32
- constructor(processName: string, processId: string, mqttProxy: MqttProxy, unsMqttProxies: UnsMqttProxy[], handoverRequestEnabled: boolean, handoverEnabled: boolean, forceStartEnabled: boolean, handoverId?: string, shutdownHooks?: HandoverShutdownHooks);
39
+ constructor(processName: string, processId: string, mqttProxy: MqttProxy, unsMqttProxies: UnsMqttProxy[], handoverRequestEnabled: boolean, handoverEnabled: boolean, forceStartEnabled: boolean, handoverId?: string, shutdownHooks?: HandoverShutdownHooks, statefulHandover?: boolean);
33
40
  private getUserProperties;
34
41
  private handoverPayload;
35
42
  private getHandoverId;
@@ -47,6 +54,8 @@ export declare class HandoverManager {
47
54
  */
48
55
  private exitSource;
49
56
  private prepareSourceHandover;
57
+ private sendPreparedState;
58
+ private acceptPreparedState;
50
59
  private finishSourceHandover;
51
60
  private handleHandover;
52
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"handover-manager.d.ts","sourceRoot":"","sources":["../../src/uns/handover-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAiD,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACnH,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,SAAS,MAAM,2BAA2B,CAAC;AAElD,OAAO,YAAY,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAElF,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQhD;;;;GAIG;AACH,qBAAa,eAAe;IACnB,KAAK,EAAE,2BAA2B,CAAC,qBAAqB,CAAC,CAA4D;IAC5H,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAC3D,sBAAsB,EAAE,OAAO,CAAS;IACxC,eAAe,EAAE,OAAO,CAAQ;IAChC,iBAAiB,EAAE,OAAO,CAAS;gBAGxC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,YAAY,EAAE,EAC9B,sBAAsB,EAAE,OAAO,EAC/B,eAAe,EAAE,OAAO,EACxB,iBAAiB,EAAE,OAAO,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,qBAAqB;IAiCvC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,oBAAoB;IAU5B;;;OAGG;IACU,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoFxE;;OAEG;IACH,OAAO,CAAC,UAAU;YAIJ,qBAAqB;YA6DrB,oBAAoB;YAiBpB,cAAc;CA2F7B"}
1
+ {"version":3,"file":"handover-manager.d.ts","sourceRoot":"","sources":["../../src/uns/handover-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiD,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACnH,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,SAAS,MAAM,2BAA2B,CAAC;AAElD,OAAO,YAAY,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAElF,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQhD;;;;GAIG;AACH,qBAAa,eAAe;IAqCxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IApC5B,KAAK,EAAE,2BAA2B,CAAC,qBAAqB,CAAC,CAA4D;IAC5H,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAClE,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAA6B;IACtC,sBAAsB,EAAE,OAAO,CAAS;IACxC,eAAe,EAAE,OAAO,CAAQ;IAChC,iBAAiB,EAAE,OAAO,CAAS;gBAGxC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,YAAY,EAAE,EAC9B,sBAAsB,EAAE,OAAO,EAC/B,eAAe,EAAE,OAAO,EACxB,iBAAiB,EAAE,OAAO,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,qBAAqB,EACpB,gBAAgB,UAAQ;IAkC3C,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,oBAAoB;IAU5B;;;OAGG;IACU,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqFxE;;OAEG;IACH,OAAO,CAAC,UAAU;YAIJ,qBAAqB;YA8ErB,iBAAiB;YAOjB,mBAAmB;YAkBnB,oBAAoB;YA2BpB,cAAc;CAwH7B"}
@@ -1,3 +1,4 @@
1
+ import { mqttHandoverOfferSchema, parseMqttHandoverState, mqttHandoverStateDigest } from "../runtime/mqtt-handover-state.js";
1
2
  import logger from "../logger.js";
2
3
  import { runHandoverShutdown, validateHandoverShutdown } from "./handover-shutdown.js";
3
4
  import { MqttTopicBuilder } from "../uns-mqtt/mqtt-topic-builder.js";
@@ -15,6 +16,7 @@ function normalizeHandoverId(value) {
15
16
  * and processing handover responses.
16
17
  */
17
18
  export class HandoverManager {
19
+ statefulHandover;
18
20
  event = new HandoverManagerEventEmitter();
19
21
  processName;
20
22
  processId;
@@ -31,10 +33,17 @@ export class HandoverManager {
31
33
  sourcePreparation;
32
34
  sourceExit;
33
35
  shutdownHooks;
36
+ expectedSourceId;
37
+ preparedState;
38
+ stateDigest;
39
+ acceptedStateDigest;
40
+ targetPreparation;
41
+ finRetry;
34
42
  handoverRequestEnabled = false;
35
43
  handoverEnabled = true;
36
44
  forceStartEnabled = false;
37
- constructor(processName, processId, mqttProxy, unsMqttProxies, handoverRequestEnabled, handoverEnabled, forceStartEnabled, handoverId, shutdownHooks) {
45
+ constructor(processName, processId, mqttProxy, unsMqttProxies, handoverRequestEnabled, handoverEnabled, forceStartEnabled, handoverId, shutdownHooks, statefulHandover = false) {
46
+ this.statefulHandover = statefulHandover;
38
47
  validateHandoverShutdown(shutdownHooks);
39
48
  this.shutdownHooks = shutdownHooks ? { ...shutdownHooks } : undefined;
40
49
  this.processName = processName;
@@ -51,6 +60,8 @@ export class HandoverManager {
51
60
  this.topicBuilder = new MqttTopicBuilder(`uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageName)}/${MqttTopicBuilder.sanitizeTopicPart(version)}/${MqttTopicBuilder.sanitizeTopicPart(this.processName)}/`);
52
61
  // Set status as active after a timeout if no other active process are detected.
53
62
  this.activeTimeout = setTimeout(() => {
63
+ if (this.statefulHandover && this.handoverId)
64
+ return; // A reviewed successor never self-promotes.
54
65
  logger.info(`${this.processName} - No active message received within timeout. Assuming no other process is running.`);
55
66
  this.active = true;
56
67
  this.event.emit("handoverManager", { active: this.active });
@@ -75,6 +86,7 @@ export class HandoverManager {
75
86
  const normalized = normalizeHandoverId(handoverId ?? this.handoverId);
76
87
  return JSON.stringify({
77
88
  type,
89
+ ...(this.statefulHandover ? { protocol: 2 } : {}),
78
90
  ...fields,
79
91
  ...(normalized ? { handoverId: normalized } : {}),
80
92
  });
@@ -161,6 +173,7 @@ export class HandoverManager {
161
173
  this.activeTimeout = undefined;
162
174
  this.event.emit("handoverManager", { active: this.active });
163
175
  this.requestingHandover = true;
176
+ this.expectedSourceId = sourceProcessId;
164
177
  const eventHandoverTopic = new MqttTopicBuilder(MqttTopicBuilder.extractBaseTopic(event.topic)).getHandoverTopic();
165
178
  await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload("handover_intent"), {
166
179
  retain: false,
@@ -172,7 +185,7 @@ export class HandoverManager {
172
185
  setTimeout(async () => {
173
186
  logger.info(`${this.processName} - Requesting handover ${eventHandoverTopic}.`);
174
187
  this.handoverInProgress = true;
175
- await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload("handover_request"), {
188
+ await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload("handover_request", undefined, this.statefulHandover ? { offer: this.unsMqttProxies.map(proxy => proxy.getHandoverCompatibility()) } : {}), {
176
189
  retain: false,
177
190
  properties: {
178
191
  responseTopic: this.topicBuilder.getHandoverTopic(),
@@ -231,9 +244,29 @@ export class HandoverManager {
231
244
  const mqttWorkerData = [];
232
245
  for (let i = 0; i < this.unsMqttProxies.length; i++) {
233
246
  const unsProxy = this.unsMqttProxies[i];
234
- const workerData = await unsProxy.setSubscriberPassiveAndDrainQueue();
247
+ const workerData = await unsProxy.setSubscriberPassiveAndDrainQueue(this.statefulHandover);
235
248
  mqttWorkerData.push(workerData);
236
249
  }
250
+ if (this.statefulHandover) {
251
+ // Finish accepted application callbacks before taking the calculation-state boundary.
252
+ await this.shutdownHooks?.drain();
253
+ for (const proxy of this.unsMqttProxies)
254
+ await proxy.flush();
255
+ this.preparedState = parseMqttHandoverState({ protocol: 1, proxies: this.unsMqttProxies.map((proxy, i) => proxy.exportHandoverState({ batchSize: mqttWorkerData[i].batchSize, referenceHash: mqttWorkerData[i].referenceHash })) });
256
+ this.stateDigest = mqttHandoverStateDigest(this.preparedState);
257
+ await this.sendPreparedState(event, handoverId);
258
+ let retries = 0;
259
+ this.finRetry = setInterval(() => {
260
+ if (++retries > 30 || this.sourceExit) {
261
+ clearInterval(this.finRetry);
262
+ return;
263
+ }
264
+ void this.sendPreparedState(event, handoverId).catch(() => logger.warn("MQTT handover receipt retry unavailable"));
265
+ }, 1000);
266
+ this.finRetry.unref();
267
+ // Keep the old owner passive until the successor acknowledges this exact state.
268
+ return;
269
+ }
237
270
  logger.info(`${this.processName} - Handover request accepted. Sending handover_subscriber messages.`);
238
271
  // Publish handover_subscriber messages for each instance that has processed some data.
239
272
  for (let i = 0; i < mqttWorkerData.length; i++) {
@@ -265,10 +298,48 @@ export class HandoverManager {
265
298
  logger.info(`${this.processName} - Handover fin message sent.`);
266
299
  await Promise.all(this.unsMqttProxies.map((unsProxy) => unsProxy.stop()));
267
300
  }
301
+ async sendPreparedState(event, handoverId) {
302
+ await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? "", this.handoverPayload("handover_fin", handoverId, { state: this.preparedState, stateDigest: this.stateDigest }), {
303
+ retain: false, qos: 1, properties: { responseTopic: this.topicBuilder.getHandoverTopic(), userProperties: this.getUserProperties(handoverId) },
304
+ });
305
+ }
306
+ async acceptPreparedState(response) {
307
+ const state = parseMqttHandoverState(response.state);
308
+ const digest = mqttHandoverStateDigest(state);
309
+ if (digest !== response.stateDigest)
310
+ throw Error("MQTT handover state digest mismatch");
311
+ const byName = new Map(this.unsMqttProxies.map(proxy => [proxy.instanceName, proxy]));
312
+ if (byName.size !== this.unsMqttProxies.length || state.proxies.length !== byName.size || state.proxies.some(p => !byName.has(p.instanceName)))
313
+ throw Error("MQTT handover proxy set differs");
314
+ for (const snapshot of state.proxies)
315
+ byName.get(snapshot.instanceName).validateHandoverState(snapshot);
316
+ // Validate every cursor before importing any state or activating any subscriber.
317
+ for (const snapshot of state.proxies)
318
+ await byName.get(snapshot.instanceName).prepareHandoverResume(snapshot.cursor);
319
+ for (const snapshot of state.proxies)
320
+ byName.get(snapshot.instanceName).importHandoverState(snapshot);
321
+ for (const proxy of this.unsMqttProxies)
322
+ proxy.setPublisherActive();
323
+ for (const proxy of this.unsMqttProxies)
324
+ await proxy.activateHandoverResume();
325
+ this.acceptedStateDigest = digest;
326
+ this.active = true;
327
+ this.event.emit("handoverManager", { active: true });
328
+ }
268
329
  async finishSourceHandover() {
269
330
  const result = await runHandoverShutdown(async () => {
270
331
  await this.sourcePreparation;
271
332
  await this.shutdownHooks?.drain();
333
+ if (this.statefulHandover) {
334
+ await Promise.all(this.unsMqttProxies.map(proxy => proxy.stop()));
335
+ // The host persists this receipt synchronously before the real process
336
+ // exit. No receipt is emitted for a partial/failed application drain.
337
+ process.emit("uns-kit:mqtt-handover-drained", {
338
+ protocol: 2, handoverId: this.acceptedHandoverId,
339
+ stateDigest: this.stateDigest, pendingRecords: 0,
340
+ outputs: this.unsMqttProxies.length,
341
+ });
342
+ }
272
343
  }, this.shutdownHooks?.timeoutMs ?? 30_000);
273
344
  this.handoverInProgress = false;
274
345
  this.requestingHandover = false;
@@ -284,14 +355,32 @@ export class HandoverManager {
284
355
  }
285
356
  async handleHandover(event) {
286
357
  try {
358
+ if (event.message.length > 1100000)
359
+ return;
287
360
  const response = JSON.parse(event.message.toString());
361
+ // No downgrade: stateful peers must agree before either relinquishes ownership.
362
+ if ((response.protocol === 2) !== this.statefulHandover)
363
+ return;
364
+ if (this.statefulHandover && (event.packet?.retain || !this.getHandoverId(response, event)))
365
+ return;
288
366
  // Responder process
289
367
  // Check if the message is a handover request and publish MULTIPLE handover_subscriber messages
290
368
  if (response.type === "handover_request") {
291
369
  const peerId = this.getSourceProcessId(event);
292
370
  const replyTopic = event.packet?.properties?.responseTopic;
371
+ if (this.statefulHandover && this.sourcePeerId === peerId && this.acceptedHandoverId === this.getHandoverId(response, event) && this.preparedState) {
372
+ await this.sendPreparedState(event, this.acceptedHandoverId);
373
+ return;
374
+ }
293
375
  if (this.sourcePeerId || !this.active || !peerId || typeof replyTopic !== "string" || !replyTopic)
294
376
  return;
377
+ if (this.statefulHandover) {
378
+ // Reject incompatible upgrades before freezing the current owner.
379
+ const offer = mqttHandoverOfferSchema.parse(response.offer);
380
+ const own = this.unsMqttProxies.map(proxy => proxy.getHandoverCompatibility());
381
+ if (offer.length !== own.length || own.some(p => !offer.some(o => o.instanceName === p.instanceName && o.compatibility === p.compatibility)))
382
+ throw Error("MQTT source/destination or semantic contract differs; source remains active");
383
+ }
295
384
  this.sourcePeerId = peerId;
296
385
  this.acceptedHandoverId = this.getHandoverId(response, event);
297
386
  this.handoverInProgress = true;
@@ -303,8 +392,8 @@ export class HandoverManager {
303
392
  }
304
393
  catch {
305
394
  // Subscriber transfer or onRelease failed; never report successful source completion.
306
- logger.error(`${this.processName} - Handover source preparation failed. Exiting with incomplete drain.`);
307
- if (!this.sourceExit)
395
+ logger.error(`${this.processName} - Handover source preparation failed; ownership requires review.`);
396
+ if (!this.sourceExit && !this.statefulHandover)
308
397
  this.exitSource(1);
309
398
  }
310
399
  }
@@ -312,6 +401,8 @@ export class HandoverManager {
312
401
  // Check if the message is one of the handover_subscriber message in response to handover_request
313
402
  // and publish a handover_ack message
314
403
  if (response.type === "handover_subscriber") {
404
+ if (this.statefulHandover)
405
+ return;
315
406
  if (this.sourcePeerId)
316
407
  return;
317
408
  if (!this.acceptsHandoverResponse(this.getHandoverId(response, event)))
@@ -326,6 +417,20 @@ export class HandoverManager {
326
417
  // Requestor process
327
418
  // Check if the message is a handover_fin at the end of handover_subscriber messages
328
419
  if (response.type === "handover_fin") {
420
+ if (this.statefulHandover) {
421
+ const id = this.getHandoverId(response, event);
422
+ if (this.sourcePeerId || !this.requestingHandover || id !== this.handoverId || this.getSourceProcessId(event) !== this.expectedSourceId)
423
+ return;
424
+ if (this.acceptedStateDigest && response.stateDigest !== this.acceptedStateDigest)
425
+ return;
426
+ this.targetPreparation ??= this.acceptPreparedState(response);
427
+ await this.targetPreparation;
428
+ // Duplicate fin only replays the receipt; it never reapplies a baseline.
429
+ if (response.stateDigest !== this.acceptedStateDigest)
430
+ return;
431
+ await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? "", this.handoverPayload("handover_ack", id, { stateDigest: this.acceptedStateDigest }), { retain: false, qos: 1, properties: { userProperties: this.getUserProperties(id) } });
432
+ return;
433
+ }
329
434
  if (this.sourcePeerId)
330
435
  return;
331
436
  const handoverId = this.getHandoverId(response, event);
@@ -363,6 +468,9 @@ export class HandoverManager {
363
468
  logger.warn(`${this.processName} - Ignoring acknowledgement for another migration.`);
364
469
  return;
365
470
  }
471
+ if (this.statefulHandover && (handoverId !== this.acceptedHandoverId || response.stateDigest !== this.stateDigest || !this.stateDigest))
472
+ return;
473
+ clearInterval(this.finRetry);
366
474
  logger.info(`${this.processName} - Received handover ack from ${event.packet?.properties?.userProperties?.processName}.`);
367
475
  this.sourceExit ??= this.finishSourceHandover();
368
476
  await this.sourceExit;