@zlink-systems/framework 0.30.1 → 0.30.2

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 (340) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
  3. package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
  4. package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
  5. package/dist/contracts/Common/encoded-payload-storage.js +5 -2
  6. package/dist/contracts/Configuration/Builders.d.ts +1 -1
  7. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
  8. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
  9. package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
  10. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
  11. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
  12. package/dist/contracts/Locations/Rows.d.ts +2 -0
  13. package/dist/contracts/Spots/Contracts.d.ts +4 -0
  14. package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
  15. package/dist/runtime/abort.d.ts +5 -0
  16. package/dist/runtime/abort.js +10 -0
  17. package/dist/runtime/actors/actor-authority-publication.js +3 -2
  18. package/dist/runtime/actors/actor-client.d.ts +0 -1
  19. package/dist/runtime/actors/actor-client.js +38 -45
  20. package/dist/runtime/actors/actor-context.d.ts +2 -0
  21. package/dist/runtime/actors/actor-context.js +46 -9
  22. package/dist/runtime/actors/actor-handoff.d.ts +7 -3
  23. package/dist/runtime/actors/actor-handoff.js +212 -88
  24. package/dist/runtime/actors/actor-join-relocation.d.ts +2 -0
  25. package/dist/runtime/actors/actor-local-native-join.js +4 -0
  26. package/dist/runtime/actors/actor-mailbox.js +27 -1
  27. package/dist/runtime/actors/actor-remote-joiner.js +3 -1
  28. package/dist/runtime/actors/actor-reply.d.ts +4 -0
  29. package/dist/runtime/actors/actor-reply.js +29 -0
  30. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
  31. package/dist/runtime/actors/actor-runtime-state.js +2 -20
  32. package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
  33. package/dist/runtime/actors/index.d.ts +6 -2
  34. package/dist/runtime/actors/index.js +37 -21
  35. package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
  36. package/dist/runtime/actors/session-disconnected-wire.js +48 -0
  37. package/dist/runtime/admission.d.ts +9 -1
  38. package/dist/runtime/admission.js +55 -32
  39. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +13 -0
  40. package/dist/runtime/application-jobs/application-job-queue-scope.js +27 -1
  41. package/dist/runtime/application-jobs/contracts.d.ts +2 -0
  42. package/dist/runtime/backend/contracts/index.d.ts +19 -3
  43. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
  44. package/dist/runtime/backend/mesh-completion-table.js +5 -0
  45. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +26 -2
  46. package/dist/runtime/backend/mesh-dispatch-pump.js +193 -107
  47. package/dist/runtime/backend/node/node-raw-binding-port.js +90 -58
  48. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +33 -8
  49. package/dist/runtime/backend/node/node-raw-mesh-backend.js +142 -143
  50. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
  51. package/dist/runtime/backend/node/node-socket-backend-adapter.js +5 -5
  52. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  53. package/dist/runtime/channels/channel-clients.js +20 -5
  54. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +22 -3
  55. package/dist/runtime/channels/channel-dispatch-pipeline.js +103 -57
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +3 -2
  57. package/dist/runtime/channels/channel-dispatchers.js +44 -37
  58. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  59. package/dist/runtime/channels/channel-envelope.js +74 -31
  60. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
  61. package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
  62. package/dist/runtime/channels/channel-runtime-manager.d.ts +3 -2
  63. package/dist/runtime/channels/channel-runtime-manager.js +4 -4
  64. package/dist/runtime/channels/channel-transports.d.ts +0 -1
  65. package/dist/runtime/channels/channel-transports.js +35 -33
  66. package/dist/runtime/channels/client-server-location-runtime.js +5 -4
  67. package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
  68. package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
  69. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  70. package/dist/runtime/channels/fanout-location-runtime.js +3 -3
  71. package/dist/runtime/diagnostics/flow-context.js +19 -7
  72. package/dist/runtime/diagnostics/index.js +4 -9
  73. package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
  74. package/dist/runtime/diagnostics/message-flow.js +35 -5
  75. package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
  76. package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
  77. package/dist/runtime/execution/index.d.ts +4 -2
  78. package/dist/runtime/execution/index.js +33 -10
  79. package/dist/runtime/execution/serial-execution-queue.d.ts +4 -0
  80. package/dist/runtime/execution/serial-execution-queue.js +21 -2
  81. package/dist/runtime/execution/state-lane.d.ts +2 -0
  82. package/dist/runtime/execution/state-lane.js +5 -0
  83. package/dist/runtime/foundation/operation-registry.d.ts +25 -1
  84. package/dist/runtime/foundation/operation-registry.js +86 -18
  85. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +39 -3
  86. package/dist/runtime/foundation/raw-service-mesh-runtime.js +151 -55
  87. package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
  88. package/dist/runtime/foundation/service-liveness-registry.js +38 -0
  89. package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
  90. package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
  91. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -3
  92. package/dist/runtime/foundation/service-relocation-object-owner.js +48 -35
  93. package/dist/runtime/foundation/service-relocation-runtime.js +7 -3
  94. package/dist/runtime/foundation/service-runtime-contracts.d.ts +8 -1
  95. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
  96. package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
  97. package/dist/runtime/foundation/service-stateful-registry.js +24 -26
  98. package/dist/runtime/foundation/service-stateful-runtime.d.ts +72 -6
  99. package/dist/runtime/foundation/service-stateful-runtime.js +444 -117
  100. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -1
  101. package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
  102. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
  103. package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
  104. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  105. package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
  106. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +10 -0
  107. package/dist/runtime/foundation/service-wire-m6a-codec.js +166 -53
  108. package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
  109. package/dist/runtime/host/actor-packet-relay.js +59 -72
  110. package/dist/runtime/host/actor-placement-coordinator.js +25 -8
  111. package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
  112. package/dist/runtime/host/actor-transfer-runtime.js +85 -331
  113. package/dist/runtime/host/application-job-queue.d.ts +24 -3
  114. package/dist/runtime/host/application-job-queue.js +28 -41
  115. package/dist/runtime/host/index.d.ts +5 -1
  116. package/dist/runtime/host/index.js +171 -97
  117. package/dist/runtime/host/location-runtime-owner.js +2 -6
  118. package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
  119. package/dist/runtime/host/mesh-router-resolver.js +14 -6
  120. package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
  121. package/dist/runtime/host/remote-bound-session-relay.js +71 -190
  122. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
  123. package/dist/runtime/host/route-mesh-runtime.js +5 -3
  124. package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
  125. package/dist/runtime/host/runtime-shutdown.js +3 -2
  126. package/dist/runtime/host/service-relocation-host-runtime.d.ts +17 -7
  127. package/dist/runtime/host/service-relocation-host-runtime.js +550 -367
  128. package/dist/runtime/host/spot-runtime-options-factory.js +15 -7
  129. package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
  130. package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
  131. package/dist/runtime/locations/auto-connect-loop.js +22 -14
  132. package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
  133. package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
  134. package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
  135. package/dist/runtime/locations/descriptor-publication.js +11 -0
  136. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  137. package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
  138. package/dist/runtime/locations/in-memory-authority-store.js +56 -19
  139. package/dist/runtime/locations/in-memory-location-store.js +1 -10
  140. package/dist/runtime/locations/index.d.ts +1 -0
  141. package/dist/runtime/locations/index.js +1 -0
  142. package/dist/runtime/locations/lease-tracker.js +1 -6
  143. package/dist/runtime/locations/location-store-repository.d.ts +51 -1
  144. package/dist/runtime/locations/location-store-repository.js +363 -139
  145. package/dist/runtime/locations/relocation-blob.d.ts +18 -1
  146. package/dist/runtime/locations/relocation-blob.js +52 -1
  147. package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
  148. package/dist/runtime/locations/request-source-resolver.js +80 -0
  149. package/dist/runtime/locations/resolvers.js +1 -1
  150. package/dist/runtime/locations/runtime.d.ts +6 -2
  151. package/dist/runtime/locations/runtime.js +37 -30
  152. package/dist/runtime/messaging/payload-codec.d.ts +7 -1
  153. package/dist/runtime/messaging/payload-codec.js +7 -6
  154. package/dist/runtime/messaging/request-result.js +29 -26
  155. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +19 -1
  156. package/dist/runtime/protocol/service_wire_codec.generated.js +85 -0
  157. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +7 -1
  158. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +23 -7
  159. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +3 -2
  160. package/dist/runtime/spots/index.d.ts +18 -11
  161. package/dist/runtime/spots/index.js +234 -176
  162. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  163. package/dist/runtime/spots/spot-activation-registry.js +21 -11
  164. package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
  165. package/dist/runtime/spots/spot-activation-state.js +7 -7
  166. package/dist/runtime/spots/spot-activation.d.ts +6 -3
  167. package/dist/runtime/spots/spot-activation.js +123 -44
  168. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
  169. package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
  170. package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
  171. package/dist/runtime/spots/spot-actor-membership.js +0 -8
  172. package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
  173. package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
  174. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
  175. package/dist/runtime/spots/spot-entry-activation.js +14 -9
  176. package/dist/runtime/spots/spot-handler-registry.d.ts +4 -3
  177. package/dist/runtime/spots/spot-handler-registry.js +6 -2
  178. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
  179. package/dist/runtime/spots/spot-manager-public.js +2 -2
  180. package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
  181. package/dist/runtime/spots/spot-node-autoconnect.js +18 -39
  182. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
  183. package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
  184. package/dist/runtime/spots/spot-outbound.js +3 -3
  185. package/dist/runtime/spots/spot-remote-codec.js +5 -1
  186. package/dist/runtime/spots/spot-runtime-ports.d.ts +0 -1
  187. package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
  188. package/dist/runtime/spots/spot-serial-executor.js +61 -8
  189. package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
  190. package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
  191. package/dist/runtime/spots/spot-timer.d.ts +57 -5
  192. package/dist/runtime/spots/spot-timer.js +287 -103
  193. package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
  194. package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
  195. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
  196. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
  197. package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
  198. package/dist/runtime/streams/bound-session-service.d.ts +1 -1
  199. package/dist/runtime/streams/bound-session-service.js +6 -11
  200. package/dist/runtime/streams/index.d.ts +3 -2
  201. package/dist/runtime/streams/index.js +6 -4
  202. package/dist/runtime/streams/managed-stream.js +3 -2
  203. package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
  204. package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
  205. package/dist/runtime/streams/session-actor-coordinator.js +15 -32
  206. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
  207. package/dist/runtime/streams/stream-session-runtime.js +1 -4
  208. package/dist/runtime/workers/index.js +1 -1
  209. package/package.json +3 -3
  210. package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
  211. package/src/contracts/Common/encoded-payload-storage.ts +6 -3
  212. package/src/contracts/Configuration/Builders.ts +4 -1
  213. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
  214. package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
  215. package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
  216. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
  217. package/src/contracts/Locations/Rows.ts +2 -0
  218. package/src/contracts/Spots/Contracts.ts +8 -0
  219. package/src/contracts/Spots/ZLinkSpot.ts +3 -3
  220. package/src/runtime/abort.ts +12 -0
  221. package/src/runtime/actors/actor-authority-publication.ts +3 -2
  222. package/src/runtime/actors/actor-client.ts +61 -70
  223. package/src/runtime/actors/actor-context.ts +49 -9
  224. package/src/runtime/actors/actor-handoff.ts +282 -106
  225. package/src/runtime/actors/actor-join-relocation.ts +2 -0
  226. package/src/runtime/actors/actor-local-native-join.ts +4 -0
  227. package/src/runtime/actors/actor-mailbox.ts +40 -2
  228. package/src/runtime/actors/actor-remote-joiner.ts +6 -1
  229. package/src/runtime/actors/actor-reply.ts +42 -0
  230. package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
  231. package/src/runtime/actors/actor-runtime-state.ts +2 -20
  232. package/src/runtime/actors/actor-source-transfer.ts +1 -34
  233. package/src/runtime/actors/index.ts +41 -27
  234. package/src/runtime/actors/session-disconnected-wire.ts +66 -0
  235. package/src/runtime/admission.ts +69 -34
  236. package/src/runtime/application-jobs/application-job-queue-scope.ts +33 -1
  237. package/src/runtime/application-jobs/contracts.ts +2 -0
  238. package/src/runtime/backend/contracts/index.ts +39 -4
  239. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
  240. package/src/runtime/backend/mesh-completion-table.ts +4 -0
  241. package/src/runtime/backend/mesh-dispatch-pump.ts +223 -124
  242. package/src/runtime/backend/node/node-raw-binding-port.ts +106 -70
  243. package/src/runtime/backend/node/node-raw-mesh-backend.ts +221 -170
  244. package/src/runtime/backend/node/node-socket-backend-adapter.ts +5 -5
  245. package/src/runtime/channels/channel-clients.ts +49 -24
  246. package/src/runtime/channels/channel-dispatch-pipeline.ts +173 -124
  247. package/src/runtime/channels/channel-dispatchers.ts +116 -72
  248. package/src/runtime/channels/channel-envelope.ts +105 -36
  249. package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
  250. package/src/runtime/channels/channel-runtime-manager.ts +12 -5
  251. package/src/runtime/channels/channel-transports.ts +49 -58
  252. package/src/runtime/channels/client-server-location-runtime.ts +11 -10
  253. package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
  254. package/src/runtime/channels/fanout-location-runtime.ts +17 -9
  255. package/src/runtime/diagnostics/flow-context.ts +20 -7
  256. package/src/runtime/diagnostics/index.ts +1 -7
  257. package/src/runtime/diagnostics/message-flow.ts +47 -9
  258. package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
  259. package/src/runtime/execution/index.ts +40 -14
  260. package/src/runtime/execution/serial-execution-queue.ts +31 -4
  261. package/src/runtime/execution/state-lane.ts +7 -0
  262. package/src/runtime/foundation/operation-registry.ts +98 -20
  263. package/src/runtime/foundation/raw-service-mesh-runtime.ts +244 -67
  264. package/src/runtime/foundation/service-liveness-registry.ts +39 -0
  265. package/src/runtime/foundation/service-mailbox.ts +8 -0
  266. package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
  267. package/src/runtime/foundation/service-relocation-object-owner.ts +54 -37
  268. package/src/runtime/foundation/service-relocation-runtime.ts +7 -3
  269. package/src/runtime/foundation/service-runtime-contracts.ts +12 -1
  270. package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
  271. package/src/runtime/foundation/service-stateful-registry.ts +38 -35
  272. package/src/runtime/foundation/service-stateful-runtime.ts +667 -152
  273. package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -11
  274. package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
  275. package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
  276. package/src/runtime/foundation/service-wire-m6a-codec.ts +187 -51
  277. package/src/runtime/host/actor-packet-relay.ts +113 -94
  278. package/src/runtime/host/actor-placement-coordinator.ts +31 -8
  279. package/src/runtime/host/actor-transfer-runtime.ts +104 -430
  280. package/src/runtime/host/application-job-queue.ts +29 -44
  281. package/src/runtime/host/index.ts +286 -129
  282. package/src/runtime/host/location-runtime-owner.ts +2 -6
  283. package/src/runtime/host/mesh-router-resolver.ts +13 -5
  284. package/src/runtime/host/remote-bound-session-relay.ts +86 -248
  285. package/src/runtime/host/route-mesh-runtime.ts +11 -5
  286. package/src/runtime/host/runtime-shutdown.ts +15 -4
  287. package/src/runtime/host/service-relocation-host-runtime.ts +784 -475
  288. package/src/runtime/host/spot-runtime-options-factory.ts +18 -7
  289. package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
  290. package/src/runtime/locations/auto-connect-loop.ts +22 -14
  291. package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
  292. package/src/runtime/locations/auto-connect-types.ts +0 -1
  293. package/src/runtime/locations/descriptor-publication.ts +7 -0
  294. package/src/runtime/locations/domain-store-contract.ts +5 -0
  295. package/src/runtime/locations/in-memory-authority-store.ts +85 -23
  296. package/src/runtime/locations/in-memory-location-store.ts +1 -12
  297. package/src/runtime/locations/index.ts +1 -0
  298. package/src/runtime/locations/lease-tracker.ts +2 -9
  299. package/src/runtime/locations/location-store-repository.ts +628 -152
  300. package/src/runtime/locations/relocation-blob.ts +75 -1
  301. package/src/runtime/locations/request-source-resolver.ts +138 -0
  302. package/src/runtime/locations/resolvers.ts +2 -2
  303. package/src/runtime/locations/runtime.ts +70 -40
  304. package/src/runtime/messaging/payload-codec.ts +8 -11
  305. package/src/runtime/messaging/request-result.ts +33 -29
  306. package/src/runtime/protocol/service_wire_codec.generated.ts +87 -4
  307. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +13 -10
  308. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +3 -2
  309. package/src/runtime/spots/index.ts +375 -281
  310. package/src/runtime/spots/spot-activation-registry.ts +25 -13
  311. package/src/runtime/spots/spot-activation-state.ts +12 -19
  312. package/src/runtime/spots/spot-activation.ts +170 -86
  313. package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
  314. package/src/runtime/spots/spot-actor-membership.ts +0 -15
  315. package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
  316. package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
  317. package/src/runtime/spots/spot-entry-activation.ts +24 -19
  318. package/src/runtime/spots/spot-handler-registry.ts +15 -4
  319. package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
  320. package/src/runtime/spots/spot-manager-public.ts +2 -2
  321. package/src/runtime/spots/spot-node-autoconnect.ts +22 -45
  322. package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
  323. package/src/runtime/spots/spot-outbound.ts +3 -3
  324. package/src/runtime/spots/spot-remote-codec.ts +9 -2
  325. package/src/runtime/spots/spot-runtime-ports.ts +0 -1
  326. package/src/runtime/spots/spot-serial-executor.ts +97 -25
  327. package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
  328. package/src/runtime/spots/spot-subscription-dispatch.ts +1 -1
  329. package/src/runtime/spots/spot-timer.ts +413 -157
  330. package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
  331. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
  332. package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
  333. package/src/runtime/streams/bound-session-service.ts +7 -10
  334. package/src/runtime/streams/index.ts +12 -6
  335. package/src/runtime/streams/managed-stream.ts +4 -2
  336. package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
  337. package/src/runtime/streams/session-actor-coordinator.ts +39 -88
  338. package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
  339. package/src/runtime/streams/stream-session-runtime.ts +1 -5
  340. package/src/runtime/workers/index.ts +1 -1
@@ -1,6 +1,7 @@
1
1
  import { type ActorRef, type RoutingId, ZLinkFrameworkException } from '../../contracts';
2
2
 
3
3
  import type { Message } from '../../contracts/Common/Message';
4
+ import { DEFAULT_REQUEST_TIMEOUT_MS } from '../../contracts/Configuration/Registration';
4
5
  import { zlinkDefaultLocationOptions } from '../../contracts/Locations/Options';
5
6
  import { releaseApplicationJobPermitForDurableHandoff } from '../application-jobs/application-job-queue-scope';
6
7
  import type { ApplicationJobOrigin } from '../application-jobs/contracts';
@@ -10,12 +11,22 @@ import {
10
11
  type MessageFollowSuppressionFence
11
12
  } from '../foundation/message-follow-suppression-registry';
12
13
  import type { ZLinkMessageFollowOrigin } from '../foundation/service-runtime-contracts';
14
+ import { RELOCATION_REPLY_RETENTION_MS } from '../foundation/service-stateful-registry';
15
+ import type { ServiceActorRouteFence } from '../foundation/service-stateful-wire-codec';
16
+ import { OPERATION_IDENTITY_BYTES } from '../foundation/operation-identity';
17
+ import { UINT64_BYTES } from '@zlink-systems/stream-wire';
13
18
  import {
14
19
  createInternalFrameworkException,
15
20
  internalFrameworkErrorKind,
16
21
  ZLinkFrameworkInternalErrorKind
17
22
  } from '../framework-errors-internal';
18
- import { encodeRoutingIdStorageHex, routingIdsEqual } from '../routing-id';
23
+ import { waitRequestReply } from '../messaging/request-deadline';
24
+ import {
25
+ decodeRoutingId,
26
+ encodeRoutingIdStorageHex,
27
+ routingIdsEqual,
28
+ routingIdWireHex
29
+ } from '../routing-id';
19
30
  import type { ZLinkSpotRouteTarget } from '../spots/spot-routing-internal';
20
31
  import { decodeActorRequestDeadlineUnixMs, decodeStreamHeader } from '../streams/protocol';
21
32
  import {
@@ -43,7 +54,7 @@ import type { ZLinkRemoteBoundSessionTarget } from './actor-runtime-state';
43
54
 
44
55
  export const DEFAULT_MESSAGE_FOLLOW_DURATION_MS =
45
56
  zlinkDefaultLocationOptions.messageFollowDurationMs;
46
- const RELOCATION_REPLY_RETENTION_MS = 24 * 60 * 60 * 1_000;
57
+ export const RELOCATED_REQUEST_OWNED_BY_REQUESTER = Symbol('relocated request owned by requester');
47
58
 
48
59
  export interface ZLinkActorHandoffPacket {
49
60
  readonly index: number;
@@ -74,6 +85,7 @@ export interface ZLinkActorHandoffRequestSource {
74
85
  readonly ownerId: string;
75
86
  readonly ownerLeaseGeneration: string;
76
87
  readonly nodeRid: string;
88
+ readonly nodeRidHex?: string;
77
89
  readonly nodeGeneration: string;
78
90
  readonly replyRouteId: string;
79
91
  }
@@ -119,6 +131,7 @@ export interface ZLinkActorHandoffPrefixAdmission {
119
131
  }
120
132
 
121
133
  export interface ZLinkActorHandoffPrefixRecord {
134
+ readonly onWithdrawable?: (withdraw: () => boolean) => void;
122
135
  readonly drain: (dispatch: ZLinkActorHandoffDispatch) => Promise<void>;
123
136
  readonly preparation?: {
124
137
  prepare(signal: AbortSignal): Promise<void>;
@@ -139,6 +152,7 @@ export type ZLinkActorHandoffPrefixQueue = (
139
152
  ) => ZLinkActorHandoffPrefixAdmission;
140
153
 
141
154
  interface PendingPacket {
155
+ withdraw?: () => boolean;
142
156
  readonly origin: ApplicationJobOrigin;
143
157
  readonly packet: ZLinkActorHandoffPacket;
144
158
  readonly resolve?: (value: unknown) => void;
@@ -290,7 +304,12 @@ function requireExactTargetOwnerFence(
290
304
  /** Owns packet ordering from relocation start through Message Follow removal. */
291
305
  export class ZLinkActorHandoffCoordinator {
292
306
  private readonly active = new Map<string, ActiveHandoff>();
293
- private readonly messageFollowRoutes = new Map<string, MessageFollowRoute>();
307
+ // Each route is stored once: Actor -> native fence -> location owner id.
308
+ // Native ingress has the complete fence except the location owner's text id.
309
+ private readonly messageFollowRoutes = new Map<
310
+ string,
311
+ Map<string, Map<string, MessageFollowRoute>>
312
+ >();
294
313
  private readonly messageFollowSuppression = new MessageFollowSuppressionRegistry();
295
314
  // Relocation preserves ObjectGeneration, so (nodeRid, objectGeneration) alone
296
315
  // also matches a tenure that later RETURNS to a previously-visited node. The
@@ -322,7 +341,10 @@ export class ZLinkActorHandoffCoordinator {
322
341
  oldGeneration: bigint,
323
342
  phase: 'relocating' | 'provisional'
324
343
  ): void {
325
- if (this.active.has(actorId)) {
344
+ // A releasing handoff has returned its hold to the Actor FIFO; only its
345
+ // durable prefix drain remains, and the next hold takes over its ingress.
346
+ const previous = this.active.get(actorId);
347
+ if (this.isActive(actorId)) {
326
348
  throw new Error(`Actor '${actorId}' already has an active packet handoff.`);
327
349
  }
328
350
  if (oldGeneration <= 0n) {
@@ -362,6 +384,24 @@ export class ZLinkActorHandoffCoordinator {
362
384
  nodeGeneration: source.nodeGeneration,
363
385
  authorityOwnerGeneration: source.authorityOwnerGeneration
364
386
  });
387
+ const pending: PendingPacket[] = [];
388
+ if (previous?.prefixRelease !== undefined) {
389
+ // Only records still in the FIFO belong to the new barrier. Running
390
+ // records keep their existing terminal; withdrawn records surrender
391
+ // readiness and move their payload before later ingress can arrive.
392
+ for (let index = 0; index < previous.pending.length;) {
393
+ const record = previous.pending[index]!;
394
+ if (record.withdraw?.() === true) {
395
+ record.withdraw = undefined;
396
+ pending.push(record);
397
+ previous.pending.splice(index, 1);
398
+ previous.prefixRelease.cursor -= 1;
399
+ previous.pendingBytes -= packetBytes(record.packet);
400
+ } else {
401
+ index += 1;
402
+ }
403
+ }
404
+ }
365
405
  this.active.set(actorId, {
366
406
  oldGeneration,
367
407
  oldNodeRid: sourceOwner.nodeRid,
@@ -371,29 +411,23 @@ export class ZLinkActorHandoffCoordinator {
371
411
  phase,
372
412
  deferredJoin: phase === 'provisional',
373
413
  connectionBoundSealed: false,
374
- pending: [],
375
- nextIndex: 0,
414
+ pending,
415
+ nextIndex: pending.reduce((next, record) => Math.max(next, record.packet.index + 1), 0),
376
416
  snapshotIndex: -1,
377
- pendingBytes: 0
417
+ pendingBytes: pending.reduce((bytes, record) => bytes + packetBytes(record.packet), 0)
378
418
  });
379
419
  }
380
420
 
421
+ /** True while a hold owns this Actor's ingress, before its release to the Actor FIFO. */
381
422
  isActive(actorId: string): boolean {
382
- return this.active.has(actorId);
423
+ const handoff = this.active.get(actorId);
424
+ return handoff !== undefined && handoff.phase !== 'releasing';
383
425
  }
384
426
 
385
427
  isProvisional(actorId: string): boolean {
386
428
  return this.active.get(actorId)?.phase === 'provisional';
387
429
  }
388
430
 
389
- promoteProvisional(actorId: string): void {
390
- const handoff = this.active.get(actorId);
391
- if (handoff?.phase !== 'provisional') {
392
- throw new Error(`Actor '${actorId}' does not have a provisional packet handoff.`);
393
- }
394
- handoff.phase = 'relocating';
395
- }
396
-
397
431
  sealConnectionBoundIngress(actorId: string): void {
398
432
  const handoff = this.active.get(actorId);
399
433
  if (handoff !== undefined) handoff.connectionBoundSealed = true;
@@ -459,6 +493,44 @@ export class ZLinkActorHandoffCoordinator {
459
493
  return this.admitHandoffPrefix(actorId, handoff, queue, preparation, start);
460
494
  }
461
495
 
496
+ /** Installs a restored target's payload in the same owner used by local handoffs. */
497
+ admitTransferredPrefix(
498
+ actorId: string,
499
+ objectGeneration: bigint,
500
+ packets: readonly ZLinkActorHandoffPacket[],
501
+ queue: ZLinkActorHandoffPrefixQueue,
502
+ preparation: ZLinkActorHandoffReplayPreparation | undefined,
503
+ start: Promise<void>,
504
+ onResult: (packet: ZLinkActorHandoffPacket, result: ZLinkActorHandoffResult) => void
505
+ ): ZLinkActorHandoffPrefixAdmission {
506
+ this.beginProvisional(actorId, objectGeneration);
507
+ const handoff = this.requireActive(actorId);
508
+ for (const packet of packets) {
509
+ handoff.pending.push({
510
+ packet,
511
+ origin: 'remote',
512
+ resolve: (response) => {
513
+ if (response !== RELOCATED_REQUEST_OWNED_BY_REQUESTER) {
514
+ onResult(packet, { index: packet.index, ok: true, response });
515
+ }
516
+ },
517
+ reject: (error) =>
518
+ onResult(packet, {
519
+ index: packet.index,
520
+ ok: false,
521
+ error: error instanceof Error ? error.message : String(error),
522
+ errorKind:
523
+ error instanceof ZLinkFrameworkException
524
+ ? internalFrameworkErrorKind(error)
525
+ : undefined
526
+ })
527
+ });
528
+ handoff.nextIndex = Math.max(handoff.nextIndex, packet.index + 1);
529
+ handoff.pendingBytes += packetBytes(packet);
530
+ }
531
+ return this.admitHandoffPrefix(actorId, handoff, queue, preparation, start);
532
+ }
533
+
462
534
  private admitHandoffPrefix(
463
535
  actorId: string,
464
536
  handoff: ActiveHandoff,
@@ -551,6 +623,9 @@ export class ZLinkActorHandoffCoordinator {
551
623
  prepared = undefined;
552
624
  };
553
625
  return {
626
+ onWithdrawable: (withdraw) => {
627
+ pending.withdraw = withdraw;
628
+ },
554
629
  payloadBytes: packetBytes(pending.packet),
555
630
  preparation: {
556
631
  prepare: async (signal) => {
@@ -572,6 +647,9 @@ export class ZLinkActorHandoffCoordinator {
572
647
  cancel
573
648
  },
574
649
  drain: async (replay) => {
650
+ // The FIFO claim, rather than this prefix's eventual terminal,
651
+ // ends the record's durable ownership and transfer capability.
652
+ pending.withdraw = undefined;
575
653
  const admission =
576
654
  prepared === undefined
577
655
  ? undefined
@@ -779,11 +857,38 @@ export class ZLinkActorHandoffCoordinator {
779
857
  provisionalReplay?: ZLinkActorHandoffDispatch,
780
858
  onAdmitted?: () => void
781
859
  ): Promise<unknown> | undefined {
782
- const incomingContext = actorMessageFollowContext(fallbackActorRef);
860
+ let incomingContext = actorMessageFollowContext(fallbackActorRef);
783
861
  const originalDeadlineUnixMs =
784
862
  deadlineUnixMs ?? incomingContext?.deadlineUnixMs ?? packetDeadlineUnixMs(parts);
785
- const handoff = this.active.get(actorId);
863
+ const followRoute = this.findMessageFollowRoute(
864
+ actorId,
865
+ incomingContext,
866
+ messageFollowOrigin?.target
867
+ );
868
+ // An exact departed tenure belongs to its committed route, even while the
869
+ // same Actor incarnation is performing a later Join on this node.
870
+ const handoff = followRoute === undefined ? this.active.get(actorId) : undefined;
871
+ if (
872
+ incomingContext === undefined &&
873
+ followRoute !== undefined &&
874
+ messageFollowOrigin?.target !== undefined
875
+ ) {
876
+ incomingContext = this.createInitialIngressContext(
877
+ followRoute.sourceOwner,
878
+ messageFollowOrigin.target.actor.generation,
879
+ parts,
880
+ returnResponse,
881
+ originalDeadlineUnixMs,
882
+ messageFollowOrigin
883
+ );
884
+ }
786
885
  if (handoff !== undefined) {
886
+ if (
887
+ handoff.phase === 'releasing' &&
888
+ handoff.prefixRelease !== undefined &&
889
+ handoff.pending.at(-1)?.withdraw === undefined
890
+ )
891
+ return undefined;
787
892
  if (parts.length < 2) return Promise.resolve(undefined);
788
893
  if (
789
894
  handoff.connectionBoundSealed &&
@@ -806,10 +911,15 @@ export class ZLinkActorHandoffCoordinator {
806
911
  handoff.oldGeneration,
807
912
  parts,
808
913
  returnResponse,
809
- originalDeadlineUnixMs
914
+ originalDeadlineUnixMs,
915
+ messageFollowOrigin
810
916
  );
811
917
  try {
812
918
  this.validateContext(actorId, context, parts, returnResponse, fallbackActorRef);
919
+ // Accepted handoff retains its original deadline; Message Follow uses a local relay window.
920
+ if (context.deadlineUnixMs !== undefined && Date.now() >= context.deadlineUnixMs) {
921
+ throw actorDeadlineExceeded(actorId);
922
+ }
813
923
  } catch (error) {
814
924
  return Promise.reject(error);
815
925
  }
@@ -844,8 +954,25 @@ export class ZLinkActorHandoffCoordinator {
844
954
  return Promise.resolve(undefined);
845
955
  }
846
956
  const result = new Promise((resolve, reject) => {
847
- const source = this.captureRequestSource(handoff.sourceEvidence, context.replyRouteId);
957
+ const original = messageFollowOrigin?.requestSource;
958
+ const originalRidHex =
959
+ original === undefined ? undefined : routingIdWireHex(original.nodeRid);
960
+ const source =
961
+ original === undefined
962
+ ? this.captureRequestSource(handoff.sourceEvidence, context.replyRouteId)
963
+ : {
964
+ ownerId: original.ownerId,
965
+ ownerLeaseGeneration: original.leaseGeneration.toString(),
966
+ nodeRid: String(original.nodeRid),
967
+ ...(originalRidHex === undefined ? {} : { nodeRidHex: originalRidHex }),
968
+ nodeGeneration: original.nodeGeneration.toString(),
969
+ replyRouteId: messageFollowOrigin!.originalReplyRouteId.toString()
970
+ };
848
971
  const requestPacket = { ...packet, source };
972
+ if (original !== undefined) {
973
+ handoff.pending.push({ packet: requestPacket, origin, resolve, reject });
974
+ return;
975
+ }
849
976
  const route: ReplyRoute = {
850
977
  actorId,
851
978
  operationId: requestPacket.messageFollowContext.operationId,
@@ -885,7 +1012,6 @@ export class ZLinkActorHandoffCoordinator {
885
1012
  return result;
886
1013
  }
887
1014
 
888
- const followRoute = this.findMessageFollowRoute(actorId, incomingContext);
889
1015
  const staleGeneration = fallbackActorRef?.objectGeneration;
890
1016
  if (
891
1017
  fallbackActorRef !== undefined &&
@@ -984,19 +1110,6 @@ export class ZLinkActorHandoffCoordinator {
984
1110
  return handoff.pending.map((entry) => entry.packet);
985
1111
  }
986
1112
 
987
- snapshotCoreBacklog(actorId: string): readonly ZLinkActorHandoffPacket[] {
988
- const handoff = this.requireActive(actorId);
989
- let snapshotIndex = -1;
990
- while (
991
- snapshotIndex + 1 < handoff.pending.length &&
992
- handoff.pending[snapshotIndex + 1].packet.returnResponse === false
993
- ) {
994
- snapshotIndex++;
995
- }
996
- handoff.snapshotIndex = snapshotIndex;
997
- return handoff.pending.slice(0, snapshotIndex + 1).map((entry) => entry.packet);
998
- }
999
-
1000
1113
  /**
1001
1114
  * Freezes the post-capture ingress segment immediately before the caller
1002
1115
  * appends the one-way cutover on the same relocation lane. Records returned
@@ -1015,14 +1128,25 @@ export class ZLinkActorHandoffCoordinator {
1015
1128
  target: ZLinkSpotRouteTarget,
1016
1129
  targetActorRef: ActorRef,
1017
1130
  results: readonly ZLinkActorHandoffResult[],
1018
- targetOwnerFence: ZLinkActorMessageFollowOwnerFence
1131
+ targetOwnerFence: ZLinkActorMessageFollowOwnerFence | null
1019
1132
  ): void {
1020
1133
  const handoff = this.requireActive(actorId);
1021
- const committedTargetOwner = requireExactTargetOwnerFence(actorId, targetOwnerFence);
1134
+ const committedTargetOwner =
1135
+ targetOwnerFence === null ? null : requireExactTargetOwnerFence(actorId, targetOwnerFence);
1022
1136
  this.active.delete(actorId);
1137
+ // Location runtime §10: a later owner has no source-local Follow route.
1138
+ if (committedTargetOwner === null) {
1139
+ const unavailable = actorLocationStale(actorId);
1140
+ for (const pending of handoff.pending) this.failReleasedPending(pending, unavailable);
1141
+ return;
1142
+ }
1023
1143
  const byIndex = new Map(results.map((result) => [result.index, result]));
1024
1144
  for (let i = 0; i <= handoff.snapshotIndex; i++) {
1025
1145
  const pending = handoff.pending[i];
1146
+ if (pending.packet.messageFollowOrigin?.requestSource !== undefined) {
1147
+ pending.resolve?.(RELOCATED_REQUEST_OWNED_BY_REQUESTER);
1148
+ continue;
1149
+ }
1026
1150
  if (pending.packet.source !== undefined) continue;
1027
1151
  const result = byIndex.get(pending.packet.index);
1028
1152
  if (result?.ok === false) {
@@ -1074,11 +1198,16 @@ export class ZLinkActorHandoffCoordinator {
1074
1198
  }
1075
1199
 
1076
1200
  messageFollowCount(actorId?: string): number {
1077
- return actorId === undefined
1078
- ? this.messageFollowRoutes.size
1079
- : [...this.messageFollowRoutes.values()].filter(
1080
- (route) => route.targetActorRef.actorId === actorId
1081
- ).length;
1201
+ let count = 0;
1202
+ if (actorId === undefined) {
1203
+ for (const id of this.messageFollowRoutes.keys()) count += this.messageFollowCount(id);
1204
+ } else {
1205
+ const routes = this.messageFollowRoutes.get(actorId);
1206
+ if (routes !== undefined) {
1207
+ for (const owners of routes.values()) count += owners.size;
1208
+ }
1209
+ }
1210
+ return count;
1082
1211
  }
1083
1212
 
1084
1213
  pendingCount(actorId: string): number {
@@ -1087,7 +1216,7 @@ export class ZLinkActorHandoffCoordinator {
1087
1216
 
1088
1217
  isKnownStale(actor: ActorRef): boolean {
1089
1218
  return (
1090
- this.messageFollowCount(actor.actorId) === 0 &&
1219
+ !this.messageFollowRoutes.has(actor.actorId) &&
1091
1220
  this.options.isCurrentActorRef?.(actor.actorId, actor) !== true &&
1092
1221
  this.isKnownStaleRef(actor.actorId, actor)
1093
1222
  );
@@ -1244,8 +1373,24 @@ export class ZLinkActorHandoffCoordinator {
1244
1373
  refs.set(exactRefKey, departedAuthorityOwnerGeneration);
1245
1374
  }
1246
1375
  }
1247
- const key = messageFollowRouteKey(actorId, oldGeneration, sourceOwner);
1248
- const previous = this.messageFollowRoutes.get(key);
1376
+ const key = messageFollowRouteKey(
1377
+ oldGeneration,
1378
+ sourceOwner.nodeRidHex ?? encodeRoutingIdStorageHex(sourceOwner.nodeRid),
1379
+ sourceOwner.nodeGeneration,
1380
+ sourceOwner.authorityOwnerGeneration,
1381
+ sourceOwner.ownerLeaseGeneration
1382
+ );
1383
+ let routes = this.messageFollowRoutes.get(actorId);
1384
+ if (routes === undefined) {
1385
+ routes = new Map();
1386
+ this.messageFollowRoutes.set(actorId, routes);
1387
+ }
1388
+ let owners = routes.get(key);
1389
+ if (owners === undefined) {
1390
+ owners = new Map();
1391
+ routes.set(key, owners);
1392
+ }
1393
+ const previous = owners.get(sourceOwner.ownerId);
1249
1394
  if (previous !== undefined) clearTimeout(previous.deadline);
1250
1395
  const suppressionFence = actorMessageFollowSuppressionFence(
1251
1396
  actorId,
@@ -1281,15 +1426,21 @@ export class ZLinkActorHandoffCoordinator {
1281
1426
  } else {
1282
1427
  this.messageFollowSuppression.replaceRoute(previous.suppressionFence, suppressionFence);
1283
1428
  }
1284
- this.messageFollowRoutes.set(key, entry);
1429
+ owners.set(sourceOwner.ownerId, entry);
1285
1430
  this.options.onMarker?.('message_follow_registered', actorId, this.messageFollowDurationMs);
1286
1431
  return entry;
1287
1432
  }
1288
1433
 
1289
1434
  private removeMessageFollowRoute(entry: MessageFollowRoute): void {
1290
- if (this.messageFollowRoutes.get(entry.key) !== entry) return;
1435
+ const actorId = entry.targetActorRef.actorId;
1436
+ const routes = this.messageFollowRoutes.get(actorId);
1437
+ if (routes === undefined) return;
1438
+ const owners = routes.get(entry.key);
1439
+ if (owners?.get(entry.sourceOwner.ownerId) !== entry) return;
1291
1440
  clearTimeout(entry.deadline);
1292
- this.messageFollowRoutes.delete(entry.key);
1441
+ owners.delete(entry.sourceOwner.ownerId);
1442
+ if (owners.size === 0) routes.delete(entry.key);
1443
+ if (routes.size === 0) this.messageFollowRoutes.delete(actorId);
1293
1444
  this.messageFollowSuppression.expireRoute(entry.suppressionFence);
1294
1445
  this.pruneStaleTenureRecords(entry);
1295
1446
  this.options.onMarker?.('message_follow_route_removed', entry.targetActorRef.actorId);
@@ -1328,22 +1479,54 @@ export class ZLinkActorHandoffCoordinator {
1328
1479
 
1329
1480
  private findMessageFollowRoute(
1330
1481
  actorId: string,
1331
- context: ZLinkActorMessageFollowContext | undefined
1482
+ context: ZLinkActorMessageFollowContext | undefined,
1483
+ nativeTarget?: ServiceActorRouteFence
1332
1484
  ): MessageFollowRoute | undefined {
1333
- if (context === undefined) return undefined;
1334
- return this.messageFollowRoutes.get(
1335
- messageFollowRouteKey(actorId, BigInt(context.objectGeneration), context.targetOwner)
1336
- );
1485
+ const routes = this.messageFollowRoutes.get(actorId);
1486
+ if (routes === undefined) return undefined;
1487
+ if (context === undefined) {
1488
+ if (nativeTarget === undefined || nativeTarget.actor.actorId !== actorId) return undefined;
1489
+ return routes
1490
+ .get(
1491
+ messageFollowRouteKey(
1492
+ nativeTarget.actor.generation,
1493
+ encodeRoutingIdStorageHex(nativeTarget.actor.nodeRid),
1494
+ nativeTarget.targetNodeGeneration,
1495
+ nativeTarget.authorityOwnerGeneration,
1496
+ nativeTarget.ownerLeaseGeneration
1497
+ )
1498
+ )
1499
+ ?.values()
1500
+ .next().value;
1501
+ }
1502
+ const owner = context.targetOwner;
1503
+ return routes
1504
+ .get(
1505
+ messageFollowRouteKey(
1506
+ BigInt(context.objectGeneration),
1507
+ owner.nodeRidHex ?? encodeRoutingIdStorageHex(owner.nodeRid),
1508
+ owner.nodeGeneration,
1509
+ owner.authorityOwnerGeneration,
1510
+ owner.ownerLeaseGeneration
1511
+ )
1512
+ )
1513
+ ?.get(owner.ownerId);
1337
1514
  }
1338
1515
 
1339
1516
  private hasMessageFollowRouteForStaleRef(actorId: string, actorRef: ActorRef): boolean {
1340
- return [...this.messageFollowRoutes.values()].some(
1341
- (route) =>
1342
- route.targetActorRef.actorId === actorId &&
1343
- actorRef.objectGeneration === route.oldGeneration &&
1344
- (route.oldNodeRid === undefined ||
1345
- routingIdsEqual(actorRef.nodeRid, messageFollowOwnerNodeRid(route.sourceOwner)))
1346
- );
1517
+ const routes = this.messageFollowRoutes.get(actorId);
1518
+ if (routes === undefined) return false;
1519
+ for (const owners of routes.values()) {
1520
+ for (const route of owners.values()) {
1521
+ if (
1522
+ actorRef.objectGeneration === route.oldGeneration &&
1523
+ (route.oldNodeRid === undefined ||
1524
+ routingIdsEqual(actorRef.nodeRid, messageFollowOwnerNodeRid(route.sourceOwner)))
1525
+ )
1526
+ return true;
1527
+ }
1528
+ }
1529
+ return false;
1347
1530
  }
1348
1531
 
1349
1532
  private createInitialIngressContext(
@@ -1351,9 +1534,21 @@ export class ZLinkActorHandoffCoordinator {
1351
1534
  generation: bigint,
1352
1535
  parts: readonly Message[],
1353
1536
  request: boolean,
1354
- deadlineUnixMs?: number
1537
+ deadlineUnixMs?: number,
1538
+ origin?: ZLinkMessageFollowOrigin
1355
1539
  ): ZLinkActorMessageFollowContext {
1356
- const operationId = createMessageFollowId();
1540
+ let operationId: string;
1541
+ if (origin === undefined) {
1542
+ operationId = createMessageFollowId();
1543
+ } else {
1544
+ const bytes = Buffer.allocUnsafe(OPERATION_IDENTITY_BYTES);
1545
+ bytes.writeBigUInt64BE(BigInt.asUintN(UINT64_BYTES * 8, origin.originalOperation.high));
1546
+ bytes.writeBigUInt64BE(
1547
+ BigInt.asUintN(UINT64_BYTES * 8, origin.originalOperation.low),
1548
+ UINT64_BYTES
1549
+ );
1550
+ operationId = bytes.toString('hex');
1551
+ }
1357
1552
  return Object.freeze({
1358
1553
  operationId,
1359
1554
  objectGeneration: generation.toString(),
@@ -1361,7 +1556,11 @@ export class ZLinkActorHandoffCoordinator {
1361
1556
  targetOwner: sourceOwner,
1362
1557
  deadlineUnixMs,
1363
1558
  correlationId: request ? createMessageFollowId() : undefined,
1364
- replyRouteId: request ? createMessageFollowId() : undefined,
1559
+ replyRouteId: request
1560
+ ? origin === undefined
1561
+ ? createMessageFollowId()
1562
+ : operationId
1563
+ : undefined,
1365
1564
  request,
1366
1565
  hopCount: 0,
1367
1566
  visitedOwners: Object.freeze([messageFollowOwnerFenceKey(sourceOwner)]),
@@ -1385,9 +1584,6 @@ export class ZLinkActorHandoffCoordinator {
1385
1584
  if (context.objectGeneration === '0' || context.request !== request) {
1386
1585
  throw actorLocationStale(actorId);
1387
1586
  }
1388
- if (context.deadlineUnixMs !== undefined && Date.now() >= context.deadlineUnixMs) {
1389
- throw actorDeadlineExceeded(actorId);
1390
- }
1391
1587
  verifyActorMessageFollowPayload(context, parts);
1392
1588
  }
1393
1589
 
@@ -1433,7 +1629,10 @@ export class ZLinkActorHandoffCoordinator {
1433
1629
  return BigInt(context.targetOwner.authorityOwnerGeneration);
1434
1630
  }
1435
1631
  const current = this.options.currentOwnerFence?.(actorId);
1436
- if (current !== undefined && current.nodeRid === String(actor.nodeRid)) {
1632
+ if (
1633
+ current !== undefined &&
1634
+ routingIdsEqual(messageFollowOwnerNodeRid(current), actor.nodeRid)
1635
+ ) {
1437
1636
  return BigInt(current.authorityOwnerGeneration);
1438
1637
  }
1439
1638
  return undefined;
@@ -1526,15 +1725,16 @@ export class ZLinkActorHandoffCoordinator {
1526
1725
  await this.messageFollowRelayed(actorId, entry, packet, advanced);
1527
1726
  return undefined;
1528
1727
  }
1529
- const remainingMs = remainingRequestTime(actorId, packet.messageFollowContext.deadlineUnixMs);
1728
+ const timeoutMs = this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
1729
+ const relayDeadlineMs = performance.now() + timeoutMs;
1530
1730
  if (this.options.routedTransport.requestRawToSpot === undefined) {
1531
- const reply = await awaitBeforeDeadline(
1731
+ const reply = await waitRequestReply(
1532
1732
  this.options.routedTransport.requestToSpot<Record<string, unknown>>(target, payload, {
1533
1733
  packetName: ZLINK_REMOTE_ACTOR_PACKET_RELAY_PACKET,
1534
- timeoutMs: remainingMs ?? this.options.requestTimeoutMs
1734
+ timeoutMs
1535
1735
  }),
1536
1736
  actorId,
1537
- remainingMs
1737
+ relayDeadlineMs
1538
1738
  );
1539
1739
  if (reply.ok === false) {
1540
1740
  throw actorRelayError(actorId, reply.errorKind, reply.error);
@@ -1542,12 +1742,12 @@ export class ZLinkActorHandoffCoordinator {
1542
1742
  await this.messageFollowRelayed(actorId, entry, packet, advanced);
1543
1743
  return reply.response;
1544
1744
  }
1545
- const response = await awaitBeforeDeadline(
1745
+ const response = await waitRequestReply(
1546
1746
  requestRoutedJsonReply(
1547
1747
  this.options.routedTransport,
1548
1748
  target,
1549
1749
  payload,
1550
- { timeoutMs: remainingMs ?? this.options.requestTimeoutMs },
1750
+ { timeoutMs },
1551
1751
  `Actor Message Follow raw request is not available for '${actorId}'.`,
1552
1752
  (parts) => {
1553
1753
  if (parts.length === 0) {
@@ -1566,7 +1766,7 @@ export class ZLinkActorHandoffCoordinator {
1566
1766
  }
1567
1767
  ),
1568
1768
  actorId,
1569
- remainingMs
1769
+ relayDeadlineMs
1570
1770
  );
1571
1771
  await this.messageFollowRelayed(actorId, entry, packet, advanced);
1572
1772
  return response;
@@ -1775,35 +1975,6 @@ function packetDeadlineUnixMs(parts: readonly Message[]): number | undefined {
1775
1975
  }
1776
1976
  }
1777
1977
 
1778
- function remainingRequestTime(
1779
- actorId: string,
1780
- deadlineUnixMs: number | undefined
1781
- ): number | undefined {
1782
- if (deadlineUnixMs === undefined) return undefined;
1783
- const remaining = deadlineUnixMs - Date.now();
1784
- if (remaining <= 0) throw actorDeadlineExceeded(actorId);
1785
- return Math.max(1, Math.ceil(remaining));
1786
- }
1787
-
1788
- async function awaitBeforeDeadline<T>(
1789
- operation: Promise<T>,
1790
- actorId: string,
1791
- remainingMs: number | undefined
1792
- ): Promise<T> {
1793
- if (remainingMs === undefined) return await operation;
1794
- let timer: ReturnType<typeof setTimeout> | undefined;
1795
- try {
1796
- return await Promise.race([
1797
- operation,
1798
- new Promise<never>((_resolve, reject) => {
1799
- timer = setTimeout(() => reject(actorDeadlineExceeded(actorId)), remainingMs);
1800
- })
1801
- ]);
1802
- } finally {
1803
- if (timer !== undefined) clearTimeout(timer);
1804
- }
1805
- }
1806
-
1807
1978
  async function waitForHandoffReplayStart(start: Promise<void>, signal: AbortSignal): Promise<void> {
1808
1979
  if (signal.aborted) throw signal.reason;
1809
1980
  let abort!: () => void;
@@ -1819,11 +1990,13 @@ async function waitForHandoffReplayStart(start: Promise<void>, signal: AbortSign
1819
1990
  }
1820
1991
 
1821
1992
  function messageFollowRouteKey(
1822
- actorId: string,
1823
1993
  objectGeneration: bigint,
1824
- sourceOwner: ZLinkActorMessageFollowOwnerFence
1994
+ nodeRidHex: string,
1995
+ nodeGeneration: bigint | string,
1996
+ authorityOwnerGeneration: bigint | string,
1997
+ ownerLeaseGeneration: bigint | string
1825
1998
  ): string {
1826
- return `${actorId}\u0000${objectGeneration}\u0000${messageFollowOwnerFenceKey(sourceOwner)}`;
1999
+ return `${objectGeneration}\u0000${nodeRidHex}\u0000${nodeGeneration}\u0000${authorityOwnerGeneration}\u0000${ownerLeaseGeneration}`;
1827
2000
  }
1828
2001
 
1829
2002
  function actorRefKey(nodeRid: ActorRef['nodeRid'], generation: bigint): string {
@@ -1846,7 +2019,10 @@ function requestSourcesEqual(
1846
2019
  expected.replyRouteId === actual.replyRouteId &&
1847
2020
  expected.ownerId === actual.ownerId &&
1848
2021
  expected.ownerLeaseGeneration === actual.ownerLeaseGeneration &&
1849
- expected.nodeRid === actual.nodeRid &&
2022
+ routingIdsEqual(
2023
+ decodeRoutingId(expected.nodeRid, expected.nodeRidHex),
2024
+ decodeRoutingId(actual.nodeRid, actual.nodeRidHex)
2025
+ ) &&
1850
2026
  expected.nodeGeneration === actual.nodeGeneration &&
1851
2027
  /^[1-9][0-9]*$/.test(actual.ownerLeaseGeneration) &&
1852
2028
  /^[1-9][0-9]*$/.test(actual.nodeGeneration)
@@ -33,6 +33,8 @@ export interface ZLinkActorJoinRelocation {
33
33
  readonly deadlineAtMs?: number;
34
34
  readonly signal?: AbortSignal;
35
35
  }): Promise<{
36
+ /** Source-only terminal after relay readiness transferred public completion. */
37
+ readonly sourceCleanup?: () => Promise<void>;
36
38
  readonly actorRef: ZLinkBackendActorRef;
37
39
  readonly membershipEpoch: bigint;
38
40
  readonly spotGeneration: bigint;
@@ -471,6 +471,10 @@ export class ZLinkLocalNativeActorJoin {
471
471
  admission.parts[0]?.close();
472
472
  throw error;
473
473
  }
474
+ if (relocated.sourceCleanup !== undefined) {
475
+ admission.parts[0]?.close();
476
+ return { accepted: false, sourceCleanup: relocated.sourceCleanup };
477
+ }
474
478
  state.setNativeActorRef(relocated.actorRef);
475
479
  if (entrySpot) {
476
480
  state.clearJoinedSpot();