@zlink-systems/framework 0.31.0 → 0.32.1

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 (181) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Actors/ZLinkActor.d.ts +2 -0
  3. package/dist/contracts/Actors/ZLinkSessionBindingIdentity.d.ts +6 -0
  4. package/dist/contracts/Actors/ZLinkSessionBindingIdentity.js +2 -0
  5. package/dist/contracts/Actors/index.d.ts +1 -0
  6. package/dist/contracts/Actors/index.js +1 -0
  7. package/dist/contracts/Common/payload-slab.d.ts +4 -0
  8. package/dist/contracts/Common/payload-slab.js +30 -0
  9. package/dist/contracts/Handlers/Contexts.d.ts +1 -0
  10. package/dist/internal.d.ts +9 -0
  11. package/dist/internal.js +23 -1
  12. package/dist/runtime/actors/actor-client.d.ts +1 -1
  13. package/dist/runtime/actors/actor-client.js +32 -23
  14. package/dist/runtime/actors/actor-context.js +1 -1
  15. package/dist/runtime/actors/actor-creation.js +1 -1
  16. package/dist/runtime/actors/actor-mailbox.d.ts +1 -1
  17. package/dist/runtime/actors/actor-runtime-state.d.ts +3 -2
  18. package/dist/runtime/actors/actor-runtime-state.js +24 -8
  19. package/dist/runtime/actors/index.d.ts +3 -3
  20. package/dist/runtime/actors/index.js +19 -32
  21. package/dist/runtime/actors/spot-actor-dispatch.d.ts +4 -2
  22. package/dist/runtime/actors/spot-actor-dispatch.js +2 -1
  23. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +1 -0
  24. package/dist/runtime/application-jobs/application-ingress-record-owner.js +3 -0
  25. package/dist/runtime/backend/contracts/index.d.ts +2 -0
  26. package/dist/runtime/backend/mesh-completion-table.d.ts +1 -0
  27. package/dist/runtime/backend/mesh-completion-table.js +1 -0
  28. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +5 -1
  29. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +7 -2
  30. package/dist/runtime/backend/node/node-raw-binding-port.js +17 -11
  31. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +2 -2
  32. package/dist/runtime/backend/node/node-raw-mesh-backend.js +15 -8
  33. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +7 -6
  34. package/dist/runtime/channels/channel-dispatch-pipeline.js +1 -0
  35. package/dist/runtime/channels/channel-dispatchers.d.ts +7 -3
  36. package/dist/runtime/channels/channel-dispatchers.js +27 -19
  37. package/dist/runtime/channels/channel-envelope.js +543 -23
  38. package/dist/runtime/channels/channel-receive-loops.d.ts +9 -6
  39. package/dist/runtime/channels/channel-receive-loops.js +59 -18
  40. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +22 -3
  41. package/dist/runtime/channels/channel-socket-registry.d.ts +22 -4
  42. package/dist/runtime/diagnostics/runtime-metrics.d.ts +1 -1
  43. package/dist/runtime/diagnostics/runtime-metrics.js +2 -1
  44. package/dist/runtime/execution/serial-execution-queue.d.ts +26 -13
  45. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +27 -11
  46. package/dist/runtime/foundation/raw-service-mesh-runtime.js +29 -25
  47. package/dist/runtime/foundation/service-liveness-registry.d.ts +1 -1
  48. package/dist/runtime/foundation/service-mailbox.d.ts +3 -1
  49. package/dist/runtime/foundation/service-mailbox.js +4 -1
  50. package/dist/runtime/foundation/service-runtime-contracts.d.ts +3 -1
  51. package/dist/runtime/foundation/service-stateful-registry.d.ts +2 -0
  52. package/dist/runtime/foundation/service-stateful-registry.js +28 -12
  53. package/dist/runtime/foundation/service-stateful-runtime.d.ts +51 -19
  54. package/dist/runtime/foundation/service-stateful-runtime.js +54 -5
  55. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +3 -0
  56. package/dist/runtime/foundation/service-stateful-wire-codec.js +15 -0
  57. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  58. package/dist/runtime/foundation/service-wire-constants.generated.js +12 -0
  59. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +2 -0
  60. package/dist/runtime/foundation/service-wire-m6a-codec.js +17 -7
  61. package/dist/runtime/host/actor-placement-coordinator.d.ts +1 -1
  62. package/dist/runtime/host/actor-transfer-runtime.d.ts +3 -3
  63. package/dist/runtime/host/application-job-queue.d.ts +1 -1
  64. package/dist/runtime/host/index.d.ts +89 -36
  65. package/dist/runtime/host/index.js +101 -7
  66. package/dist/runtime/host/location-runtime-owner.d.ts +2 -2
  67. package/dist/runtime/host/service-relocation-host-runtime.d.ts +181 -44
  68. package/dist/runtime/host/service-relocation-host-runtime.js +47 -13
  69. package/dist/runtime/host/spot-address-transport.js +50 -42
  70. package/dist/runtime/locations/actor-location-claims.js +9 -10
  71. package/dist/runtime/locations/auto-connect-loop.d.ts +0 -1
  72. package/dist/runtime/locations/auto-connect-loop.js +25 -19
  73. package/dist/runtime/locations/auto-connect-planner.js +2 -5
  74. package/dist/runtime/locations/auto-connect-reconciler.d.ts +1 -0
  75. package/dist/runtime/locations/auto-connect-reconciler.js +35 -23
  76. package/dist/runtime/locations/in-memory-location-store.d.ts +0 -2
  77. package/dist/runtime/locations/in-memory-location-store.js +1 -38
  78. package/dist/runtime/locations/location-store-repository.d.ts +0 -1
  79. package/dist/runtime/locations/location-store-repository.js +13 -115
  80. package/dist/runtime/locations/runtime.d.ts +3 -3
  81. package/dist/runtime/locations/runtime.js +12 -16
  82. package/dist/runtime/messaging/creation-payload-codec.js +2 -2
  83. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +4 -0
  84. package/dist/runtime/protocol/service_wire_codec.generated.js +17 -7
  85. package/dist/runtime/spots/index.d.ts +20 -5
  86. package/dist/runtime/spots/index.js +14 -0
  87. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +3 -3
  88. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +1 -0
  89. package/dist/runtime/spots/spot-actor-packet-dispatch.js +13 -7
  90. package/dist/runtime/spots/spot-actor-packet-drain.d.ts +1 -0
  91. package/dist/runtime/spots/spot-actor-packet-drain.js +12 -5
  92. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -1
  93. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +8 -6
  94. package/dist/runtime/spots/spot-node-runtime-manager.js +2 -0
  95. package/dist/runtime/spots/spot-route-packet-dispatch.js +7 -4
  96. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +3 -1
  97. package/dist/runtime/spots/spot-serial-executor.d.ts +2 -1
  98. package/dist/runtime/spots/spot-subscription-dispatch.js +3 -1
  99. package/dist/runtime/spots/spot-timer.d.ts +1 -1
  100. package/dist/runtime/streams/actor-session-binding-registry.d.ts +9 -3
  101. package/dist/runtime/streams/actor-session-binding-registry.js +17 -0
  102. package/dist/runtime/streams/index.d.ts +3 -3
  103. package/dist/runtime/streams/index.js +22 -2
  104. package/dist/runtime/streams/managed-stream.js +2 -1
  105. package/dist/runtime/streams/session-calls.d.ts +1 -1
  106. package/dist/runtime/streams/session-calls.js +3 -9
  107. package/dist/runtime/streams/session-context.d.ts +2 -2
  108. package/dist/runtime/streams/session-context.js +2 -2
  109. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -0
  110. package/dist/runtime/streams/stream-session-runtime.js +37 -12
  111. package/package.json +3 -3
  112. package/src/contracts/Actors/ZLinkActor.ts +6 -0
  113. package/src/contracts/Actors/ZLinkSessionBindingIdentity.ts +7 -0
  114. package/src/contracts/Actors/index.ts +1 -0
  115. package/src/contracts/Common/payload-slab.ts +29 -0
  116. package/src/contracts/Handlers/Contexts.ts +1 -0
  117. package/src/internal.ts +17 -0
  118. package/src/runtime/actors/actor-client.ts +48 -23
  119. package/src/runtime/actors/actor-context.ts +1 -1
  120. package/src/runtime/actors/actor-creation.ts +1 -1
  121. package/src/runtime/actors/actor-mailbox.ts +1 -1
  122. package/src/runtime/actors/actor-runtime-state.ts +28 -10
  123. package/src/runtime/actors/index.ts +30 -35
  124. package/src/runtime/actors/spot-actor-dispatch.ts +4 -3
  125. package/src/runtime/application-jobs/application-ingress-record-owner.ts +4 -0
  126. package/src/runtime/backend/contracts/index.ts +2 -0
  127. package/src/runtime/backend/mesh-completion-table.ts +2 -0
  128. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +5 -1
  129. package/src/runtime/backend/node/node-raw-binding-port.ts +20 -7
  130. package/src/runtime/backend/node/node-raw-mesh-backend.ts +18 -10
  131. package/src/runtime/channels/channel-dispatch-pipeline.ts +6 -5
  132. package/src/runtime/channels/channel-dispatchers.ts +39 -19
  133. package/src/runtime/channels/channel-envelope.ts +547 -20
  134. package/src/runtime/channels/channel-receive-loops.ts +93 -36
  135. package/src/runtime/channels/channel-runtime-lifecycle.ts +2 -2
  136. package/src/runtime/channels/channel-socket-registry.ts +3 -3
  137. package/src/runtime/diagnostics/runtime-metrics.ts +3 -1
  138. package/src/runtime/execution/serial-execution-queue.ts +13 -13
  139. package/src/runtime/foundation/raw-service-mesh-runtime.ts +40 -39
  140. package/src/runtime/foundation/service-liveness-registry.ts +1 -1
  141. package/src/runtime/foundation/service-mailbox.ts +6 -1
  142. package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
  143. package/src/runtime/foundation/service-stateful-registry.ts +39 -14
  144. package/src/runtime/foundation/service-stateful-runtime.ts +87 -21
  145. package/src/runtime/foundation/service-stateful-wire-codec.ts +18 -0
  146. package/src/runtime/foundation/service-wire-constants.generated.ts +10 -0
  147. package/src/runtime/foundation/service-wire-m6a-codec.ts +29 -7
  148. package/src/runtime/host/actor-placement-coordinator.ts +1 -1
  149. package/src/runtime/host/actor-transfer-runtime.ts +3 -3
  150. package/src/runtime/host/application-job-queue.ts +1 -1
  151. package/src/runtime/host/index.ts +183 -44
  152. package/src/runtime/host/location-runtime-owner.ts +2 -2
  153. package/src/runtime/host/service-relocation-host-runtime.ts +101 -65
  154. package/src/runtime/host/spot-address-transport.ts +67 -61
  155. package/src/runtime/locations/actor-location-claims.ts +14 -14
  156. package/src/runtime/locations/auto-connect-loop.ts +24 -16
  157. package/src/runtime/locations/auto-connect-planner.ts +2 -5
  158. package/src/runtime/locations/auto-connect-reconciler.ts +37 -24
  159. package/src/runtime/locations/in-memory-location-store.ts +1 -74
  160. package/src/runtime/locations/location-store-repository.ts +32 -153
  161. package/src/runtime/locations/runtime.ts +16 -28
  162. package/src/runtime/messaging/creation-payload-codec.ts +3 -3
  163. package/src/runtime/protocol/service_wire_codec.generated.ts +18 -8
  164. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
  165. package/src/runtime/spots/index.ts +28 -4
  166. package/src/runtime/spots/spot-actor-admission-coordinator.ts +1 -1
  167. package/src/runtime/spots/spot-actor-packet-dispatch.ts +16 -6
  168. package/src/runtime/spots/spot-actor-packet-drain.ts +21 -6
  169. package/src/runtime/spots/spot-entry-activation.ts +1 -1
  170. package/src/runtime/spots/spot-node-runtime-manager.ts +8 -6
  171. package/src/runtime/spots/spot-route-packet-dispatch.ts +8 -4
  172. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +3 -1
  173. package/src/runtime/spots/spot-serial-executor.ts +1 -1
  174. package/src/runtime/spots/spot-subscription-dispatch.ts +3 -1
  175. package/src/runtime/spots/spot-timer.ts +1 -1
  176. package/src/runtime/streams/actor-session-binding-registry.ts +30 -3
  177. package/src/runtime/streams/index.ts +30 -4
  178. package/src/runtime/streams/managed-stream.ts +2 -1
  179. package/src/runtime/streams/session-calls.ts +9 -14
  180. package/src/runtime/streams/session-context.ts +6 -11
  181. package/src/runtime/streams/stream-session-runtime.ts +49 -20
@@ -8,7 +8,7 @@ import { type ZLinkFrameworkRegistration } from '../configuration';
8
8
  import type { ZLinkListenerRecords } from '../foundation/listener-records';
9
9
  import { ApplicationJobQueue } from '../host/application-job-queue';
10
10
  import type { ZLinkSubmitResult } from '../messaging/submission-result';
11
- import { type ZLinkActorSessionAuthorityFence } from './actor-session-binding-registry';
11
+ import { ZLinkActorSessionBindingRegistry, type ZLinkActorSessionAuthorityFence } from './actor-session-binding-registry';
12
12
  import { type ZLinkBoundActorRelaySenderOptions } from './bound-actor-relay-sender';
13
13
  import { type ZLinkBoundSessionResponseTarget } from './bound-session-response-target';
14
14
  import { type ZLinkBoundSessionTransport } from './bound-session-service';
@@ -100,7 +100,7 @@ export declare class ZLinkStreamSessionNodeRuntime extends ZLinkStreamSessionNod
100
100
  constructor(options: ZLinkStreamSessionNodeRuntimeOptions);
101
101
  }
102
102
  export declare class ZLinkStreamBindingRuntime {
103
- private readonly routes;
103
+ readonly routes: ZLinkActorSessionBindingRegistry<DefaultZLinkSessionContext, DefaultZLinkSessionActor>;
104
104
  private readonly frameMessages;
105
105
  private readonly compressionCodec;
106
106
  private readonly boundSessions;
@@ -149,5 +149,5 @@ export declare class ZLinkStreamBindingRuntime {
149
149
  createBinaryMessage(payload: Uint8Array): Message;
150
150
  decompressPayload(payload: Message): Message;
151
151
  createJsonFrameMessage(kind: ZLinkStreamMessageKind, packetName: string, metadata: ReadonlyMap<string, string>, compressed: boolean, requestSeq: bigint | undefined, payload: unknown, correlationId?: string): Message;
152
- createJsonReplyFrameMessage(requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Message;
152
+ submitReply(context: DefaultZLinkSessionContext, requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Promise<ZLinkSubmitResult>;
153
153
  }
@@ -348,8 +348,28 @@ class ZLinkStreamBindingRuntime {
348
348
  createJsonFrameMessage(kind, packetName, metadata, compressed, requestSeq, payload, correlationId) {
349
349
  return this.frameMessages.createJsonFrameMessage(kind, packetName, metadata, compressed, requestSeq, payload, correlationId);
350
350
  }
351
- createJsonReplyFrameMessage(requestHeader, kind, metadata, compressed, payload) {
352
- return this.frameMessages.createJsonReplyFrameMessage(requestHeader, kind, metadata, compressed, payload);
351
+ async submitReply(context, requestHeader, kind, metadata, compressed, payload) {
352
+ const frame = this.frameMessages.createJsonReplyFrameMessage(requestHeader, kind, metadata, compressed, payload);
353
+ try {
354
+ return await this.routes.submitReply(context, requestHeader, async (header) => {
355
+ if (header === requestHeader)
356
+ return await context.stream.submitRaw(frame);
357
+ const encoded = (0, protocol_1.decodeStreamFrame)((0, protocol_1.messageToBytes)(frame));
358
+ const normalized = this.createBinaryMessage((0, protocol_1.encodeStreamFrame)({
359
+ ...(0, protocol_1.decodeStreamHeader)(encoded.header),
360
+ actorSlot: header.actorSlot
361
+ }, encoded.payload));
362
+ try {
363
+ return await context.stream.submitRaw(normalized);
364
+ }
365
+ finally {
366
+ normalized.close();
367
+ }
368
+ });
369
+ }
370
+ finally {
371
+ frame.close();
372
+ }
353
373
  }
354
374
  }
355
375
  exports.ZLinkStreamBindingRuntime = ZLinkStreamBindingRuntime;
@@ -297,7 +297,8 @@ class ZLinkManagedStream {
297
297
  try {
298
298
  if (completion.terminalResult !== 0 &&
299
299
  !acceptedTerminalResults.has(completion.terminalResult)) {
300
- throw (0, framework_errors_internal_1.wireReplyFailureException)(completion.terminalResult, completion.failureErrno, `${operationName} failed with result ${completion.terminalResult} (errno ${completion.failureErrno}).`);
300
+ throw (0, framework_errors_internal_1.wireReplyFailureException)(completion.terminalResult, completion.failureErrno, completion.failureMessage ??
301
+ `${operationName} failed with result ${completion.terminalResult} (errno ${completion.failureErrno}).`);
301
302
  }
302
303
  }
303
304
  finally {
@@ -12,7 +12,7 @@ export interface ZLinkSessionCallContext {
12
12
  };
13
13
  readonly dispatchHeader: ZLinkStreamFrameHeader | undefined;
14
14
  createJsonFrameMessage(kind: ZLinkStreamMessageKind, packetName: string, metadata: ReadonlyMap<string, string>, compressed: boolean, requestSeq: bigint | undefined, payload: unknown, correlationId?: string): Message;
15
- createJsonReplyFrameMessage(requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Message;
15
+ submitReply(requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Promise<ZLinkSubmitResult>;
16
16
  claimReply(requestHeader: ZLinkStreamFrameHeader): void;
17
17
  /**
18
18
  * Spec 26 §2.2: the STREAM surface records session-connected sends and the
@@ -93,15 +93,9 @@ class DefaultZLinkSessionReplyCall {
93
93
  throw new Error('Reply is only available while handling a request packet.');
94
94
  }
95
95
  this.context.claimReply(requestHeader);
96
- const message = this.context.createJsonReplyFrameMessage(requestHeader, protocol_1.ZLinkStreamMessageKind.Response, new Map(), this.compressionEnabled, this.message);
97
- try {
98
- const result = await this.context.stream.submitRaw(message);
99
- (0, submission_result_1.requireOneWayCompletion)(result, 'STREAM session reply');
100
- this.context.traceFrameWritten?.(protocol_1.ZLinkStreamMessageKind.Response, requestHeader.name, requestHeader.correlationId);
101
- }
102
- finally {
103
- message.close();
104
- }
96
+ const result = await this.context.submitReply(requestHeader, protocol_1.ZLinkStreamMessageKind.Response, new Map(), this.compressionEnabled, this.message);
97
+ (0, submission_result_1.requireOneWayCompletion)(result, 'STREAM session reply');
98
+ this.context.traceFrameWritten?.(protocol_1.ZLinkStreamMessageKind.Response, requestHeader.name, requestHeader.correlationId);
105
99
  }
106
100
  }
107
101
  exports.DefaultZLinkSessionReplyCall = DefaultZLinkSessionReplyCall;
@@ -17,7 +17,7 @@ interface ZLinkSessionContextRuntime {
17
17
  createTextMessage(payload: string): Message;
18
18
  createBinaryMessage(payload: Uint8Array): Message;
19
19
  createJsonFrameMessage(kind: ZLinkStreamMessageKind, packetName: string, metadata: ReadonlyMap<string, string>, compressed: boolean, requestSeq: bigint | undefined, payload: unknown, correlationId?: string): Message;
20
- createJsonReplyFrameMessage(requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Message;
20
+ submitReply(context: DefaultZLinkSessionContext, requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Promise<ZLinkSubmitResult>;
21
21
  decompressPayload(payload: Message): Message;
22
22
  bind(context: DefaultZLinkSessionContext, actor: ZLinkActor | ActorRef, signal?: AbortSignal): Promise<DefaultZLinkSessionActor>;
23
23
  bindOrGet(context: DefaultZLinkSessionContext, actorRef: ActorRef, signal?: AbortSignal): Promise<DefaultZLinkSessionActor>;
@@ -64,7 +64,7 @@ export declare class DefaultZLinkSessionContext implements ZLinkSessionContext {
64
64
  createTextMessage(payload: string): Message;
65
65
  createBinaryMessage(payload: Uint8Array): Message;
66
66
  createJsonFrameMessage(kind: ZLinkStreamMessageKind, packetName: string, metadata: ReadonlyMap<string, string>, compressed: boolean, requestSeq: bigint | undefined, payload: unknown, correlationId?: string): Message;
67
- createJsonReplyFrameMessage(requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Message;
67
+ submitReply(requestHeader: ZLinkStreamFrameHeader, kind: ZLinkStreamReplyMessageKind, metadata: ReadonlyMap<string, string>, compressed: boolean, payload: unknown): Promise<ZLinkSubmitResult>;
68
68
  enterDispatch(header: ZLinkStreamFrameHeader): void;
69
69
  exitDispatch(): void;
70
70
  get dispatchHeader(): ZLinkStreamFrameHeader | undefined;
@@ -105,8 +105,8 @@ class DefaultZLinkSessionContext {
105
105
  createJsonFrameMessage(kind, packetName, metadata, compressed, requestSeq, payload, correlationId) {
106
106
  return this.runtime.createJsonFrameMessage(kind, packetName, metadata, compressed, requestSeq, payload, correlationId);
107
107
  }
108
- createJsonReplyFrameMessage(requestHeader, kind, metadata, compressed, payload) {
109
- return this.runtime.createJsonReplyFrameMessage(requestHeader, kind, metadata, compressed, payload);
108
+ submitReply(requestHeader, kind, metadata, compressed, payload) {
109
+ return this.runtime.submitReply(this, requestHeader, kind, metadata, compressed, payload);
110
110
  }
111
111
  enterDispatch(header) {
112
112
  if (this.closingForActorReplacement) {
@@ -93,6 +93,7 @@ export declare class ZLinkStreamSessionRuntime {
93
93
  private markConnected;
94
94
  private dispatchPacket;
95
95
  private handleControl;
96
+ private logIgnoredControl;
96
97
  private scheduleLivenessCheck;
97
98
  private runLivenessCheck;
98
99
  private closeForLiveness;
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkStreamSessionNodeRuntime = exports.ZLinkStreamSessionRuntime = void 0;
4
+ const submission_result_1 = require("../messaging/submission-result");
5
+ const api_logs_1 = require("@opentelemetry/api-logs");
6
+ const stream_wire_1 = require("@zlink-systems/stream-wire");
4
7
  const Registration_1 = require("../../contracts/Configuration/Registration");
5
8
  const ZLinkDispatchOptions_1 = require("../../contracts/Dispatch/ZLinkDispatchOptions");
6
9
  const abort_1 = require("../abort");
@@ -8,6 +11,7 @@ const admission_1 = require("../admission");
8
11
  const application_job_queue_scope_1 = require("../application-jobs/application-job-queue-scope");
9
12
  const channels_1 = require("../channels");
10
13
  const diagnostics_1 = require("../diagnostics");
14
+ const message_flow_record_1 = require("../diagnostics/message-flow-record");
11
15
  const flow_context_1 = require("../diagnostics/flow-context");
12
16
  const internal_event_contracts_1 = require("../diagnostics/internal-event-contracts");
13
17
  const runtime_metrics_1 = require("../diagnostics/runtime-metrics");
@@ -20,7 +24,6 @@ const session_context_1 = require("./session-context");
20
24
  const session_serial_executor_1 = require("./session-serial-executor");
21
25
  const stream_message_utils_1 = require("./stream-message-utils");
22
26
  const RegistrationNormalizers_1 = require("../../contracts/Configuration/RegistrationNormalizers");
23
- const ZLINK_SEND_DONT_WAIT = 1;
24
27
  const ZLINK_RECV_DONT_WAIT = 1;
25
28
  const ZLINK_STREAM_RECEIVE_FRAME_BATCH_LIMIT = 64;
26
29
  const ZLINK_STREAM_ACTOR_BINDING_REPLACEMENT_CLOSE_DELAY_MS = 100;
@@ -28,6 +31,7 @@ const ZLINK_STREAM_MONITOR_IDLE_MIN_DELAY_MS = 1;
28
31
  const ZLINK_STREAM_MONITOR_IDLE_MAX_DELAY_MS = 20;
29
32
  const ZLINK_STREAM_MONITOR_IDLE_MAX_STEPS = 7;
30
33
  const MAX_TIMER_DELAY_MS = 2_147_483_647;
34
+ const STREAM_RUNTIME_LOGGER = api_logs_1.logs.getLogger(message_flow_record_1.TELEMETRY_INSTRUMENTATION_NAME);
31
35
  const systemLivenessClock = {
32
36
  now: () => performance.now(),
33
37
  setTimer: (callback, delayMs) => setTimeout(callback, Math.min(delayMs, MAX_TIMER_DELAY_MS)),
@@ -384,19 +388,45 @@ class ZLinkStreamSessionRuntime {
384
388
  }
385
389
  }
386
390
  async handleControl(header, payload) {
387
- if ((0, protocol_1.messageToBytes)(payload).length !== 0) {
388
- await this.closeForLiveness(protocol_1.ZLinkStreamCloseReasonCode.ProtocolError, 'protocol_error', 'Control heartbeat payload must be empty.');
391
+ const payloadBytes = (0, protocol_1.messageToBytes)(payload);
392
+ if (header.name === protocol_1.ZLINK_STREAM_HEARTBEAT_PING) {
393
+ if (payloadBytes.length !== 0) {
394
+ this.logIgnoredControl(header.name, payloadBytes.length);
395
+ }
396
+ await this.stream.writeControl(protocol_1.ZLINK_STREAM_HEARTBEAT_PONG);
389
397
  return;
390
398
  }
391
399
  if (header.name === protocol_1.ZLINK_STREAM_HEARTBEAT_PONG) {
400
+ if (payloadBytes.length !== 0) {
401
+ this.logIgnoredControl(header.name, payloadBytes.length);
402
+ }
392
403
  return;
393
404
  }
394
- if (header.name === protocol_1.ZLINK_STREAM_HEARTBEAT_PING) {
395
- await this.stream.writeControl(protocol_1.ZLINK_STREAM_HEARTBEAT_PONG);
405
+ if (header.name === stream_wire_1.ZlinkStreamControlPacket.ActorBound ||
406
+ header.name === stream_wire_1.ZlinkStreamControlPacket.ActorUnbound) {
407
+ await this.closeForLiveness(protocol_1.ZLinkStreamCloseReasonCode.ProtocolError, 'protocol_error', `Unexpected stream actor control frame: ${header.name}`);
408
+ return;
409
+ }
410
+ if (header.name.startsWith('$zlink.')) {
411
+ this.logIgnoredControl(header.name, payloadBytes.length);
396
412
  return;
397
413
  }
398
414
  await this.closeForLiveness(protocol_1.ZLinkStreamCloseReasonCode.ProtocolError, 'protocol_error', `Unknown stream control frame: ${header.name}`);
399
415
  }
416
+ logIgnoredControl(name, payloadLength) {
417
+ STREAM_RUNTIME_LOGGER.emit({
418
+ eventName: 'zlink.stream.control_ignored',
419
+ timestamp: new Date(),
420
+ severityNumber: api_logs_1.SeverityNumber.DEBUG,
421
+ severityText: 'DEBUG',
422
+ body: `Ignored STREAM control name=${name} payloadBytes=${payloadLength} peerSessionRid=${this.stream.sessionId}`,
423
+ attributes: {
424
+ control_name: name,
425
+ payload_bytes: payloadLength,
426
+ peer_session_rid: this.stream.sessionId
427
+ }
428
+ });
429
+ }
400
430
  scheduleLivenessCheck() {
401
431
  if (this.disposed || this.disconnected || this.livenessTimer !== undefined) {
402
432
  return;
@@ -461,19 +491,14 @@ class ZLinkStreamSessionRuntime {
461
491
  // record (spec 26 §2.2) and confuse the peer's reply matching.
462
492
  return;
463
493
  }
464
- const message = this.context.createJsonReplyFrameMessage(header, protocol_1.ZLinkStreamMessageKind.Error, new Map(), false, (0, bound_session_response_target_1.boundSessionErrorPayload)(error));
465
494
  try {
466
- if (!this.context.stream.writeRaw(message, ZLINK_SEND_DONT_WAIT)) {
467
- throw new Error('Client stream error reply send failed.');
468
- }
495
+ const result = await this.context.submitReply(header, protocol_1.ZLinkStreamMessageKind.Error, new Map(), false, (0, bound_session_response_target_1.boundSessionErrorPayload)(error));
496
+ (0, submission_result_1.requireOneWayCompletion)(result, 'Client stream error reply');
469
497
  this.traceFrameWritten(protocol_1.ZLinkStreamMessageKind.Error, header.name, header.correlationId);
470
498
  }
471
499
  catch (replyError) {
472
500
  this.options.onError?.(replyError);
473
501
  }
474
- finally {
475
- message.close();
476
- }
477
502
  }
478
503
  /**
479
504
  * Spec 26 §2.1/§2.2: a successful session write is the surface's terminal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zlink-systems/framework",
3
- "version": "0.31.0",
3
+ "version": "0.32.1",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "@opentelemetry/api": "^1.9.1",
21
21
  "@opentelemetry/api-logs": "^0.221.0",
22
- "@zlink-systems/stream-wire": "0.31.0",
23
- "@zlink-systems/zlink": "1.21.0"
22
+ "@zlink-systems/stream-wire": "0.32.1",
23
+ "@zlink-systems/zlink": "1.23.0"
24
24
  }
25
25
  }
@@ -1,8 +1,14 @@
1
1
  import type { ZLinkActorContext } from './ZLinkActorContext';
2
2
  import type { ZLinkActorJoinCompletion } from './ZLinkActorFactory';
3
+ import type { ZLinkSessionBindingIdentity } from './ZLinkSessionBindingIdentity';
3
4
 
4
5
  export interface ZLinkActor {
5
6
  readonly context: ZLinkActorContext;
6
7
  configure?(): void;
7
8
  onJoinCompleted?(completion: ZLinkActorJoinCompletion): Promise<void>;
9
+ onDuplicateBind?(
10
+ current: ZLinkSessionBindingIdentity,
11
+ incoming: ZLinkSessionBindingIdentity,
12
+ signal: AbortSignal
13
+ ): Promise<string | undefined>;
8
14
  }
@@ -0,0 +1,7 @@
1
+ import type { RoutingId } from '../Common';
2
+
3
+ export interface ZLinkSessionBindingIdentity {
4
+ readonly sessionOwnerNodeRid: RoutingId;
5
+ readonly sessionOwnerNodeGeneration: bigint;
6
+ readonly bindingGeneration: bigint;
7
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './ZLinkActor';
2
+ export * from './ZLinkSessionBindingIdentity';
2
3
  export * from './ZLinkActorContext';
3
4
  export * from './ZLinkActorClient';
4
5
  export * from './ZLinkActorFactory';
@@ -0,0 +1,29 @@
1
+ const SLAB_BYTES = 64 * 1024;
2
+ const MAX_POOLED_BYTES = 16 * 1024;
3
+ const ALIGNMENT = 8;
4
+
5
+ let slab: Buffer | undefined;
6
+ let offset = 0;
7
+
8
+ /** Allocates independent bytes; previously returned regions are never reused. */
9
+ export function allocatePayloadBytes(length: number): Buffer {
10
+ if (length > MAX_POOLED_BYTES || length < 0 || !Number.isInteger(length)) {
11
+ return Buffer.allocUnsafe(length);
12
+ }
13
+ if (slab === undefined || offset + length > SLAB_BYTES) {
14
+ slab = Buffer.allocUnsafe(SLAB_BYTES);
15
+ offset = 0;
16
+ }
17
+ const bytes = slab.subarray(offset, offset + length);
18
+ offset += Math.ceil(length / ALIGNMENT) * ALIGNMENT;
19
+ // Transient runtime frames only; local queues and application boundaries
20
+ // copy before they retain or expose these bytes.
21
+ return bytes;
22
+ }
23
+
24
+ /** Copies bytes into an exact, standalone backing store with no Buffer pool. */
25
+ export function copyPayloadBytes(bytes: Uint8Array): Buffer {
26
+ const copy = Buffer.allocUnsafeSlow(bytes.byteLength);
27
+ copy.set(bytes);
28
+ return copy;
29
+ }
@@ -7,6 +7,7 @@ export interface ZLinkMessageContext {
7
7
  readonly contentType?: string;
8
8
  readonly metadata: ZLinkMessageMetadata;
9
9
  readonly correlationId?: string;
10
+ readonly receivedAt: Date;
10
11
  }
11
12
 
12
13
  export interface ZLinkPublishMessageContext extends ZLinkMessageContext {
package/src/internal.ts CHANGED
@@ -3,6 +3,19 @@ export * from './index';
3
3
  export { requireValidSendTimeoutMs } from './contracts/Configuration/SendTimeoutValidation';
4
4
  export * from './runtime/diagnostics';
5
5
  export * from './runtime/host';
6
+ export { ZLinkActorPlacementCoordinator } from './runtime/host/actor-placement-coordinator';
7
+ export { ZLinkActorTransferRuntime } from './runtime/host/actor-transfer-runtime';
8
+ export {
9
+ ApplicationJobQueue,
10
+ ApplicationJobQueuePermit,
11
+ nodeEffectiveProcessorCount,
12
+ resolveApplicationJobQueueConfiguration
13
+ } from './runtime/host/application-job-queue';
14
+ export { ZLinkLocationRuntimeOwner } from './runtime/host/location-runtime-owner';
15
+ export {
16
+ relocationFailedFailureCode,
17
+ ZLinkHostServiceRelocationRuntime
18
+ } from './runtime/host/service-relocation-host-runtime';
6
19
  export * from './runtime/admission';
7
20
  export * from './runtime/activation-admission';
8
21
  export * from './runtime/streams';
@@ -21,9 +34,13 @@ export {
21
34
  } from './contracts/Locations/Values';
22
35
  export { ZLinkLocationWriteIntent, ZLinkLocationWriteStatus } from './contracts/Locations/Writes';
23
36
  export * from './runtime/channels';
37
+ export { ZLinkChannelRuntimeLifecycle } from './runtime/channels/channel-runtime-lifecycle';
38
+ export { ZLinkChannelSocketRegistry } from './runtime/channels/channel-socket-registry';
39
+ export { ZLinkChannelDispatchPipeline } from './runtime/channels/channel-dispatch-pipeline';
24
40
  export * from './runtime/backend';
25
41
  export * from './runtime/codecs';
26
42
  export * from './runtime/execution';
43
+ export { ZLinkSerialExecutionQueue } from './runtime/execution/serial-execution-queue';
27
44
  export * from './runtime/handlers';
28
45
  export * from './runtime/messaging';
29
46
  export * from './runtime/foundation';
@@ -52,7 +52,11 @@ import {
52
52
  internalFrameworkErrorKindFromWireFailureCode,
53
53
  ZLinkFrameworkInternalErrorKind
54
54
  } from '../framework-errors-internal';
55
- import type { ZLinkResolvedActorRoute, ZLinkStoreLocationResolvers } from '../locations';
55
+ import type {
56
+ ZLinkActorRouteInvalidationFence,
57
+ ZLinkResolvedActorRoute,
58
+ ZLinkStoreLocationResolvers
59
+ } from '../locations';
56
60
  import { resolveFrameworkPacketName } from '../messaging/packet-name';
57
61
  import { decodeFrameworkPayloadMessage, encodeFrameworkPayload } from '../messaging/payload-codec';
58
62
  import {
@@ -161,7 +165,7 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
161
165
  ): Promise<ZLinkSubmitResult> {
162
166
  const route = await this.resolveActorRoute(actorId);
163
167
  const { meshName, actorRef: actor } = route;
164
- this.throwIfKnownStale(meshName, actor);
168
+ this.throwIfKnownStale(route);
165
169
  const parts = this.createPacketParts(
166
170
  ZLinkStreamMessageKind.Send,
167
171
  undefined,
@@ -169,8 +173,10 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
169
173
  message,
170
174
  metadata
171
175
  );
176
+ let routeFence: ZLinkActorRouteInvalidationFence | undefined;
172
177
  try {
173
178
  const messageFollow = createActorMessageFollowContext(route, parts, false);
179
+ routeFence = actorRouteInvalidationFence(route);
174
180
  const routedActor = attachActorMessageFollowContext(actor, messageFollow);
175
181
  const submissionCopies =
176
182
  (await this.options.transportDeliveryGate?.()?.waitBeforeSubmit(actorId, 'oneWay')) ?? 1;
@@ -218,12 +224,7 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
218
224
  }
219
225
  return await this.submitActorSend(meshName, toBackendActorRef(actor), parts, route);
220
226
  } catch (error) {
221
- if (isStaleActorError(error)) {
222
- this.invalidateActorRoute(actorId);
223
- this.options.staleActorRefReporter?.(meshName, actor.actorId);
224
- throw actorLocationStale(actor.actorId, error);
225
- }
226
- throw error;
227
+ throw this.mapActorFailure(actorId, error, routeFence, meshName);
227
228
  } finally {
228
229
  closeMessages(parts);
229
230
  }
@@ -243,6 +244,7 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
243
244
  const sourceSpotId = currentZLinkActorExecution()?.spotId ?? currentZLinkSpotSerialSourceId();
244
245
  const effectiveTimeoutMs = timeoutMs ?? this.options.defaultRequestTimeoutMs;
245
246
  let meshName: string | undefined;
247
+ let routeFence: ZLinkActorRouteInvalidationFence | undefined;
246
248
  return this.requests.prepare<TReply>(
247
249
  effectiveTimeoutMs,
248
250
  signal,
@@ -265,8 +267,10 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
265
267
  }
266
268
  const { actorRef: actor } = route;
267
269
  meshName = route.meshName;
268
- if (this.options.staleActorRefPredicate?.(meshName, actor) === true)
270
+ if (this.options.staleActorRefPredicate?.(meshName, actor) === true) {
271
+ routeFence = actorRouteInvalidationFence(route);
269
272
  throw actorLocationStale(actor.actorId, undefined);
273
+ }
270
274
  const operationId = createMessageFollowId();
271
275
  const correlationId = createMessageFollowId();
272
276
  const requestSequence = BigInt(`0x${operationId.slice(16)}`);
@@ -287,6 +291,7 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
287
291
  correlationId,
288
292
  operationId
289
293
  );
294
+ routeFence = actorRouteInvalidationFence(route);
290
295
  const routedActor = attachActorMessageFollowContext(actor, messageFollow);
291
296
  const delivery = this.options
292
297
  .transportDeliveryGate?.()
@@ -342,14 +347,7 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
342
347
  })().catch((error) => receiver.operationFailed(requestOperation.id, error, undefined));
343
348
  },
344
349
  (value) => value as TReply,
345
- (error) => {
346
- if (isStaleActorError(error)) {
347
- this.invalidateActorRoute(actorId);
348
- if (meshName !== undefined) this.options.staleActorRefReporter?.(meshName, actorId);
349
- return actorLocationStale(actorId, error);
350
- }
351
- return error;
352
- }
350
+ (error) => this.mapActorFailure(actorId, error, routeFence, meshName)
353
351
  );
354
352
  }
355
353
 
@@ -387,15 +385,29 @@ export class DefaultZLinkActorClient implements ZLinkActorClient {
387
385
  return resolution.route;
388
386
  }
389
387
 
390
- private invalidateActorRoute(actorId: string): void {
391
- this.options.locationResolver()?.invalidateActorRoute(actorId);
388
+ private mapActorFailure(
389
+ actorId: string,
390
+ error: unknown,
391
+ routeFence: ZLinkActorRouteInvalidationFence | undefined,
392
+ meshName: string | undefined
393
+ ): unknown {
394
+ if (!isStaleActorError(error)) return error;
395
+ const resolver = this.options.locationResolver();
396
+ if (routeFence !== undefined && resolver !== undefined)
397
+ resolver.invalidateActorRouteIfMatches(routeFence);
398
+ if (meshName !== undefined) this.options.staleActorRefReporter?.(meshName, actorId);
399
+ return actorLocationStale(actorId, error);
392
400
  }
393
401
 
394
- private throwIfKnownStale(meshName: string, actor: ActorRef): void {
402
+ private throwIfKnownStale(route: ZLinkResolvedActorRoute): void {
403
+ const { meshName, actorRef: actor } = route;
395
404
  if (this.options.staleActorRefPredicate?.(meshName, actor) !== true) return;
396
- this.invalidateActorRoute(actor.actorId);
397
- this.options.staleActorRefReporter?.(meshName, actor.actorId);
398
- throw actorLocationStale(actor.actorId, undefined);
405
+ throw this.mapActorFailure(
406
+ actor.actorId,
407
+ actorLocationStale(actor.actorId, undefined),
408
+ actorRouteInvalidationFence(route),
409
+ meshName
410
+ );
399
411
  }
400
412
 
401
413
  private createPacketParts(
@@ -609,6 +621,19 @@ function nativeActorRouteFence(route: ZLinkResolvedActorRoute, actor: ZLinkBacke
609
621
  };
610
622
  }
611
623
 
624
+ function actorRouteInvalidationFence(
625
+ route: ZLinkResolvedActorRoute
626
+ ): ZLinkActorRouteInvalidationFence {
627
+ return {
628
+ actorId: route.actorRef.actorId,
629
+ objectGeneration: route.actorRef.objectGeneration,
630
+ targetNodeRid: route.actorRef.nodeRid,
631
+ targetNodeGeneration: route.ownerNodeGeneration,
632
+ authorityOwnerGeneration: route.authorityOwnerGeneration,
633
+ ownerLeaseGeneration: route.ownerLeaseGeneration
634
+ };
635
+ }
636
+
612
637
  function remoteActorRouteTarget(route: ZLinkResolvedActorRoute) {
613
638
  if (route.enclosingSpotRoute !== undefined) {
614
639
  return route.enclosingSpotRoute;
@@ -97,7 +97,7 @@ export class DefaultZLinkActorContext implements ZLinkActorContext {
97
97
  }
98
98
 
99
99
  get objectGeneration(): bigint {
100
- return this.state.nativeActorRef?.generation ?? 1n;
100
+ return this.state.currentActorRef().generation;
101
101
  }
102
102
 
103
103
  get spotId(): SpotId | undefined {
@@ -211,7 +211,7 @@ export class ZLinkActorCreationCoordinator {
211
211
  await this.options.locationLifecycle?.setActorRef(
212
212
  actorType,
213
213
  actorId,
214
- { actorId, objectGeneration: 1n, meshName, nodeRid },
214
+ toFrameworkActorRef(state.currentActorRef(), meshName),
215
215
  0n
216
216
  );
217
217
  }
@@ -14,7 +14,7 @@ import {
14
14
  import type { ApplicationJobPermitPort } from '../application-jobs/contracts';
15
15
 
16
16
  export class ZLinkActorSerialExecutor {
17
- private readonly scheduler: ZLinkSerialExecutionQueue;
17
+ readonly scheduler: ZLinkSerialExecutionQueue;
18
18
 
19
19
  constructor(
20
20
  private readonly actorId: string,
@@ -9,6 +9,7 @@ import {
9
9
 
10
10
  import type { Message } from '../../contracts/Common/Message';
11
11
  import type { ZLinkBackendActorRef, ZLinkBackendMeshNode } from '../backend/contracts';
12
+ import { ZLinkConfigurationException } from '../configuration';
12
13
  import { isStructuralGuardEnabled } from '../execution/state-lane';
13
14
  import {
14
15
  ZLinkFrameworkInternalErrorKind,
@@ -172,9 +173,11 @@ export class ZLinkActorRuntimeState {
172
173
  private spotIdValue: RoutingId | undefined;
173
174
  private spotGenerationValue: bigint | undefined;
174
175
  private spotMembershipEpochValue = 0n;
176
+ // Preserve the exact incarnation until teardown finalization, even after native removal.
175
177
  private nativeActorRefValue: ZLinkBackendActorRef | undefined;
178
+ private nativeActorDestroyed = false;
176
179
  private entryNodeRidValue: RoutingId | undefined;
177
- private boundSessionValue: ZLinkRemoteBoundSessionTarget | undefined;
180
+ boundSessionValue: ZLinkRemoteBoundSessionTarget | undefined;
178
181
  private remoteActorPacketTargetValue: ZLinkRemoteActorPacketTarget | undefined;
179
182
  private createRequestPayloadValue: Buffer | undefined;
180
183
  private ownsLocationValue = false;
@@ -228,6 +231,15 @@ export class ZLinkActorRuntimeState {
228
231
  return this.nativeActorRefValue;
229
232
  }
230
233
 
234
+ currentActorRef(): ZLinkBackendActorRef {
235
+ if (this.nativeActorRefValue === undefined) {
236
+ throw new ZLinkConfigurationException(
237
+ `Actor '${this.actorId}' lifecycle identity is not initialized.`
238
+ );
239
+ }
240
+ return this.nativeActorRefValue;
241
+ }
242
+
231
243
  get boundSessionBindingGeneration(): bigint {
232
244
  return this.boundSessionValue?.bindingGeneration ?? 0n;
233
245
  }
@@ -355,24 +367,26 @@ export class ZLinkActorRuntimeState {
355
367
  );
356
368
  }
357
369
 
358
- const task = Promise.resolve().then(() => destroy(actorRef));
370
+ const task = Promise.resolve()
371
+ .then(() => destroy(this.nativeActorDestroyed ? undefined : actorRef))
372
+ .catch((error: unknown) => {
373
+ // A caller may start another attempt only after this attempt has failed.
374
+ if (this.destroyTask === task) {
375
+ this.destroyTask = undefined;
376
+ this.movingValue = false;
377
+ }
378
+ throw error;
379
+ });
359
380
  this.destroyTask = task;
360
381
  return task;
361
382
  }
362
383
 
363
384
  markNativeActorDestroyed(actorRef: ZLinkBackendActorRef): void {
364
385
  if (this.nativeActorRefValue === actorRef) {
365
- this.nativeActorRefValue = undefined;
386
+ this.nativeActorDestroyed = true;
366
387
  }
367
388
  }
368
389
 
369
- clearFailedDestroy(task: Promise<void>): void {
370
- if (this.destroyTask === task) {
371
- this.destroyTask = undefined;
372
- }
373
- this.movingValue = false;
374
- }
375
-
376
390
  ensureContext(createContext: () => ZLinkActorContext): ZLinkActorContext {
377
391
  this.context ??= createContext();
378
392
  return this.context;
@@ -425,6 +439,7 @@ export class ZLinkActorRuntimeState {
425
439
  this.createRequestPayloadValue = undefined;
426
440
  this.configured = false;
427
441
  this.nativeActorRefValue = undefined;
442
+ this.nativeActorDestroyed = false;
428
443
  this.entryNodeRidValue = undefined;
429
444
  return true;
430
445
  }
@@ -474,6 +489,7 @@ export class ZLinkActorRuntimeState {
474
489
 
475
490
  setNativeActorRef(actorRef: ZLinkBackendActorRef): void {
476
491
  this.nativeActorRefValue = actorRef;
492
+ this.nativeActorDestroyed = false;
477
493
  this.entryNodeRidValue ??= toFrameworkRoutingId(actorRef.nodeRid);
478
494
  }
479
495
 
@@ -556,6 +572,7 @@ export class ZLinkActorRuntimeState {
556
572
  this.spotGenerationValue = undefined;
557
573
  this.spotMembershipEpochValue = 0n;
558
574
  this.nativeActorRefValue = undefined;
575
+ this.nativeActorDestroyed = false;
559
576
  this.entryNodeRidValue = undefined;
560
577
  this.boundSessionValue = undefined;
561
578
  this.remoteActorPacketTargetValue = undefined;
@@ -578,6 +595,7 @@ export class ZLinkActorRuntimeState {
578
595
  this.spotValue = undefined;
579
596
  this.spotIdValue = undefined;
580
597
  this.nativeActorRefValue = undefined;
598
+ this.nativeActorDestroyed = false;
581
599
  // The arriving relocation installs the binding it carries.
582
600
  this.boundSessionValue = undefined;
583
601
  this.remoteActorPacketTargetValue = undefined;