@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,3 +1,4 @@
1
+ import type { ZLinkMeshDispatchAdmission } from '../admission';
1
2
  import type { ApplicationJobOrigin } from '../application-jobs/contracts';
2
3
  import { RuntimeDisposal } from '../disposal';
3
4
  import { randomUUID } from 'node:crypto';
@@ -34,7 +35,7 @@ import {
34
35
  import { ZLinkLocationWriteIntent, ZLinkLocationWriteStatus } from '../../contracts/Locations';
35
36
  import type { ZLinkLocationOptionOverrides } from '../../contracts/Locations/Options';
36
37
  import type { ZLinkLocationOwnerToken } from '../../contracts/Locations/Writes';
37
- import { createAbortError } from '../abort';
38
+ import { awaitWithAbort, createAbortError } from '../abort';
38
39
  import type { ZLinkActivationConcurrency } from '../activation-admission';
39
40
  import type { ZLinkRemoteBoundSessionTarget } from '../actors';
40
41
  import type { ZLinkActorHandoffPacket } from '../actors/actor-handoff';
@@ -205,6 +206,12 @@ export class ZLinkSpotNodeRuntimeManager {
205
206
  );
206
207
  }
207
208
 
209
+ async requestPeerReconcile(meshName: string, peerRid: string): Promise<void> {
210
+ await Promise.all(
211
+ this.autoConnectLoops.map((loop) => loop.requestPeerReconcile(meshName, peerRid))
212
+ );
213
+ }
214
+
208
215
  async startLocationAutoConnect(signal?: AbortSignal): Promise<void> {
209
216
  const location = this.locationAutoConnect;
210
217
  if (location === undefined || this.autoConnectLoops.length > 0) {
@@ -218,6 +225,16 @@ export class ZLinkSpotNodeRuntimeManager {
218
225
  }
219
226
  const capability = spotNodeAutoConnectCapability(spotNodeName, spotNode, node);
220
227
  if (capability === undefined) continue;
228
+ node.setRequestSourceAcceptance?.(
229
+ (nodeRid, nodeGeneration, nodeRidStorageHex, sourceSignal) =>
230
+ location.requestSources.accept(
231
+ capability.local.meshName,
232
+ nodeRid,
233
+ nodeGeneration,
234
+ nodeRidStorageHex,
235
+ sourceSignal
236
+ )
237
+ );
221
238
  const reconciler = new ZLinkAutoConnectReconciler({
222
239
  local: capability.local,
223
240
  localRow: capability.localRow,
@@ -292,6 +309,24 @@ export class ZLinkSpotNodeRuntimeManager {
292
309
  if (this.options.dispatchErrors !== undefined) {
293
310
  node.setDispatchErrorReporter?.(this.options.dispatchErrors, spotNodeName);
294
311
  }
312
+ // Session-Actor binding §4: the Session owner identity comes from the
313
+ // host's own descriptor or from a peer descriptor that passed the
314
+ // Location runtime §4.1 owner lease check.
315
+ node.setSessionOwnerDescriptors?.({
316
+ local: () => this.locationAutoConnect?.runtime.currentOwnerToken,
317
+ peer: async (peerRid, peerGeneration) => {
318
+ const location = this.locationAutoConnect;
319
+ if (location === undefined) return undefined;
320
+ const descriptor = (await location.runtime.listLiveMeshNodes(spotNodeName)).find(
321
+ (candidate) =>
322
+ routingIdsEqual(candidate.rid, peerRid) &&
323
+ candidate.lifecycleGeneration === peerGeneration
324
+ );
325
+ return descriptor === undefined
326
+ ? undefined
327
+ : { ownerId: descriptor.ownerId, leaseGeneration: descriptor.leaseGeneration };
328
+ }
329
+ });
295
330
  node.setMailboxRecordDroppedHandler?.((record) =>
296
331
  this.options.dispatchErrors?.report({
297
332
  surface: ZLinkDispatchErrorSurface.RouteMeshChannel,
@@ -412,7 +447,7 @@ export class ZLinkSpotNodeRuntimeManager {
412
447
  this.meshNodes.delete(spotNodeName);
413
448
  completions.dispose(error);
414
449
  await pump?.dispose();
415
- node.close();
450
+ await node.close();
416
451
  throw error;
417
452
  }
418
453
  }
@@ -447,9 +482,8 @@ export class ZLinkSpotNodeRuntimeManager {
447
482
  const ownerChanged =
448
483
  this.publishedOwnerToken !== undefined && !sameOwnerToken(this.publishedOwnerToken, owner);
449
484
  if (ownerChanged) {
450
- // A new owner token can refer to an empty or replaced Store. The cached
451
- // descriptor was written under the previous lease and must not force a
452
- // Renew against a row that no longer exists.
485
+ // A descriptor confirmed under the previous lease must not supply
486
+ // cached population data for a new owner token.
453
487
  this.publishedMeshNodeDescriptors.clear();
454
488
  }
455
489
  for (const [meshName, registration] of this.options.registration.spotNodes) {
@@ -467,7 +501,14 @@ export class ZLinkSpotNodeRuntimeManager {
467
501
  ...instanceSpots.map(([stableType, factory]) =>
468
502
  objectCapability('instance_spot', stableType, factory)
469
503
  ),
470
- ...actors.map(([stableType, factory]) => objectCapability('actor', stableType, factory))
504
+ ...actors.map(([stableType, factory]) =>
505
+ objectCapability(
506
+ 'actor',
507
+ stableType,
508
+ factory,
509
+ registrationAcceptsNewActor(registration, stableType)
510
+ )
511
+ )
471
512
  ].sort((left, right) => {
472
513
  const kindOrder = left.objectKind.localeCompare(right.objectKind);
473
514
  return kindOrder !== 0 ? kindOrder : left.stableType.localeCompare(right.stableType);
@@ -482,9 +523,8 @@ export class ZLinkSpotNodeRuntimeManager {
482
523
  // The raw MeshNode resolves port zero and applies AdvertiseHost once.
483
524
  // Discovery and RouteMesh hello must publish that same public identity.
484
525
  endpoint: status.localEndpoint,
485
- objectRole: effectiveObjectRole(registration),
526
+ ...this.localDescriptorFields(meshName, registration, state),
486
527
  entrySpotId: this.entrySpotId(meshName, registration),
487
- placementWeight: this.placementWeight(meshName),
488
528
  populationCapacity: {
489
529
  actors: {
490
530
  active: current?.populationCapacity.actors.active ?? 0,
@@ -517,19 +557,6 @@ export class ZLinkSpotNodeRuntimeManager {
517
557
  active: 0,
518
558
  limit: registration.activationConcurrencyLimit ?? DEFAULT_ACTIVATION_CONCURRENCY_LIMIT
519
559
  },
520
- channelWeights: Object.fromEntries(
521
- this.serverChannels(meshName).map(([channelName, channel]) => [
522
- channelName,
523
- state === ZLinkFrameworkRuntimeState.Draining
524
- ? 0
525
- : this.effectiveChannelWeight(
526
- meshName,
527
- channelName,
528
- channel.weight ?? ZLINK_DEFAULT_PUBLIC_WEIGHT
529
- )
530
- ])
531
- ),
532
- applicationVersion: this.options.registration.applicationVersion,
533
560
  maintenanceWave: this.options.registration.maintenanceWave,
534
561
  spotTypes: [
535
562
  ...userSpots.map(([stableType]) => stableType),
@@ -540,13 +567,14 @@ export class ZLinkSpotNodeRuntimeManager {
540
567
  state,
541
568
  securityIdentity: 'default'
542
569
  };
570
+ // Revision is issued before submission: an unconfirmed Store write may
571
+ // already have applied, so the next publication must not reuse it.
572
+ this.descriptorRevisionByMesh.set(meshName, descriptor.descriptorRevision);
543
573
  const result = await location.runtime.writeMeshNode(
544
574
  descriptor,
545
- ownerChanged
546
- ? ZLinkLocationWriteIntent.Renew
547
- : current === undefined
548
- ? ZLinkLocationWriteIntent.NewClaim
549
- : ZLinkLocationWriteIntent.Renew,
575
+ previousRevision === 0n
576
+ ? ZLinkLocationWriteIntent.NewClaim
577
+ : ZLinkLocationWriteIntent.Renew,
550
578
  signal
551
579
  );
552
580
  if (result.status !== ZLinkLocationWriteStatus.Stored) {
@@ -560,11 +588,37 @@ export class ZLinkSpotNodeRuntimeManager {
560
588
  leaseGeneration: location.runtime.currentOwnerToken!.leaseGeneration,
561
589
  updatedAt: result.updatedAt
562
590
  });
563
- this.descriptorRevisionByMesh.set(meshName, descriptor.descriptorRevision);
564
591
  }
565
592
  this.publishedOwnerToken = owner;
566
593
  }
567
594
 
595
+ private localDescriptorFields(
596
+ meshName: string,
597
+ registration: ZLinkSpotNodeOptions,
598
+ state: ZLinkFrameworkRuntimeState
599
+ ): Pick<
600
+ ZLinkMeshNodeDescriptor,
601
+ 'objectRole' | 'placementWeight' | 'channelWeights' | 'applicationVersion'
602
+ > {
603
+ return {
604
+ objectRole: effectiveObjectRole(registration),
605
+ placementWeight: this.placementWeight(meshName),
606
+ channelWeights: Object.fromEntries(
607
+ this.serverChannels(meshName).map(([channelName, channel]) => [
608
+ channelName,
609
+ state === ZLinkFrameworkRuntimeState.Draining
610
+ ? 0
611
+ : this.effectiveChannelWeight(
612
+ meshName,
613
+ channelName,
614
+ channel.weight ?? ZLINK_DEFAULT_PUBLIC_WEIGHT
615
+ )
616
+ ])
617
+ ),
618
+ applicationVersion: this.options.registration.applicationVersion
619
+ };
620
+ }
621
+
568
622
  async reconcileAndPublishMeshNodeState(
569
623
  state: ZLinkFrameworkRuntimeState,
570
624
  meshName: string,
@@ -578,13 +632,20 @@ export class ZLinkSpotNodeRuntimeManager {
578
632
  if (owner === undefined) return;
579
633
  const current = (await location.runtime.listLiveMeshNodes(meshName, signal)).find(
580
634
  (descriptor) =>
581
- String(descriptor.rid) === String(status.routingId) &&
635
+ routingIdsEqual(descriptor.rid, status.routingId) &&
582
636
  descriptor.lifecycleGeneration === status.lifecycleGeneration &&
583
637
  descriptor.ownerId === owner.ownerId &&
584
638
  descriptor.leaseGeneration === owner.leaseGeneration
585
639
  );
586
640
  if (current !== undefined) {
587
- this.publishedMeshNodeDescriptors.set(meshName, current);
641
+ this.publishedMeshNodeDescriptors.set(meshName, {
642
+ ...current,
643
+ ...this.localDescriptorFields(
644
+ meshName,
645
+ this.options.registration.spotNodes.get(meshName)!,
646
+ state
647
+ )
648
+ });
588
649
  this.descriptorRevisionByMesh.set(
589
650
  meshName,
590
651
  maxBigInt(this.descriptorRevisionByMesh.get(meshName) ?? 0n, current.descriptorRevision)
@@ -848,12 +909,16 @@ export class ZLinkSpotNodeRuntimeManager {
848
909
  };
849
910
  await settle(publishers.map(async (publisher) => publisher.close()));
850
911
  await settle(autoConnectLoops.map((loop) => loop.prepareTransportShutdown()));
851
- await settle(entryActivations.reverse().map((activation) => activation.dispose(deadline)));
852
- await settle(meshPumps.reverse().map((pump) => pump.dispose()));
912
+ await settle(
913
+ entryActivations
914
+ .reverse()
915
+ .map((activation) => awaitWithAbort(activation.dispose(deadline), signal))
916
+ );
917
+ await settle(meshPumps.reverse().map((pump) => pump.dispose(signal)));
853
918
  await settle(
854
919
  meshNodes.reverse().map(async (node) => {
855
- node.shutdown(DEFAULT_SPOT_NODE_SHUTDOWN_TIMEOUT_MS);
856
- node.close();
920
+ await node.shutdown(DEFAULT_SPOT_NODE_SHUTDOWN_TIMEOUT_MS);
921
+ await node.close();
857
922
  })
858
923
  );
859
924
  for (const completions of meshCompletions) {
@@ -870,39 +935,61 @@ export class ZLinkSpotNodeRuntimeManager {
870
935
  this.meshCompletions.clear();
871
936
  }
872
937
 
873
- private async dispatchMeshRecord(
938
+ /**
939
+ * Node and Channel records go straight to the framework dispatcher in the
940
+ * pump's turn. Only Spot and Actor records addressed to the Entry Spot wait
941
+ * for its activation first.
942
+ */
943
+ private dispatchMeshRecord(
874
944
  meshName: string,
875
945
  owner: ReadyRecord,
876
946
  record: ReceiveRecord
877
- ): Promise<void> {
878
- const node = this.meshNodes.get(meshName);
879
- const targetsEntrySpot =
880
- owner.spotId === null ||
881
- (node !== undefined &&
882
- routingIdsEqual(owner.spotId as unknown as RoutingId, String(node.status().routingId)));
947
+ ): void | Promise<void> {
883
948
  if (
884
- targetsEntrySpot &&
885
949
  (record.kind === ReceiveKind.ActorSend ||
886
950
  record.kind === ReceiveKind.ActorRequest ||
887
951
  record.kind === ReceiveKind.SpotSend ||
888
952
  record.kind === ReceiveKind.SpotRequest ||
889
- record.kind === ReceiveKind.SpotMulticast)
953
+ record.kind === ReceiveKind.SpotMulticast) &&
954
+ this.targetsEntrySpot(meshName, owner)
890
955
  ) {
891
- await this.ensureEntryActivation(meshName);
956
+ return this.ensureEntryActivation(meshName).then(() =>
957
+ this.dispatchFrameworkRecord(meshName, owner, record)
958
+ );
892
959
  }
960
+ return this.dispatchFrameworkRecord(meshName, owner, record);
961
+ }
962
+
963
+ private targetsEntrySpot(meshName: string, owner: ReadyRecord): boolean {
964
+ if (owner.spotId === null) return true;
965
+ const node = this.meshNodes.get(meshName);
966
+ return (
967
+ node !== undefined &&
968
+ routingIdsEqual(owner.spotId as unknown as RoutingId, String(node.status().routingId))
969
+ );
970
+ }
971
+
972
+ private dispatchFrameworkRecord(
973
+ meshName: string,
974
+ owner: ReadyRecord,
975
+ record: ReceiveRecord
976
+ ): void | Promise<void> {
893
977
  const dispatcher = this.options.meshRecordDispatcher;
894
978
  if (dispatcher === undefined) {
895
- throw new ZLinkConfigurationException(
896
- `MeshNode '${meshName}' received a record before its framework dispatcher was registered.`
979
+ return Promise.reject(
980
+ new ZLinkConfigurationException(
981
+ `MeshNode '${meshName}' received a record before its framework dispatcher was registered.`
982
+ )
897
983
  );
898
984
  }
899
- await dispatcher(meshName, owner, record);
985
+ return dispatcher(meshName, owner, record);
900
986
  }
901
987
 
902
988
  async dispatchEntrySpotRecord(
903
989
  meshName: string,
904
990
  owner: ReadyRecord,
905
- record: ReceiveRecord
991
+ record: ReceiveRecord,
992
+ admit?: ZLinkMeshDispatchAdmission
906
993
  ): Promise<boolean> {
907
994
  if (
908
995
  record.kind !== ReceiveKind.SpotSend &&
@@ -922,11 +1009,13 @@ export class ZLinkSpotNodeRuntimeManager {
922
1009
  'MeshNode Entry Spot multicast record is missing its topic.'
923
1010
  );
924
1011
  }
925
- await activation.dispatchSubscriptionRecord(
926
- record.topic,
927
- record.parts,
928
- record.sourceNodeRid as unknown as RoutingId | null
929
- );
1012
+ const dispatch = () =>
1013
+ activation.dispatchSubscriptionRecord(
1014
+ record.topic!,
1015
+ record.parts,
1016
+ record.sourceNodeRid as unknown as RoutingId | null
1017
+ );
1018
+ await (admit === undefined ? dispatch() : admit(dispatch));
930
1019
  return true;
931
1020
  }
932
1021
  const envelope = decodeChannelEnvelope(
@@ -940,21 +1029,30 @@ export class ZLinkSpotNodeRuntimeManager {
940
1029
  channelName: envelope.header.channelName,
941
1030
  contentType: envelope.header.contentType
942
1031
  };
943
- if (record.kind === ReceiveKind.SpotSend) {
944
- await activation.dispatchPacketEncoded(envelope.packetName, decodePayload, context, false);
945
- return true;
946
- }
947
1032
  try {
948
- const response = await activation.dispatchPacketEncoded(
949
- envelope.packetName,
950
- decodePayload,
951
- context,
952
- true
953
- );
954
- requireEntrySpotReply(
955
- record.reply(encodeChannelReplyParts(envelope.header, response, codecs))
956
- );
1033
+ const dispatch = async () => {
1034
+ if (record.kind === ReceiveKind.SpotSend) {
1035
+ await activation.dispatchPacketEncoded(
1036
+ envelope.packetName,
1037
+ decodePayload,
1038
+ context,
1039
+ false
1040
+ );
1041
+ return;
1042
+ }
1043
+ const response = await activation.dispatchPacketEncoded(
1044
+ envelope.packetName,
1045
+ decodePayload,
1046
+ context,
1047
+ true
1048
+ );
1049
+ requireEntrySpotReply(
1050
+ record.reply(encodeChannelReplyParts(envelope.header, response, codecs))
1051
+ );
1052
+ };
1053
+ await (admit === undefined ? dispatch() : admit(dispatch));
957
1054
  } catch (error) {
1055
+ if (record.kind !== ReceiveKind.SpotRequest) throw error;
958
1056
  requireEntrySpotReply(record.reply(encodeChannelErrorReplyParts(envelope.header, error)));
959
1057
  }
960
1058
  return true;
@@ -1110,6 +1208,20 @@ export class ZLinkSpotNodeRuntimeManager {
1110
1208
  await activation.commitServiceActorJoin(actor, handoffBacklog);
1111
1209
  }
1112
1210
 
1211
+ admitEntryActorPacketPrefix(
1212
+ meshName: string,
1213
+ actorId: string,
1214
+ records: readonly import('../actors/actor-handoff').ZLinkActorHandoffPrefixRecord[]
1215
+ ): import('../actors/actor-handoff').ZLinkActorHandoffPrefixAdmission {
1216
+ const activation = this.entryActivations.get(meshName);
1217
+ if (activation === undefined) {
1218
+ throw new ZLinkConfigurationException(
1219
+ `Entry Spot Actor '${actorId}' has no activation for MeshNode '${meshName}'.`
1220
+ );
1221
+ }
1222
+ return activation.admitActorPacketPrefix(actorId, records);
1223
+ }
1224
+
1113
1225
  executeEntryActor<T>(meshName: string, actorId: string, operation: () => Promise<T>): Promise<T> {
1114
1226
  const activation = this.entryActivations.get(meshName);
1115
1227
  if (activation === undefined) {
@@ -1345,7 +1457,8 @@ function effectiveObjectRole(registration: ZLinkSpotNodeOptions): ZLinkObjectRol
1345
1457
  function objectCapability(
1346
1458
  objectKind: 'actor' | 'user_spot' | 'instance_spot',
1347
1459
  stableType: string,
1348
- factory: DescriptorFactoryRegistration
1460
+ factory: DescriptorFactoryRegistration,
1461
+ entryAccepted = false
1349
1462
  ) {
1350
1463
  const policy = factory.relocation?.kind ?? 'disabled';
1351
1464
  return {
@@ -1353,10 +1466,27 @@ function objectCapability(
1353
1466
  stableType,
1354
1467
  policy,
1355
1468
  hasSnapshotAdapter: policy === 'snapshot',
1356
- limit: objectKind === 'actor' ? 0 : (factory.options?.stableTypeLimit ?? 0)
1469
+ limit: objectKind === 'actor' ? 0 : (factory.options?.stableTypeLimit ?? 0),
1470
+ entryAccepted
1357
1471
  };
1358
1472
  }
1359
1473
 
1474
+ /**
1475
+ * The one decision for creating a new Actor on this node (Actor model §6.3): the node registered
1476
+ * an Entry Spot type that accepts the Actor type and an Actor factory for it. Publication and the
1477
+ * target refusal both read it.
1478
+ */
1479
+ export function registrationAcceptsNewActor(
1480
+ registration: ZLinkSpotNodeOptions,
1481
+ stableType: string
1482
+ ): boolean {
1483
+ return (
1484
+ registration.entrySpotType !== undefined &&
1485
+ registration.entrySpotActorType === stableType &&
1486
+ effectiveActorRegistrations(registration).some(([type]) => type === stableType)
1487
+ );
1488
+ }
1489
+
1360
1490
  function aggregatePlacementCapacity(actorLimit: number, spotLimit: number): number {
1361
1491
  const unlimited = ZLINK_MAX_CAPACITY;
1362
1492
  const actors = actorLimit === 0 ? unlimited : actorLimit;
@@ -370,7 +370,7 @@ function createAddressedSpotRequestCall(
370
370
  markSubmitted(options);
371
371
  rejectSameSpotAsyncRequest(serial, spotId, 'yield');
372
372
  const pending = begin<TReply>(signal);
373
- return turn.yieldPromise(pending);
373
+ return turn.yieldFrameworkPromise(pending);
374
374
  }
375
375
  };
376
376
  }
@@ -508,7 +508,7 @@ function wrapRequestCall(
508
508
  yield<TReply>(signal?: AbortSignal) {
509
509
  const turn = requireZLinkYieldTurn();
510
510
  const pending = begin<TReply>(signal);
511
- return turn.yieldPromise(pending);
511
+ return turn.yieldFrameworkPromise(pending);
512
512
  }
513
513
  };
514
514
  }
@@ -626,7 +626,7 @@ function wrapRoutedSpotRequestCall(
626
626
  const turn = requireZLinkYieldTurn();
627
627
  rejectSameSpotAsyncRequest(serial, spot.spotId, 'yield');
628
628
  const pending = begin<TReply>(signal);
629
- return turn.yieldPromise(pending);
629
+ return turn.yieldFrameworkPromise(pending);
630
630
  }
631
631
  };
632
632
  }
@@ -8,7 +8,7 @@ import type { Message } from '../../contracts/Common/Message';
8
8
  import { ZLinkBufferMessage as RuntimeMessage } from '../backend/runtime-message';
9
9
  import type { ZLinkBackendReceived as BackendReceived } from '../backend/runtime-values';
10
10
  import { decodeChannelEnvelope } from '../channels/channel-envelope';
11
- import { decodeRoutingId as decodeWireRoutingId } from '../routing-id';
11
+ import { decodeRoutingId as decodeWireRoutingId, routingIdsEqual } from '../routing-id';
12
12
  import {
13
13
  REMOTE_ACTOR_JOIN_PACKET,
14
14
  type ZLinkRemoteActorJoinWirePayload
@@ -176,7 +176,14 @@ export function decodeHandoffBacklog(value: unknown): readonly ZLinkActorHandoff
176
176
  BigInt(source.ownerLeaseGeneration) <= 0n ||
177
177
  source.nodeRid.length === 0 ||
178
178
  BigInt(source.nodeGeneration) <= 0n ||
179
- source.replyRouteId !== messageFollowContext.replyRouteId)) ||
179
+ source.replyRouteId !==
180
+ (packet.messageFollowOrigin !== undefined &&
181
+ routingIdsEqual(
182
+ decodeWireRoutingId(source.nodeRid, source.nodeRidHex),
183
+ packet.messageFollowOrigin.sourceNodeRid
184
+ )
185
+ ? packet.messageFollowOrigin.originalReplyRouteId.toString()
186
+ : messageFollowContext.replyRouteId))) ||
180
187
  (!packet.returnResponse && source !== undefined)
181
188
  ) {
182
189
  throw new Error('Remote actor handoff request source fence is invalid.');
@@ -92,7 +92,6 @@ export interface ZLinkSpotActorTransferRuntime {
92
92
  commitRoutedActor(actor: ZLinkActor, spotId: RoutingId, spot: ZLinkSpot): void;
93
93
  clearRoutedActor(actor: ZLinkActor): void;
94
94
  rollbackRoutedActor(actor: ZLinkActor, signal?: AbortSignal): Promise<void>;
95
- notifyCoreSourceLeave(actor: ZLinkActor, callback: () => Promise<void>): Promise<void>;
96
95
  actorEntryNodeRid(actor: ZLinkActor): RoutingId | undefined;
97
96
  }
98
97
 
@@ -1,13 +1,24 @@
1
1
  import { ZLinkUserSpotExecutionMode } from '../../contracts';
2
2
  import { ZLinkActorSerialExecutor } from '../actors';
3
- import type { ZLinkExecutionBarrier } from '../execution';
3
+ import type {
4
+ ZLinkActorHandoffDispatch,
5
+ ZLinkActorHandoffPrefixAdmission,
6
+ ZLinkActorHandoffPrefixRecord
7
+ } from '../actors/actor-handoff';
8
+ import type { ZLinkExecutionBarrier, ZLinkExecutionBarrierSeal } from '../execution';
4
9
  import type {
5
10
  ZLinkSerialSchedulerOptions,
6
- ZLinkSerialWorkPreparation,
7
11
  ZLinkSerialWorkOptions
8
12
  } from '../execution/serial-execution-queue';
9
13
  import { ZLinkSpotSerialTurnExecutor } from './spot-serial-turn-executor';
10
14
 
15
+ export type ZLinkSpotPreparationCompletion = 'publication' | 'first-terminal';
16
+
17
+ export type ZLinkActorPacketTurnDispatch = (
18
+ serial: ZLinkSpotSerialTurnExecutor,
19
+ ...args: Parameters<ZLinkActorHandoffDispatch>
20
+ ) => ReturnType<ZLinkActorHandoffDispatch>;
21
+
11
22
  /**
12
23
  * Owns every application serial unit that belongs to one Spot activation.
13
24
  *
@@ -21,6 +32,11 @@ export class ZLinkSpotSerialExecutor {
21
32
  private executionBarrier: ZLinkExecutionBarrier | undefined;
22
33
  private closing = false;
23
34
  private closePromise: Promise<void> | undefined;
35
+ private preparation?: {
36
+ readonly seal: ZLinkExecutionBarrierSeal;
37
+ readonly complete: (terminal?: () => Promise<void>) => void;
38
+ readonly execution: Promise<void>;
39
+ };
24
40
 
25
41
  constructor(
26
42
  private readonly spotSerial: ZLinkSpotSerialTurnExecutor,
@@ -39,6 +55,54 @@ export class ZLinkSpotSerialExecutor {
39
55
  for (const serial of this.timerSerials.values()) serial.setExecutionBarrier(barrier);
40
56
  }
41
57
 
58
+ get isPreparing(): boolean {
59
+ return this.preparation !== undefined;
60
+ }
61
+
62
+ beginPreparation(kind: 'activation' | 'relocation' = 'activation'): void {
63
+ if (this.preparation !== undefined || this.executionBarrier === undefined)
64
+ throw new Error('Activation preparation requires one unowned execution barrier.');
65
+ const barrier = this.executionBarrier;
66
+ const seal = barrier.seal(kind);
67
+ let complete!: (terminal?: () => Promise<void>) => void;
68
+ const terminal = new Promise<(() => Promise<void>) | undefined>((resolve) => {
69
+ complete = resolve;
70
+ });
71
+ // The staging seal itself owns target preparation. No normal preparation
72
+ // item is admitted in addition to this lifecycle owner.
73
+ const execution = this.spotSerial.executeControlLifecycleOperation(
74
+ async () => {
75
+ const finish = await terminal;
76
+ await finish?.();
77
+ },
78
+ {
79
+ canExecuteApplication: (record) => record.context === undefined || !barrier.isCurrent(seal)
80
+ }
81
+ );
82
+ this.preparation = { seal, complete, execution };
83
+ }
84
+
85
+ openPreparationAdmission(): void {
86
+ if (this.preparation !== undefined) this.executionBarrier!.abort(this.preparation.seal);
87
+ }
88
+
89
+ async finishPreparation(terminal?: () => Promise<void>): Promise<void> {
90
+ const preparation = this.preparation;
91
+ if (preparation === undefined) {
92
+ await terminal?.();
93
+ return;
94
+ }
95
+ preparation.complete(terminal);
96
+ try {
97
+ await preparation.execution;
98
+ } finally {
99
+ if (this.preparation === preparation) {
100
+ this.executionBarrier!.abort(preparation.seal);
101
+ this.preparation = undefined;
102
+ }
103
+ }
104
+ }
105
+
42
106
  executeSpot<T>(
43
107
  operation: () => Promise<T> | T,
44
108
  workOptions?: ZLinkSerialWorkOptions
@@ -55,35 +119,43 @@ export class ZLinkSpotSerialExecutor {
55
119
  return this.actorExecutor(actorId).execute(() => operation(serial), workOptions);
56
120
  }
57
121
 
58
- /** @internal Restores a durable Actor FIFO prefix without starting it. */
59
- admitActorDurablePrefix(
122
+ executeTimer<T>(
123
+ timerName: string,
124
+ operation: () => Promise<T> | T,
125
+ workOptions?: ZLinkSerialWorkOptions
126
+ ): Promise<T> {
127
+ return this.timerSerial(timerName).post(operation, workOptions);
128
+ }
129
+
130
+ /** Admits held packets through the same Actor FIFO as ordinary ingress. */
131
+ admitActorPacketPrefix(
60
132
  actorId: string,
61
- records: readonly {
62
- readonly operation: (
63
- executeChild: <TChild>(
64
- child: (serial: ZLinkSpotSerialTurnExecutor) => Promise<TChild> | TChild
65
- ) => Promise<TChild>
66
- ) => Promise<void>;
67
- readonly preparation?: ZLinkSerialWorkPreparation;
68
- readonly workOptions?: ZLinkSerialWorkOptions;
69
- }[]
70
- ): readonly Promise<void>[] {
133
+ records: readonly ZLinkActorHandoffPrefixRecord[],
134
+ dispatch: ZLinkActorPacketTurnDispatch
135
+ ): ZLinkActorHandoffPrefixAdmission {
71
136
  const serial = this.actorSerial(actorId);
72
- return this.actorExecutor(actorId).admitDurablePrefix(
137
+ const terminals = this.actorExecutor(actorId).admitDurablePrefix(
73
138
  records.map((record) => ({
74
- operation: (executeChild) => record.operation((child) => executeChild(() => child(serial))),
139
+ operation: (executeChild) =>
140
+ record.drain((parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef) =>
141
+ executeChild(() =>
142
+ dispatch(serial, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef)
143
+ )
144
+ ),
75
145
  preparation: record.preparation,
76
- workOptions: record.workOptions
146
+ workOptions: { payloadBytes: record.payloadBytes, onWithdrawable: record.onWithdrawable }
77
147
  }))
78
148
  );
79
- }
80
-
81
- executeTimer<T>(
82
- timerName: string,
83
- operation: () => Promise<T> | T,
84
- workOptions?: ZLinkSerialWorkOptions
85
- ): Promise<T> {
86
- return this.timerSerial(timerName).execute(operation, workOptions);
149
+ const terminal = Promise.allSettled(terminals).then((outcomes) => {
150
+ const errors = outcomes.flatMap((outcome) =>
151
+ outcome.status === 'rejected' ? [outcome.reason] : []
152
+ );
153
+ if (errors.length === 1) throw errors[0];
154
+ if (errors.length > 1) {
155
+ throw new AggregateError(errors, `Actor '${actorId}' durable prefix replay failed.`);
156
+ }
157
+ });
158
+ return { terminal };
87
159
  }
88
160
 
89
161
  isTimerExecuting(timerName: string): boolean {