@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
@@ -61,13 +61,32 @@ export type ZLinkBackendObjectPlacement =
61
61
  | { readonly kind: 'capacity' }
62
62
  | { readonly kind: 'unavailable' };
63
63
 
64
+ export type ZLinkBackendRequestSourceAcceptance = (
65
+ nodeRid: string,
66
+ nodeGeneration: bigint,
67
+ nodeRidStorageHex: string,
68
+ signal?: AbortSignal
69
+ ) =>
70
+ | import('../../locations/request-source-resolver').ZLinkRequestSourceFence
71
+ | undefined
72
+ | Promise<import('../../locations/request-source-resolver').ZLinkRequestSourceFence | undefined>;
73
+
64
74
  export interface ZLinkBackendMeshNode {
75
+ acceptRelocatedActorTerminal?(
76
+ operation: { readonly high: bigint; readonly low: bigint },
77
+ replyRouteId: bigint,
78
+ result: import('../../foundation/service-stateful-runtime').ServiceStatefulResult
79
+ ): 'terminalReceived' | 'alreadyTerminal' | undefined;
65
80
  readonly routingId?: RoutingId;
81
+ cancelPendingOperations?(reason: unknown): void;
66
82
  completeClosedInstance?(spotId: string, objectGeneration: bigint): void;
67
83
  setDispatchErrorReporter?(
68
84
  reporter: import('../../channels/dispatch-error-reporter').ZLinkDispatchErrorReporter,
69
85
  meshName: string
70
86
  ): void;
87
+ setSessionOwnerDescriptors?(
88
+ source: import('../../foundation/service-stateful-runtime').ServiceSessionOwnerDescriptors
89
+ ): void;
71
90
  setRoutingId(routingId: unknown): void;
72
91
  setBind(endpoint: string): void;
73
92
  setAdvertiseHost(host: string): void;
@@ -98,9 +117,9 @@ export interface ZLinkBackendMeshNode {
98
117
  'kind'
99
118
  >
100
119
  ): Promise<boolean>;
101
- shutdown(timeoutMs: number): RequestResult;
120
+ shutdown(timeoutMs: number): Promise<RequestResult>;
102
121
  publishDraining?(): Promise<void>;
103
- close(): void;
122
+ close(): Promise<void>;
104
123
  addChannelName(name: string): void;
105
124
  setChannelWeight(name: string, weight: number): Promise<void>;
106
125
  setPlacementWeight(weight: number): Promise<void>;
@@ -184,12 +203,23 @@ export interface ZLinkBackendMeshNode {
184
203
  readonly securityIdentity?: string;
185
204
  readonly lifecycleGeneration: bigint;
186
205
  }): void;
206
+ /**
207
+ * Installs the source request owner check the first accepting owner runs on Actor and Spot
208
+ * ingress (Location runtime §9.3). Undefined from the check ends the request Unavailable.
209
+ */
210
+ setRequestSourceAcceptance?(acceptance: ZLinkBackendRequestSourceAcceptance): void;
187
211
  isObjectClientNodeDirectTarget?(targetRid: unknown): boolean;
188
212
  observePeerRoute?(
189
213
  targetRid: unknown
190
214
  ): import('../../foundation/durable-service-request').PeerRouteObservation;
191
215
  hasPeerRouteOrConnectionIntent?(targetRid: unknown, endpoint: string): boolean;
192
216
  isPeerRouteReady?(targetRid: unknown, lifecycleGeneration?: bigint): boolean;
217
+ waitForPeerRoute?(
218
+ targetRid: unknown,
219
+ lifecycleGeneration: bigint,
220
+ deadlineUnixMs: bigint,
221
+ signal?: AbortSignal
222
+ ): Promise<void>;
193
223
  sendToNode(
194
224
  targetRid: unknown,
195
225
  parts: MessageLike | readonly MessageLike[],
@@ -317,9 +347,10 @@ export interface ZLinkBackendMeshNode {
317
347
  source: ServiceDirectSpotRouteFence
318
348
  ): ServiceSpotMessageFollowSeal | undefined;
319
349
  abortSpotMessageFollowIngress?(seal: ServiceSpotMessageFollowSeal): boolean;
350
+ /** A null target consumes the committed seal without installing a Follow route. */
320
351
  commitSpotMessageFollowIngress?(
321
352
  seal: ServiceSpotMessageFollowSeal,
322
- target: ServiceDirectSpotRouteFence,
353
+ target: ServiceDirectSpotRouteFence | null,
323
354
  durationMs: number
324
355
  ): Promise<boolean>;
325
356
  joinActorSpot(
@@ -365,7 +396,10 @@ export interface ZLinkBackendMeshNode {
365
396
  sendToActor(
366
397
  actor: ZLinkBackendActorRef,
367
398
  parts: MessageLike | readonly MessageLike[],
368
- options?: { flags?: number }
399
+ options?: {
400
+ flags?: number;
401
+ routeFence?: import('../../foundation/service-stateful-wire-codec').ServiceActorRouteFence;
402
+ }
369
403
  ): Promise<SubmitResult>;
370
404
  requestToActor(
371
405
  actor: ZLinkBackendActorRef,
@@ -375,6 +409,7 @@ export interface ZLinkBackendMeshNode {
375
409
  timeoutMs?: number;
376
410
  applicationMetadata?: Buffer;
377
411
  onAdmitted?: () => void;
412
+ routeFence?: import('../../foundation/service-stateful-wire-codec').ServiceActorRouteFence;
378
413
  }
379
414
  ): MeshOperationId;
380
415
  actorSendToActor(
@@ -1,3 +1,4 @@
1
+ import { wireReplyFailureException } from '../framework-errors-internal';
1
2
  import { classifySubmitResult } from '../messaging/submission-result';
2
3
  import type { ZLinkBackendActorSessionNode, ZLinkBackendMeshNode } from './contracts';
3
4
  import { closeMeshCompletion, type ZLinkMeshCompletionTable } from './mesh-completion-table';
@@ -26,9 +27,10 @@ export function meshActorSessionNodeAdapter(
26
27
  );
27
28
  try {
28
29
  if (completion.terminalResult !== 0 || completion.failureErrno !== 0) {
29
- throw new Error(
30
- `Actor '${actor.actorId}' bound-session close failed with result ` +
31
- `'${completion.terminalResult}' and errno '${completion.failureErrno}'.`
30
+ throw wireReplyFailureException(
31
+ completion.terminalResult,
32
+ completion.failureErrno,
33
+ `Actor '${actor.actorId}' bound-session close failed.`
32
34
  );
33
35
  }
34
36
  } finally {
@@ -71,7 +71,11 @@ export class ZLinkMeshCompletionTable {
71
71
  this.slots.push(slot);
72
72
  this.free = index;
73
73
  }
74
+ // New slots hold no identity yet. Only a larger bucket array needs the
75
+ // pending identities placed again; it doubles, so growth to N pending
76
+ // operations re-indexes O(N) slots in total.
74
77
  const minimumBuckets = this.slots.length * COMPLETION_HASH_BUCKETS_PER_SLOT;
78
+ if (minimumBuckets <= this.buckets.length) return;
75
79
  this.buckets = new Int32Array(2 ** Math.ceil(Math.log2(minimumBuckets))).fill(-1);
76
80
  for (let index = 0; index < this.slots.length; index++) {
77
81
  const slot = this.slots[index]!;
@@ -1,6 +1,11 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { awaitWithAbort } from '../abort';
2
3
  import { availableParallelism } from 'node:os';
3
- import { runWithApplicationJobPermit } from '../application-jobs/application-job-queue-scope';
4
+ import {
5
+ enterApplicationJobPermitScope,
6
+ leaveApplicationJobPermitScope,
7
+ releaseApplicationJobPermitTurn
8
+ } from '../application-jobs/application-job-queue-scope';
4
9
  import type {
5
10
  ApplicationJobPermitPort,
6
11
  ApplicationJobQueuePort
@@ -8,6 +13,7 @@ import type {
8
13
  import { runZLinkExecutionArea } from '../execution';
9
14
  import {
10
15
  ReadyDomain,
16
+ type Claim,
11
17
  type ReadyBatch,
12
18
  type ReadyRecord,
13
19
  type ReceiveBatch,
@@ -58,7 +64,6 @@ export interface ZLinkMeshDispatchFailureContext {
58
64
  }
59
65
 
60
66
  export class ZLinkMeshDispatchPump {
61
- private readonly dispatchOwnedRecord = this.dispatchRecord.bind(this);
62
67
  private pendingDomains: number = ReadyDomain.None;
63
68
  private infrastructureScheduled = false;
64
69
  private disposed = false;
@@ -68,6 +73,10 @@ export class ZLinkMeshDispatchPump {
68
73
  private readonly capacityStop = new AbortController();
69
74
  private recordsSinceYield = 0;
70
75
  private yieldStartedAtMs = 0;
76
+ /** Drains in progress; the batch budget begins when work starts on an idle pump. */
77
+ private draining = 0;
78
+ /** The macrotask boundary every drain waits for once the shared budget is spent. */
79
+ private pendingYield?: Promise<void>;
71
80
 
72
81
  constructor(
73
82
  private readonly node: ZLinkBackendMeshNode,
@@ -85,7 +94,7 @@ export class ZLinkMeshDispatchPump {
85
94
  });
86
95
  }
87
96
 
88
- async dispose(): Promise<void> {
97
+ async dispose(signal?: AbortSignal): Promise<void> {
89
98
  if (this.disposed) {
90
99
  return;
91
100
  }
@@ -95,7 +104,7 @@ export class ZLinkMeshDispatchPump {
95
104
  for (const wake of this.idleApplicationWorkers) wake();
96
105
  this.idleApplicationWorkers.clear();
97
106
  while (this.activeDrains.size > 0) {
98
- await Promise.all([...this.activeDrains]);
107
+ await awaitWithAbort(Promise.all([...this.activeDrains]), signal);
99
108
  }
100
109
  }
101
110
 
@@ -159,12 +168,40 @@ export class ZLinkMeshDispatchPump {
159
168
  try {
160
169
  for (;;) {
161
170
  await this.waitForApplicationReady();
162
- if (this.disposed) return;
171
+ this.beginDrain();
163
172
  try {
164
- await this.drainDomain(ReadyDomain.Application, readyBatch, receiveBatch);
173
+ while (!this.disposed) {
174
+ readyBatch.reset();
175
+ const drained = this.node.drainReady(
176
+ ReadyDomain.Application,
177
+ readyBatch,
178
+ ZLINK_BACKEND_RECV_DONT_WAIT
179
+ );
180
+ if (!drained.ok || drained.records.length === 0) break;
181
+ if (drained.hasResidue) this.markReady(ReadyDomain.Application);
182
+ for (let index = 0; index < drained.records.length; index += 1) {
183
+ const claim = readyBatch.takeClaim(index);
184
+ // Raw ingress already attached one host permit to each record.
185
+ // A claim reserving admission may receive only that permit's record.
186
+ await this.drainClaim(
187
+ ReadyDomain.Application,
188
+ drained.records[index]!,
189
+ claim,
190
+ receiveBatch
191
+ );
192
+ }
193
+ // Empty ready claims count toward the shared pump budget too.
194
+ this.recordsSinceYield += 1;
195
+ const yieldTurn = this.yieldIfNeeded();
196
+ if (yieldTurn !== undefined) await yieldTurn;
197
+ }
165
198
  } catch (error) {
166
199
  this.reportDispatchError(error);
200
+ } finally {
201
+ readyBatch.reset();
202
+ this.draining -= 1;
167
203
  }
204
+ if (this.disposed) return;
168
205
  }
169
206
  } finally {
170
207
  receiveBatch.close();
@@ -181,34 +218,62 @@ export class ZLinkMeshDispatchPump {
181
218
  return new Promise((resolve) => this.idleApplicationWorkers.add(resolve));
182
219
  }
183
220
 
184
- private dispatchRecord(owner: ReadyRecord, record: ReceiveRecord): void | Promise<void> {
185
- let result: void | Promise<void>;
221
+ /**
222
+ * Starts one record in this worker's turn; a permit's scope covers the
223
+ * synchronous dispatch. Returns `false` when the dispatch threw (already
224
+ * reported), `true` when it returned synchronously, or the handler's pending
225
+ * completion, which the draining turn awaits itself before
226
+ * {@link finishRecord}.
227
+ */
228
+ private dispatchRecord(
229
+ owner: ReadyRecord,
230
+ record: ReceiveRecord,
231
+ permit: ApplicationJobPermitPort | undefined
232
+ ): boolean | PromiseLike<void> {
233
+ const previous = permit === undefined ? undefined : enterApplicationJobPermitScope(permit);
234
+ let result: void | PromiseLike<void>;
186
235
  try {
187
236
  result = this.options.dispatch(owner, record);
188
237
  } catch (error) {
189
- this.reportDispatchError(error, meshDispatchFailureContext(record));
190
- return;
238
+ this.failRecord(error, record, permit);
239
+ return false;
240
+ } finally {
241
+ if (permit !== undefined) leaveApplicationJobPermitScope(previous);
191
242
  }
192
- return result === undefined
193
- ? this.finishRecord(record)
194
- : Promise.resolve(result).then(
195
- () => this.finishRecord(record),
196
- (error) => this.reportDispatchError(error, meshDispatchFailureContext(record))
197
- );
243
+ return result ?? true;
244
+ }
245
+
246
+ private failRecord(
247
+ error: unknown,
248
+ record: ReceiveRecord,
249
+ permit: ApplicationJobPermitPort | undefined
250
+ ): void {
251
+ releaseApplicationJobPermitTurn(permit);
252
+ this.reportDispatchError(error, meshDispatchFailureContext(record));
198
253
  }
199
254
 
200
- private finishRecord(record: ReceiveRecord): void | Promise<void> {
201
- let result: void | Promise<void>;
255
+ /** Runs the record's terminal completion, then releases its permit turn. */
256
+ private finishRecord(
257
+ record: ReceiveRecord,
258
+ permit: ApplicationJobPermitPort | undefined
259
+ ): void | Promise<void> {
260
+ let result: void | Promise<void> = undefined;
202
261
  try {
203
262
  result = record.onTerminalCompletion?.();
204
263
  } catch (error) {
205
264
  this.reportDispatchError(error, meshDispatchFailureContext(record));
265
+ }
266
+ if (result === undefined) {
267
+ releaseApplicationJobPermitTurn(permit);
206
268
  return;
207
269
  }
208
- if (result !== undefined)
209
- return Promise.resolve(result).catch((error) =>
210
- this.reportDispatchError(error, meshDispatchFailureContext(record))
211
- );
270
+ return Promise.resolve(result).then(
271
+ () => releaseApplicationJobPermitTurn(permit),
272
+ (error) => {
273
+ this.reportDispatchError(error, meshDispatchFailureContext(record));
274
+ releaseApplicationJobPermitTurn(permit);
275
+ }
276
+ );
212
277
  }
213
278
 
214
279
  private reportDispatchError(error: unknown, context?: ZLinkMeshDispatchFailureContext): void {
@@ -260,12 +325,7 @@ export class ZLinkMeshDispatchPump {
260
325
  if ((this.pendingDomains & ReadyDomain.Application) !== 0) {
261
326
  setImmediate(() => this.wakeApplicationWorker());
262
327
  }
263
- const lifecycleBudgetExhausted = await this.drainDomain(
264
- ReadyDomain.Infrastructure,
265
- readyBatch,
266
- undefined,
267
- MESH_DISPATCH_LIFECYCLE_CLAIM_BUDGET
268
- );
328
+ const lifecycleBudgetExhausted = await this.drainDomain(readyBatch);
269
329
  if (lifecycleBudgetExhausted) {
270
330
  this.pendingDomains |= ReadyDomain.Infrastructure;
271
331
  await yieldToEventLoop();
@@ -276,117 +336,40 @@ export class ZLinkMeshDispatchPump {
276
336
  }
277
337
  }
278
338
 
279
- private async drainDomain(
280
- domain: number,
281
- readyBatch: ReadyBatch,
282
- receiveBatch: ReceiveBatch | undefined,
283
- claimBudget?: number
284
- ): Promise<boolean> {
339
+ private async drainDomain(readyBatch: ReadyBatch): Promise<boolean> {
285
340
  let claimsDrained = 0;
341
+ this.beginDrain();
286
342
  try {
287
343
  while (!this.disposed) {
288
- if (claimBudget !== undefined && claimsDrained >= claimBudget) {
344
+ if (claimsDrained >= MESH_DISPATCH_LIFECYCLE_CLAIM_BUDGET) {
289
345
  // Lifecycle work has priority, but a bounded turn lets application
290
346
  // work make progress when lifecycle records keep arriving.
291
347
  return true;
292
348
  }
293
349
  readyBatch.reset();
294
- const drained = this.node.drainReady(domain, readyBatch, ZLINK_BACKEND_RECV_DONT_WAIT);
350
+ const drained = this.node.drainReady(
351
+ ReadyDomain.Infrastructure,
352
+ readyBatch,
353
+ ZLINK_BACKEND_RECV_DONT_WAIT
354
+ );
295
355
  if (!drained.ok || drained.records.length === 0) {
296
356
  return false;
297
357
  }
298
- if (domain === ReadyDomain.Application && drained.hasResidue) {
299
- this.markReady(ReadyDomain.Application);
300
- }
301
358
  for (let index = 0; index < drained.records.length; index += 1) {
302
359
  const claim = readyBatch.takeClaim(index);
303
360
  claimsDrained += 1;
304
361
  const owner = drained.records[index]!;
305
- // Raw ingress already attached one host permit to each record.
306
- // A claim that reserves admission here may receive only that permit's record.
307
- const drainClaim = async () => {
308
- let ownerReceiveBatch = receiveBatch;
309
- try {
310
- ownerReceiveBatch ??= this.node.createReceiveBatch(
311
- MESH_DISPATCH_RECEIVE_CAPACITY,
312
- this.options.partCapacity ?? DEFAULT_MESH_PART_CAPACITY
313
- );
314
- const capacity =
315
- owner.ordinaryIngressPreAdmitted === true ? MESH_DISPATCH_RECEIVE_CAPACITY : 1;
316
- let claimPermit =
317
- owner.terminalCompletion === true ||
318
- owner.ordinaryIngressPreAdmitted === true ||
319
- domain === ReadyDomain.Infrastructure
320
- ? undefined
321
- : await this.acquirePermit();
322
- try {
323
- if (this.capacityStop.signal.aborted) return;
324
- ownerReceiveBatch.reset(capacity);
325
- const received = claim.recvBatch(ownerReceiveBatch, ZLINK_BACKEND_RECV_DONT_WAIT);
326
- if (received.ok) {
327
- // The bounded batch stays in claim order until its records finish.
328
- try {
329
- for (const record of received.records) {
330
- if (this.disposed) break;
331
- const permit = record.applicationJobPermit ?? claimPermit;
332
- if (owner.ordinaryIngressPreAdmitted === true && permit === undefined) {
333
- throw new Error(
334
- 'Pre-admitted raw ingress record lost its Application Job Queue permit.'
335
- );
336
- }
337
- this.recordsSinceYield += 1;
338
- if (permit === undefined) {
339
- const dispatched = this.dispatchRecord(owner, record);
340
- if (dispatched !== undefined) await dispatched;
341
- } else {
342
- if (
343
- domain === ReadyDomain.Application &&
344
- record.applicationJobPermit === undefined
345
- )
346
- permit.markApplicationQueued();
347
- // The scope now owns this reservation, including failure
348
- // and detached handler handoff. Only unused permits remain
349
- // owned by the receive attempt's finally block.
350
- if (permit === claimPermit) claimPermit = undefined;
351
- const dispatched = runWithApplicationJobPermit(
352
- permit,
353
- this.dispatchOwnedRecord,
354
- owner,
355
- record
356
- );
357
- if (dispatched !== undefined) await dispatched;
358
- }
359
- }
360
- } finally {
361
- // Batch ownership includes records whose dispatch never began,
362
- // including on failure or shutdown in the middle of the batch.
363
- for (const record of received.records) {
364
- for (const part of record.parts) part.close();
365
- record.releaseRetainedIngress?.();
366
- }
367
- }
368
- }
369
- } finally {
370
- claimPermit?.releaseAfterInternalProcessing();
371
- }
372
- } finally {
373
- claim.release();
374
- if (receiveBatch === undefined) ownerReceiveBatch?.close();
375
- }
376
- const yieldTurn = this.yieldIfNeeded();
377
- if (yieldTurn !== undefined) await yieldTurn;
378
- };
379
- // An application worker drains the one owner it claimed. Infrastructure owners
380
- // drain independently, so a suspended owner does not hold the other claims.
381
- if (receiveBatch !== undefined) {
382
- await drainClaim();
383
- } else {
384
- const drain = drainClaim().catch((error) => this.reportDispatchError(error));
385
- this.activeDrains.add(drain);
386
- void drain.finally(() => this.activeDrains.delete(drain));
387
- }
362
+ this.beginDrain();
363
+ const drain = this.drainClaim(ReadyDomain.Infrastructure, owner, claim, undefined).catch(
364
+ (error) => this.reportDispatchError(error)
365
+ );
366
+ this.activeDrains.add(drain);
367
+ void drain.finally(() => {
368
+ this.draining -= 1;
369
+ this.activeDrains.delete(drain);
370
+ });
388
371
  }
389
- if (claimBudget !== undefined && claimsDrained >= claimBudget) {
372
+ if (claimsDrained >= MESH_DISPATCH_LIFECYCLE_CLAIM_BUDGET) {
390
373
  this.wakeApplicationWorker();
391
374
  return true;
392
375
  }
@@ -399,10 +382,123 @@ export class ZLinkMeshDispatchPump {
399
382
  return false;
400
383
  } finally {
401
384
  readyBatch.reset();
385
+ this.draining -= 1;
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Time the pump spent idle is not batch work: when work starts on an idle
391
+ * pump, its batch budget starts with it (spec 08 §6).
392
+ */
393
+ private beginDrain(): void {
394
+ if (this.draining === 0) {
395
+ this.recordsSinceYield = 0;
396
+ this.yieldStartedAtMs = this.nowMs();
397
+ }
398
+ this.draining += 1;
399
+ }
400
+
401
+ /** Drains one claimed owner in this worker's turn, in claim order. */
402
+ private async drainClaim(
403
+ domain: number,
404
+ owner: ReadyRecord,
405
+ claim: Claim,
406
+ receiveBatch: ReceiveBatch | undefined
407
+ ): Promise<void> {
408
+ let ownerReceiveBatch = receiveBatch;
409
+ try {
410
+ ownerReceiveBatch ??= this.node.createReceiveBatch(
411
+ MESH_DISPATCH_RECEIVE_CAPACITY,
412
+ this.options.partCapacity ?? DEFAULT_MESH_PART_CAPACITY
413
+ );
414
+ const capacity =
415
+ owner.ordinaryIngressPreAdmitted === true ? MESH_DISPATCH_RECEIVE_CAPACITY : 1;
416
+ let claimPermit =
417
+ owner.terminalCompletion === true ||
418
+ owner.ordinaryIngressPreAdmitted === true ||
419
+ domain === ReadyDomain.Infrastructure
420
+ ? undefined
421
+ : await this.acquirePermit();
422
+ try {
423
+ if (this.capacityStop.signal.aborted) return;
424
+ ownerReceiveBatch.reset(capacity);
425
+ const received = claim.recvBatch(ownerReceiveBatch, ZLINK_BACKEND_RECV_DONT_WAIT);
426
+ if (received.ok) {
427
+ // The bounded batch stays in claim order until its records finish.
428
+ try {
429
+ for (const record of received.records) {
430
+ if (this.disposed) break;
431
+ const permit = record.applicationJobPermit ?? claimPermit;
432
+ if (owner.ordinaryIngressPreAdmitted === true && permit === undefined) {
433
+ throw new Error(
434
+ 'Pre-admitted raw ingress record lost its Application Job Queue permit.'
435
+ );
436
+ }
437
+ this.recordsSinceYield += 1;
438
+ if (permit !== undefined) {
439
+ if (domain === ReadyDomain.Application && record.applicationJobPermit === undefined)
440
+ permit.markApplicationQueued();
441
+ // The scope now owns this reservation, including failure
442
+ // and detached handler handoff. Only unused permits remain
443
+ // owned by the receive attempt's finally block.
444
+ if (permit === claimPermit) claimPermit = undefined;
445
+ }
446
+ // The record's terminal and the permit turn release follow the
447
+ // handler in this turn's own continuation.
448
+ if (record.prepareDispatch !== undefined) {
449
+ try {
450
+ const stopSignal = this.capacityStop.signal;
451
+ const preparation = record.prepareDispatch(stopSignal);
452
+ const accepted = preparation instanceof Promise ? await preparation : preparation;
453
+ if (!accepted || stopSignal.aborted) {
454
+ releaseApplicationJobPermitTurn(permit);
455
+ continue;
456
+ }
457
+ } catch (error) {
458
+ this.failRecord(error, record, permit);
459
+ continue;
460
+ }
461
+ }
462
+ const dispatched = this.dispatchRecord(owner, record, permit);
463
+ if (dispatched === false) continue;
464
+ if (dispatched !== true) {
465
+ try {
466
+ await dispatched;
467
+ } catch (error) {
468
+ this.failRecord(error, record, permit);
469
+ continue;
470
+ }
471
+ }
472
+ const finished = this.finishRecord(record, permit);
473
+ if (finished !== undefined) await finished;
474
+ }
475
+ } finally {
476
+ // Batch ownership includes records whose dispatch never began,
477
+ // including on failure or shutdown in the middle of the batch.
478
+ for (const record of received.records) {
479
+ for (const part of record.parts) part.close();
480
+ record.releaseRetainedIngress?.();
481
+ }
482
+ }
483
+ }
484
+ } finally {
485
+ claimPermit?.releaseAfterInternalProcessing();
486
+ }
487
+ } finally {
488
+ claim.release();
489
+ if (receiveBatch === undefined) ownerReceiveBatch?.close();
402
490
  }
491
+ const yieldTurn = this.yieldIfNeeded();
492
+ if (yieldTurn !== undefined) await yieldTurn;
403
493
  }
404
494
 
495
+ /**
496
+ * The batch budget is shared by every drain of this pump, so once it is
497
+ * spent every drain waits for the same macrotask boundary; one drain that
498
+ * keeps running would otherwise hold the event loop the yield was for.
499
+ */
405
500
  private yieldIfNeeded(): Promise<void> | undefined {
501
+ if (this.pendingYield !== undefined) return this.pendingYield;
406
502
  const nowMs = this.nowMs();
407
503
  if (
408
504
  this.recordsSinceYield < MESH_DISPATCH_YIELD_RECORDS &&
@@ -410,9 +506,12 @@ export class ZLinkMeshDispatchPump {
410
506
  )
411
507
  return undefined;
412
508
  this.recordsSinceYield = 0;
413
- return yieldToTimers().then(() => {
509
+ const pendingYield = yieldToTimers().then(() => {
510
+ this.pendingYield = undefined;
414
511
  this.yieldStartedAtMs = this.nowMs();
415
512
  });
513
+ this.pendingYield = pendingYield;
514
+ return pendingYield;
416
515
  }
417
516
 
418
517
  private nowMs(): number {