@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
@@ -12,6 +12,7 @@ import { isDeepStrictEqual } from 'node:util';
12
12
  import {
13
13
  type ActorRef,
14
14
  type RoutingId,
15
+ type ZLinkSessionBindingIdentity,
15
16
  type ZLinkClientServerRuntime,
16
17
  type ZLinkFanoutRuntime,
17
18
  type ZLinkFrameworkLifecycleOptions,
@@ -283,8 +284,8 @@ export class ZLinkFrameworkRuntimeHost
283
284
 
284
285
  private readonly backendAdapterFactory: ZLinkBackendAdapterFactory;
285
286
  private readonly lifecycleSink?: string[];
286
- private executionState?: ZLinkFrameworkExecutionState;
287
- private runtimeState = ZLinkFrameworkRuntimeState.Preparing;
287
+ executionState?: ZLinkFrameworkExecutionState;
288
+ runtimeState = ZLinkFrameworkRuntimeState.Preparing;
288
289
  private runtimeStatus?: ZLinkFrameworkRuntimeStatus;
289
290
  private readonly runtimeObservationSource = Symbol('zlink.framework-runtime');
290
291
  private runtimeDeadline?: Date;
@@ -299,21 +300,21 @@ export class ZLinkFrameworkRuntimeHost
299
300
  private shutdownOperationStartedAt?: number;
300
301
  private relocationTargetApplicationVersion?: bigint;
301
302
  private readonly runtimeObservers = new Set<RuntimeEventQueue<ZLinkFrameworkRuntimeStatus>>();
302
- private channelRuntime?: ZLinkChannelRuntimeManager;
303
- private spotNodeRuntime?: ZLinkSpotNodeRuntimeManager;
303
+ channelRuntime?: ZLinkChannelRuntimeManager;
304
+ spotNodeRuntime?: ZLinkSpotNodeRuntimeManager;
304
305
  private streamRuntime?: ZLinkStreamRuntimeManager;
305
306
  private statefulAuthorityRoutes?: ZLinkStatefulAuthorityRouteRuntime;
306
- private readonly locationOwner: ZLinkLocationRuntimeOwner;
307
+ readonly locationOwner: ZLinkLocationRuntimeOwner;
307
308
  private readonly meshRouters: MeshRouterResolver;
308
- private readonly boundSessionRelay: ZLinkBoundSessionRelay;
309
+ readonly boundSessionRelay: ZLinkBoundSessionRelay;
309
310
  private readonly actorHandoff: ZLinkActorHandoffCoordinator;
310
311
  private readonly actorTransferRegistry: ZLinkActorTransferRegistry;
311
312
  private readonly actorTransferRuntime: ZLinkActorTransferRuntime;
312
313
  private readonly actorTransferAuthorityRuntime: ZLinkActorTransferAuthorityRuntime;
313
- private readonly serviceRelocation: ZLinkHostServiceRelocationRuntime;
314
- private readonly entryActorRuntime: ZLinkEntryActorRuntimeService;
314
+ readonly serviceRelocation: ZLinkHostServiceRelocationRuntime;
315
+ readonly entryActorRuntime: ZLinkEntryActorRuntimeService;
315
316
  private actorManager?: DefaultZLinkActorManager;
316
- private actorPlacement?: ZLinkActorPlacementCoordinator;
317
+ actorPlacement?: ZLinkActorPlacementCoordinator;
317
318
  private spotManager?: DefaultZLinkSpotManager;
318
319
  private userSpotCoordinator?: ZLinkUserSpotCreationCoordinator;
319
320
  private ownerLeaseRecoveryRuntime?: ZLinkLocationRuntime;
@@ -324,11 +325,11 @@ export class ZLinkFrameworkRuntimeHost
324
325
  private readonly destroyedActorRefs = new Map<string, ActorRef>();
325
326
  private readonly runtimeEventPublisher: ZLinkRuntimeEventPublisher;
326
327
  private readonly metrics: ZLinkRuntimeMetrics;
327
- private readonly applicationJobQueue: ApplicationJobQueue;
328
+ readonly applicationJobQueue: ApplicationJobQueue;
328
329
  private readonly capacityStatus: HostCapacityStatusProjection;
329
330
  private readonly metricRegistrations: import('../diagnostics').ZLinkRuntimeMetricRegistration[] =
330
331
  [];
331
- private readonly admission: ZLinkRuntimeAdmissionGate;
332
+ readonly admission: ZLinkRuntimeAdmissionGate;
332
333
  private readonly activationAdmission = new ZLinkActivationAdmission(
333
334
  (meshName) =>
334
335
  this.options.registration.spotNodes.get(meshName)?.activationConcurrencyLimit ??
@@ -346,7 +347,7 @@ export class ZLinkFrameworkRuntimeHost
346
347
  ZLinkDispatchErrorSink,
347
348
  ZLinkDispatchErrorReporter
348
349
  >();
349
- private readonly runtimeOrPreStartErrorSink: ZLinkDispatchErrorSink = {
350
+ readonly runtimeOrPreStartErrorSink: ZLinkDispatchErrorSink = {
350
351
  reportRuntimeTaskException: (taskName: string, error: unknown) =>
351
352
  (this.errorSink ?? this.preStartErrorSink).reportRuntimeTaskException(taskName, error)
352
353
  };
@@ -370,7 +371,7 @@ export class ZLinkFrameworkRuntimeHost
370
371
  readonly clientServerRuntime: ZLinkClientServerRuntime;
371
372
  readonly fanoutRuntime: ZLinkFanoutRuntime;
372
373
  private readonly relocationStore?: import('../../contracts/Locations/RelocationStore').ZLinkRelocationStore;
373
- private readonly routeMeshCoordinator: ZLinkRouteMeshRuntimeCoordinator;
374
+ readonly routeMeshCoordinator: ZLinkRouteMeshRuntimeCoordinator;
374
375
  constructor(
375
376
  readonly options: ZLinkFrameworkRuntimeHostOptions,
376
377
  internalOptions?: unknown
@@ -883,8 +884,8 @@ export class ZLinkFrameworkRuntimeHost
883
884
  clear: () => this.boundSessionRelay.boundSessions.clearServiceWireSessionRelocations()
884
885
  },
885
886
  trackInstanceSpot: (input) => this.locationOwner.currentLifecycle?.trackInstanceSpot(input),
886
- invalidateActorRoute: (actorId) =>
887
- this.actorClientLocationResolver?.invalidateActorRoute(actorId),
887
+ observeActorAuthorityVersion: (actorId, storeVersion) =>
888
+ this.actorClientLocationResolver?.observeActorAuthorityVersion(actorId, storeVersion),
888
889
  reconcileStatefulAuthorityRoutes: (signal) =>
889
890
  this.statefulAuthorityRoutes?.reconcile(signal) ?? Promise.resolve(),
890
891
  runtimeEventPublisher: this.runtimeEventPublisher,
@@ -1640,7 +1641,7 @@ export class ZLinkFrameworkRuntimeHost
1640
1641
  );
1641
1642
  }
1642
1643
 
1643
- private runtimeMetricMeshSnapshots(): readonly ZLinkRuntimeMetricMeshSnapshot[] {
1644
+ runtimeMetricMeshSnapshots(): readonly ZLinkRuntimeMetricMeshSnapshot[] {
1644
1645
  const snapshots: ZLinkRuntimeMetricMeshSnapshot[] = [];
1645
1646
  for (const [meshName, options] of this.options.registration.spotNodes) {
1646
1647
  let status;
@@ -1731,7 +1732,7 @@ export class ZLinkFrameworkRuntimeHost
1731
1732
  }
1732
1733
  }
1733
1734
 
1734
- private installOwnerLeaseRecoveryPublication(
1735
+ installOwnerLeaseRecoveryPublication(
1735
1736
  runtime: ZLinkLocationRuntime,
1736
1737
  spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1737
1738
  channelRuntime: ZLinkChannelRuntimeManager
@@ -1758,7 +1759,7 @@ export class ZLinkFrameworkRuntimeHost
1758
1759
  runtime.addOwnerLeaseRenewedHandler(handler);
1759
1760
  }
1760
1761
 
1761
- private async resumeOwnerLeaseOwnedWork(
1762
+ async resumeOwnerLeaseOwnedWork(
1762
1763
  runtime: ZLinkLocationRuntime,
1763
1764
  spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1764
1765
  channelRuntime: ZLinkChannelRuntimeManager
@@ -1782,7 +1783,7 @@ export class ZLinkFrameworkRuntimeHost
1782
1783
 
1783
1784
  // The one transition from Preparing to Serving: the host publishes its
1784
1785
  // Serving descriptors first, then takes new application work.
1785
- private async enterServing(
1786
+ async enterServing(
1786
1787
  spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1787
1788
  signal: AbortSignal | undefined
1788
1789
  ): Promise<void> {
@@ -1818,7 +1819,7 @@ export class ZLinkFrameworkRuntimeHost
1818
1819
  }
1819
1820
  }
1820
1821
 
1821
- private async startStatefulAuthority(
1822
+ async startStatefulAuthority(
1822
1823
  locationStore: import('../locations/domain-store-contract').ZLinkDomainLocationStore,
1823
1824
  spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1824
1825
  signal: AbortSignal | undefined
@@ -1924,7 +1925,7 @@ export class ZLinkFrameworkRuntimeHost
1924
1925
  }
1925
1926
  }
1926
1927
 
1927
- private removeOwnerLeaseRecoveryPublication(): void {
1928
+ removeOwnerLeaseRecoveryPublication(): void {
1928
1929
  if (
1929
1930
  this.ownerLeaseRecoveryRuntime !== undefined &&
1930
1931
  this.ownerLeaseRecoveryHandler !== undefined
@@ -2018,7 +2019,7 @@ export class ZLinkFrameworkRuntimeHost
2018
2019
  );
2019
2020
  }
2020
2021
 
2021
- private async preflightAutomaticPeerReadiness(
2022
+ async preflightAutomaticPeerReadiness(
2022
2023
  deadlineAt: number,
2023
2024
  targetApplicationVersion: bigint
2024
2025
  ): Promise<ZLinkFrameworkRelocationReason | undefined> {
@@ -2099,7 +2100,7 @@ export class ZLinkFrameworkRuntimeHost
2099
2100
  return true;
2100
2101
  }
2101
2102
 
2102
- private async publishHostRelocated(): Promise<void> {
2103
+ async publishHostRelocated(): Promise<void> {
2103
2104
  await Promise.all(
2104
2105
  [...this.options.registration.spotNodes.keys()].map((meshName) =>
2105
2106
  this.spotNodeRuntime?.publishMeshNodeState(
@@ -2853,7 +2854,7 @@ export class ZLinkFrameworkRuntimeHost
2853
2854
  `Actor '${actorRef.actorId}' authority requires its RouteMesh Entry Spot.`
2854
2855
  );
2855
2856
  }
2856
- await publishInitialActorAuthority(
2857
+ const authority = await publishInitialActorAuthority(
2857
2858
  store,
2858
2859
  {
2859
2860
  actorType,
@@ -2867,7 +2868,10 @@ export class ZLinkFrameworkRuntimeHost
2867
2868
  },
2868
2869
  signal
2869
2870
  );
2870
- this.actorClientLocationResolver?.invalidateActorRoute(actorRef.actorId);
2871
+ this.actorClientLocationResolver?.observeActorAuthorityVersion(
2872
+ actorRef.actorId,
2873
+ authority.storeVersion.value
2874
+ );
2871
2875
  },
2872
2876
  reportPostCommitError: (error) =>
2873
2877
  this.runtimeOrPreStartErrorSink.reportRuntimeTaskException(
@@ -2915,7 +2919,7 @@ export class ZLinkFrameworkRuntimeHost
2915
2919
  }).create();
2916
2920
  }
2917
2921
 
2918
- private createSpotNodeRuntimeOptions(
2922
+ createSpotNodeRuntimeOptions(
2919
2923
  context: ZLinkBackendContext,
2920
2924
  dispatchErrors: ZLinkDispatchErrorReporter
2921
2925
  ) {
@@ -3038,7 +3042,7 @@ export class ZLinkFrameworkRuntimeHost
3038
3042
  return;
3039
3043
  }
3040
3044
 
3041
- private dispatchMeshRecord(
3045
+ dispatchMeshRecord(
3042
3046
  applicationJobOrigin: () => ApplicationJobOrigin,
3043
3047
  meshName: string,
3044
3048
  owner: ReadyRecord,
@@ -3228,7 +3232,7 @@ export class ZLinkFrameworkRuntimeHost
3228
3232
  );
3229
3233
  }
3230
3234
 
3231
- private async dispatchMeshActorBinding(
3235
+ async dispatchMeshActorBinding(
3232
3236
  meshName: string,
3233
3237
  record: ReceiveRecord,
3234
3238
  signal?: AbortSignal
@@ -3317,8 +3321,7 @@ export class ZLinkFrameworkRuntimeHost
3317
3321
  replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
3318
3322
  return;
3319
3323
  }
3320
- replyBindingSuccess();
3321
- state.installBoundSessionBinding({
3324
+ const incomingTarget = {
3322
3325
  ...target,
3323
3326
  sessionNodeRid: binding.sessionNodeRid,
3324
3327
  sessionRid: binding.sessionRid,
@@ -3326,15 +3329,108 @@ export class ZLinkFrameworkRuntimeHost
3326
3329
  sessionOwnerId: binding.sessionOwnerId,
3327
3330
  sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
3328
3331
  bindingGeneration: binding.bindingGeneration
3332
+ };
3333
+ const currentBinding = state.boundSession;
3334
+ const currentActor = state.actor;
3335
+ if (
3336
+ currentBinding === undefined ||
3337
+ currentActor?.onDuplicateBind === undefined ||
3338
+ samePhysicalSession(currentBinding, incomingTarget)
3339
+ ) {
3340
+ state.installBoundSessionBinding(incomingTarget);
3341
+ replyBindingSuccess();
3342
+ return;
3343
+ }
3344
+ const spotManager = this.spotManager;
3345
+ if (spotManager === undefined || state.meshName === undefined) {
3346
+ replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
3347
+ return;
3348
+ }
3349
+
3350
+ let callbackStarted!: () => void;
3351
+ const started = new Promise<void>((resolve) => {
3352
+ callbackStarted = resolve;
3329
3353
  });
3330
- return Promise.resolve();
3354
+ let callbackTimedOut = false;
3355
+ let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
3356
+ const cancellation = new AbortController();
3357
+ const callbackSignal =
3358
+ signal === undefined ? cancellation.signal : AbortSignal.any([signal, cancellation.signal]);
3359
+ const turn = spotManager.executeActorTurn(
3360
+ state.meshName,
3361
+ state.actor?.context.spotId,
3362
+ state.actorId,
3363
+ async () => {
3364
+ const current = state.boundSession;
3365
+ const actor = state.actor;
3366
+ const duplicateCallback =
3367
+ current !== undefined && !samePhysicalSession(current, incomingTarget)
3368
+ ? actor?.onDuplicateBind
3369
+ : undefined;
3370
+ if (duplicateCallback === undefined || actor === undefined || current === undefined) {
3371
+ state.installBoundSessionBinding(incomingTarget);
3372
+ replyBindingSuccess();
3373
+ return;
3374
+ }
3375
+ callbackStarted();
3376
+ const decision = await duplicateCallback.call(
3377
+ actor,
3378
+ sessionBindingIdentity(current),
3379
+ sessionBindingIdentity(incomingTarget),
3380
+ callbackSignal
3381
+ );
3382
+ if (callbackTimedOut) return;
3383
+ if (decision !== undefined && decision.length > 0) {
3384
+ if (Buffer.byteLength(decision, 'utf8') > 0xffff) {
3385
+ throw new RangeError('Duplicate bind rejection message exceeds Text16 capacity.');
3386
+ }
3387
+ if (
3388
+ record.replyFailure?.(RequestResult.Rejected, 0, {
3389
+ kind: 'streamBindRejected',
3390
+ rejectionMessage: decision
3391
+ }) !== SubmitResult.Ok
3392
+ ) {
3393
+ throw new ZLinkConfigurationException(
3394
+ `MeshNode Actor binding target '${binding.actor.actorId}' rejection acknowledgement failed.`
3395
+ );
3396
+ }
3397
+ return;
3398
+ }
3399
+ state.installBoundSessionBinding(incomingTarget);
3400
+ replyBindingSuccess();
3401
+ }
3402
+ );
3403
+ const timeout = started.then(
3404
+ () =>
3405
+ new Promise<'timedOut'>((resolve) => {
3406
+ timeoutHandle = setTimeout(() => {
3407
+ callbackTimedOut = true;
3408
+ resolve('timedOut');
3409
+ }, this.options.registration.sessionReplacementCallbackTimeoutMs);
3410
+ })
3411
+ );
3412
+ try {
3413
+ const outcome = await Promise.race([turn.then(() => 'completed' as const), timeout]);
3414
+ if (outcome === 'timedOut') {
3415
+ cancellation.abort(createDeadlineExceededError('Duplicate bind callback timed out.'));
3416
+ if (record.replyFailure?.(RequestResult.TimedOut, 0) !== SubmitResult.Ok) {
3417
+ throw new ZLinkConfigurationException(
3418
+ `MeshNode Actor binding target '${binding.actor.actorId}' timeout acknowledgement failed.`
3419
+ );
3420
+ }
3421
+ void turn.catch((error: unknown) =>
3422
+ this.runtimeOrPreStartErrorSink.reportRuntimeTaskException(
3423
+ `duplicate bind callback '${binding.actor.actorId}'`,
3424
+ error
3425
+ )
3426
+ );
3427
+ }
3428
+ } finally {
3429
+ if (timeoutHandle !== undefined) clearTimeout(timeoutHandle);
3430
+ }
3331
3431
  }
3332
3432
 
3333
- private submitLocalMeshRoute(
3334
- meshName: string,
3335
- sourceNodeRid: string,
3336
- parts: readonly MessageLike[]
3337
- ) {
3433
+ submitLocalMeshRoute(meshName: string, sourceNodeRid: string, parts: readonly MessageLike[]) {
3338
3434
  const state = this.executionState;
3339
3435
  const channelRuntime = this.channelRuntime;
3340
3436
  if (
@@ -3392,7 +3488,7 @@ export class ZLinkFrameworkRuntimeHost
3392
3488
  return { status: ZLinkSubmitStatus.Submitted } as const;
3393
3489
  }
3394
3490
 
3395
- private async dispatchMeshSpotRecord(
3491
+ async dispatchMeshSpotRecord(
3396
3492
  meshName: string,
3397
3493
  owner: ReadyRecord,
3398
3494
  record: ReceiveRecord,
@@ -3409,7 +3505,8 @@ export class ZLinkFrameworkRuntimeHost
3409
3505
  contentType: envelope.header.contentType,
3410
3506
  sourceNodeRid: String(record.sourceNodeRid ?? '') as RoutingId,
3411
3507
  metadata: zlinkMessageMetadata(envelope.header.metadata),
3412
- correlationId: envelope.header.correlationId ?? undefined
3508
+ correlationId: envelope.header.correlationId ?? undefined,
3509
+ receivedAt: record.receivedAt ?? new Date()
3413
3510
  };
3414
3511
  try {
3415
3512
  const dispatch = async () => {
@@ -3440,9 +3537,7 @@ export class ZLinkFrameworkRuntimeHost
3440
3537
  await this.spotManager.dispatchMeshSpot(meshName, owner, record, admit);
3441
3538
  }
3442
3539
 
3443
- private createDispatchErrorReporter(
3444
- errorSink: ZLinkDispatchErrorSink
3445
- ): ZLinkDispatchErrorReporter {
3540
+ createDispatchErrorReporter(errorSink: ZLinkDispatchErrorSink): ZLinkDispatchErrorReporter {
3446
3541
  const existing = this.dispatchErrorReporters.get(errorSink);
3447
3542
  if (existing !== undefined) {
3448
3543
  return existing;
@@ -3477,7 +3572,7 @@ export class ZLinkFrameworkRuntimeHost
3477
3572
  return this.cachedDiagnosticsContext;
3478
3573
  }
3479
3574
 
3480
- private flowCreationEnabled(): boolean {
3575
+ flowCreationEnabled(): boolean {
3481
3576
  const mode =
3482
3577
  this.executionState === undefined
3483
3578
  ? (this.options.registration.dispatch?.diagnostics.messageFlow ?? 'errors')
@@ -3506,7 +3601,7 @@ export class ZLinkFrameworkRuntimeHost
3506
3601
  return this.locationOwner.ensureRuntime(this.meshRouters.primaryMeshName());
3507
3602
  }
3508
3603
 
3509
- private createLocationSpotRouteResolver(): ZLinkSpotRouteResolver | undefined {
3604
+ createLocationSpotRouteResolver(): ZLinkSpotRouteResolver | undefined {
3510
3605
  if (this.cachedLocationSpotRouteResolver !== undefined) {
3511
3606
  return this.cachedLocationSpotRouteResolver;
3512
3607
  }
@@ -3545,7 +3640,7 @@ export class ZLinkFrameworkRuntimeHost
3545
3640
  return resolver;
3546
3641
  }
3547
3642
 
3548
- private createActorLocationResolver(): ZLinkStoreLocationResolvers | undefined {
3643
+ createActorLocationResolver(): ZLinkStoreLocationResolvers | undefined {
3549
3644
  return this.locationOwner.createActorLocationResolver(this.meshRouters.spotLocationMeshNames());
3550
3645
  }
3551
3646
  }
@@ -3587,6 +3682,50 @@ export function hasUnsupportedManualTopology(registration: ZLinkFrameworkRegistr
3587
3682
  return false;
3588
3683
  }
3589
3684
 
3685
+ function samePhysicalSession(
3686
+ left: {
3687
+ readonly sessionNodeRid?: RoutingId;
3688
+ readonly sessionRid?: RoutingId;
3689
+ readonly sessionOwnerNodeGeneration?: bigint;
3690
+ },
3691
+ right: {
3692
+ readonly sessionNodeRid?: RoutingId;
3693
+ readonly sessionRid?: RoutingId;
3694
+ readonly sessionOwnerNodeGeneration?: bigint;
3695
+ }
3696
+ ): boolean {
3697
+ return (
3698
+ left.sessionNodeRid !== undefined &&
3699
+ left.sessionRid !== undefined &&
3700
+ left.sessionOwnerNodeGeneration !== undefined &&
3701
+ right.sessionNodeRid !== undefined &&
3702
+ right.sessionRid !== undefined &&
3703
+ right.sessionOwnerNodeGeneration !== undefined &&
3704
+ routingIdsEqual(left.sessionNodeRid, right.sessionNodeRid) &&
3705
+ left.sessionRid === right.sessionRid &&
3706
+ left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration
3707
+ );
3708
+ }
3709
+
3710
+ function sessionBindingIdentity(value: {
3711
+ readonly sessionNodeRid?: RoutingId;
3712
+ readonly sessionOwnerNodeGeneration?: bigint;
3713
+ readonly bindingGeneration?: bigint;
3714
+ }): ZLinkSessionBindingIdentity {
3715
+ if (
3716
+ value.sessionNodeRid === undefined ||
3717
+ value.sessionOwnerNodeGeneration === undefined ||
3718
+ value.bindingGeneration === undefined
3719
+ ) {
3720
+ throw new ZLinkConfigurationException('Duplicate bind callback requires a complete identity.');
3721
+ }
3722
+ return {
3723
+ sessionOwnerNodeRid: value.sessionNodeRid,
3724
+ sessionOwnerNodeGeneration: value.sessionOwnerNodeGeneration,
3725
+ bindingGeneration: value.bindingGeneration
3726
+ };
3727
+ }
3728
+
3590
3729
  function hasConfiguredLocationStore(registration: ZLinkFrameworkRegistration): boolean {
3591
3730
  return (
3592
3731
  registration.locations.useInMemoryStores || registration.locations.storeInstance !== undefined
@@ -32,8 +32,8 @@ export interface ZLinkLocationRuntimeStopSnapshot {
32
32
  }
33
33
 
34
34
  export class ZLinkLocationRuntimeOwner {
35
- private stores?: ZLinkLocationRuntimeStores;
36
- private runtime?: ZLinkLocationRuntime;
35
+ stores?: ZLinkLocationRuntimeStores;
36
+ runtime?: ZLinkLocationRuntime;
37
37
  private lifecycle?: ZLinkLocationLifecycle;
38
38
  private events?: ZLinkLocationEventSink;
39
39
  private leaseTrackerState?: {