@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
@@ -29,7 +29,14 @@ class OperationRegistry {
29
29
  entries = new Map();
30
30
  nextId = 1n;
31
31
  deadlineCursor;
32
+ /**
33
+ * A lower bound of the earliest pending deadline. Completed entries only
34
+ * leave it early; a full expiry pass replaces it with the exact value.
35
+ */
36
+ earliestDeadlineMs = Number.POSITIVE_INFINITY;
37
+ scanEarliestDeadlineMs = Number.POSITIVE_INFINITY;
32
38
  closed = false;
39
+ pendingCount = 0;
33
40
  constructor(clock = systemClock, onPendingChanged) {
34
41
  this.clock = clock;
35
42
  this.onPendingChanged = onPendingChanged;
@@ -47,36 +54,63 @@ class OperationRegistry {
47
54
  resolve = onResolve;
48
55
  reject = onReject;
49
56
  });
50
- const entry = {
51
- context,
52
- deadlineMs: timeoutOwner === 'registry' ? this.clock.now() + timeoutMs : undefined,
53
- resolve,
54
- reject
55
- };
57
+ const deadlineMs = timeoutOwner === 'registry' ? this.clock.now() + timeoutMs : undefined;
58
+ const entry = { context, deadlineMs, resolve, reject };
56
59
  this.entries.set(id, entry);
57
- if (this.entries.size === 1)
58
- this.onPendingChanged?.();
60
+ this.notePending(deadlineMs);
59
61
  return { id, promise };
60
62
  }
61
- complete(id, value) {
63
+ /** Registers an operation whose terminal goes to `observer` instead of a Promise. */
64
+ registerObserved(timeoutMs, observer, context) {
65
+ if (this.closed)
66
+ throw new Error('Operation registry is closed.');
67
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
68
+ throw new RangeError('timeoutMs must be a non-negative finite number.');
69
+ }
70
+ const id = this.nextId++;
71
+ const deadlineMs = this.clock.now() + timeoutMs;
72
+ this.entries.set(id, { context, deadlineMs, observer });
73
+ this.notePending(deadlineMs);
74
+ return id;
75
+ }
76
+ /** The time the next expiry pass has work, as a lower bound (spec 08 §4.2). */
77
+ nextDeadlineMs() {
78
+ return this.earliestDeadlineMs;
79
+ }
80
+ notePending(deadlineMs) {
81
+ this.pendingCount++;
82
+ const earlier = deadlineMs !== undefined && deadlineMs < this.earliestDeadlineMs;
83
+ if (earlier)
84
+ this.earliestDeadlineMs = deadlineMs;
85
+ if (earlier || this.pendingCount === 1)
86
+ this.onPendingChanged?.();
87
+ }
88
+ complete(id, value, terminalContextRetentionMs = 0) {
62
89
  const entry = this.take(id);
63
90
  if (entry === undefined)
64
91
  return false;
65
- entry.resolve(value);
92
+ if (entry.observer !== undefined)
93
+ entry.observer.operationCompleted(id, value, entry.context);
94
+ else
95
+ entry.resolve(value);
96
+ this.retainTerminal(id, entry, terminalContextRetentionMs);
66
97
  return true;
67
98
  }
68
99
  fail(id, reason) {
69
100
  const entry = this.take(id);
70
101
  if (entry === undefined)
71
102
  return false;
72
- entry.reject(reason);
103
+ if (entry.observer !== undefined)
104
+ entry.observer.operationFailed(id, reason, entry.context);
105
+ else
106
+ entry.reject(reason);
73
107
  return true;
74
108
  }
75
109
  cancel(id, message) {
76
110
  return this.fail(id, new OperationCancelledError(id, message));
77
111
  }
78
112
  isPending(id) {
79
- return this.entries.has(id);
113
+ return this.pendingEntry(id) !== undefined;
80
114
  }
81
115
  context(id) {
82
116
  return this.entries.get(id)?.context;
@@ -87,36 +121,70 @@ class OperationRegistry {
87
121
  this.closed = true;
88
122
  for (const id of this.entries.keys())
89
123
  this.cancel(id, reason);
124
+ this.entries.clear();
90
125
  this.deadlineCursor = undefined;
91
126
  }
127
+ failAll(reason) {
128
+ for (const id of this.entries.keys())
129
+ this.fail(id, reason);
130
+ }
92
131
  get size() {
93
- return this.entries.size;
132
+ return this.pendingCount;
94
133
  }
95
134
  expire(nowMs, turnDeadlineMs) {
96
135
  let expired = 0;
97
136
  while (this.clock.now() < turnDeadlineMs) {
98
- this.deadlineCursor ??= this.entries.entries();
137
+ if (this.deadlineCursor === undefined) {
138
+ this.deadlineCursor = this.entries.entries();
139
+ this.scanEarliestDeadlineMs = Number.POSITIVE_INFINITY;
140
+ }
99
141
  const current = this.deadlineCursor.next();
100
142
  if (current.done === true) {
101
143
  this.deadlineCursor = undefined;
144
+ // Entries registered during the pass are appended and were scanned.
145
+ this.earliestDeadlineMs = this.scanEarliestDeadlineMs;
102
146
  break;
103
147
  }
104
148
  const [id, entry] = current.value;
105
- if (entry.deadlineMs !== undefined && entry.deadlineMs <= nowMs) {
106
- if (this.fail(id, new OperationTimeoutError(id)))
149
+ if (entry.deadlineMs === undefined)
150
+ continue;
151
+ if (entry.deadlineMs <= nowMs) {
152
+ if (!this.isPending(id))
153
+ this.entries.delete(id);
154
+ else if (this.fail(id, new OperationTimeoutError(id)))
107
155
  expired++;
108
156
  }
157
+ else if (entry.deadlineMs < this.scanEarliestDeadlineMs) {
158
+ this.scanEarliestDeadlineMs = entry.deadlineMs;
159
+ }
109
160
  }
110
161
  return expired;
111
162
  }
112
163
  take(id) {
113
- const entry = this.entries.get(id);
164
+ const entry = this.pendingEntry(id);
114
165
  if (entry === undefined)
115
166
  return undefined;
116
167
  this.entries.delete(id);
117
- if (this.entries.size === 0)
168
+ this.pendingCount--;
169
+ if (this.pendingCount === 0)
118
170
  this.onPendingChanged?.();
119
171
  return entry;
120
172
  }
173
+ pendingEntry(id) {
174
+ const entry = this.entries.get(id);
175
+ return entry !== undefined && (entry.resolve !== undefined || entry.observer !== undefined)
176
+ ? entry
177
+ : undefined;
178
+ }
179
+ retainTerminal(id, entry, retentionMs) {
180
+ if (this.closed || entry.context === undefined || retentionMs === 0)
181
+ return;
182
+ entry.resolve = undefined;
183
+ entry.reject = undefined;
184
+ entry.observer = undefined;
185
+ entry.deadlineMs = this.clock.now() + retentionMs;
186
+ this.entries.set(id, entry);
187
+ this.earliestDeadlineMs = Math.min(this.earliestDeadlineMs, entry.deadlineMs);
188
+ }
121
189
  }
122
190
  exports.OperationRegistry = OperationRegistry;
@@ -2,7 +2,7 @@ import { ApplicationIngressRecordOwner } from '../application-jobs/application-i
2
2
  import type { ApplicationJobQueuePort } from '../application-jobs/contracts';
3
3
  import type { ZLinkRawBindingPort } from '../backend/raw-binding-port';
4
4
  import { SubmitResult } from '../backend/runtime-values';
5
- import { type PendingOperation } from './operation-registry';
5
+ import { type OperationObserver, type PendingOperation } from './operation-registry';
6
6
  import { ServiceLivenessRegistry, type ServiceLivenessTick } from './service-liveness-registry';
7
7
  import { ServiceMailbox, type ServiceMailboxRecord } from './service-mailbox';
8
8
  import { ServiceTopologyRegistry, type ServiceNodeDescriptor } from './service-topology-registry';
@@ -14,9 +14,22 @@ export interface RawServiceRequestResult {
14
14
  readonly failureCode: number;
15
15
  readonly payload?: ServiceApplicationPayload;
16
16
  }
17
+ /** Receives observed request terminals; the context is the caller's operation kind. */
18
+ export type RawServiceRequestObserver = OperationObserver<RawServiceRequestResult, number>;
19
+ /**
20
+ * A registered request. An observed remote request has no Promise; its
21
+ * terminal reaches the observer. Local and Promise-contract requests carry
22
+ * the Promise.
23
+ */
24
+ export interface RawServiceObservedRequest {
25
+ readonly id: bigint;
26
+ readonly promise?: Promise<RawServiceRequestResult>;
27
+ }
17
28
  /** An M6A application frame already owned by the Framework runtime. */
18
29
  type ServiceApplicationPayloadInput = ServiceApplicationPayload | Buffer;
19
30
  export interface RawServiceIngressRecord {
31
+ /** Source identity recorded once by the first accepting owner (Location runtime §9.3). */
32
+ requestSource?: import('../locations/request-source-resolver').ZLinkRequestSourceFence;
20
33
  readonly onAdmitted?: () => void;
21
34
  readonly command: number;
22
35
  readonly flags: number;
@@ -104,12 +117,14 @@ export declare class RawServiceMeshRuntime {
104
117
  disconnectPeerEndpoint(endpoint: string): void;
105
118
  observePeerConnectionIntentRemoved(listener: (nodeRoutingId: string) => void): () => void;
106
119
  observePeerRoute(nodeRoutingId: string): import('./durable-service-request').PeerRouteObservation;
120
+ waitForPeerRoute(nodeRoutingId: string, lifecycleGeneration: bigint, deadlineUnixMs: bigint, signal?: AbortSignal): Promise<void>;
107
121
  get requestStopSignal(): AbortSignal;
108
122
  observePeerRouteChanged(listener: (nodeRoutingId: string) => void): () => void;
109
123
  hasSelectedPeerRoute(nodeRoutingId: string): boolean;
110
124
  private notifyPeerRouteChanged;
111
125
  private notifyPeerConnectionIntentRemoved;
112
- announcePeer(nodeRoutingId: string): Promise<boolean>;
126
+ announcePeer(nodeRoutingId: string): boolean;
127
+ private isPeerAnnouncementCurrent;
113
128
  isPeerRouteReady(nodeRoutingId: string, lifecycleGeneration?: bigint): boolean;
114
129
  announceExpectedPeers(): Promise<number>;
115
130
  updateLocalDescriptor(options: {
@@ -124,7 +139,20 @@ export declare class RawServiceMeshRuntime {
124
139
  sendToNode(targetNodeRoutingId: string, payload: ServiceApplicationPayloadInput): boolean | Promise<boolean>;
125
140
  sendToChannel(channelName: string, payload: ServiceApplicationPayloadInput): Promise<SubmitResult>;
126
141
  requestToNode(targetNodeRoutingId: string, payload: ServiceApplicationPayloadInput, timeoutMs: number, onAdmitted?: () => void): PendingOperation<RawServiceRequestResult>;
142
+ requestToNode(targetNodeRoutingId: string, payload: ServiceApplicationPayloadInput, timeoutMs: number, onAdmitted: (() => void) | undefined, observer: RawServiceRequestObserver, operationKind: number): RawServiceObservedRequest;
127
143
  requestToChannel(channelName: string, payload: ServiceApplicationPayloadInput, timeoutMs: number, onAdmitted?: () => void): PendingOperation<RawServiceRequestResult>;
144
+ requestToChannel(channelName: string, payload: ServiceApplicationPayloadInput, timeoutMs: number, onAdmitted: (() => void) | undefined, observer: RawServiceRequestObserver, operationKind: number): RawServiceObservedRequest;
145
+ /**
146
+ * One pending entry per request: an observed request reports its terminal
147
+ * to the caller's observer; any other request keeps the Promise contract.
148
+ */
149
+ private registerRequest;
150
+ /**
151
+ * An observed caller learns the operation id only when the request call
152
+ * returns, so a terminal decided inside that call is delivered after it.
153
+ */
154
+ private completeRequest;
155
+ private failRequest;
128
156
  private selectChannelTarget;
129
157
  setServiceIngress(handler: RawServiceIngressHandler, accepts?: (command: number) => boolean): void;
130
158
  reserveLocalIngress(signal?: AbortSignal): Promise<ApplicationIngressRecordOwner>;
@@ -148,6 +176,14 @@ export declare class RawServiceMeshRuntime {
148
176
  private enqueueOrdinaryRecord;
149
177
  expireOperations(nowMs: number, turnDeadlineMs: number): number;
150
178
  get pendingOperationCount(): number;
179
+ cancelPendingOperations(reason: unknown): void;
180
+ /**
181
+ * The next management deadline of this node (spec 08 §4.2): request expiry,
182
+ * liveness probe or timeout, or an owned HELLO exchange still awaiting
183
+ * ADMIT, which keeps the existing announce cadence.
184
+ */
185
+ nextMaintenanceDeadlineMs(nowMs: number): number;
186
+ private refreshAdmissionPending;
151
187
  tickLiveness(nowMs?: number): ServiceLivenessTick;
152
188
  /**
153
189
  * The socket's one route observer (Core ROUTER §10.1). It replaces the
@@ -172,7 +208,7 @@ export declare class RawServiceMeshRuntime {
172
208
  private sendControl;
173
209
  private submitControl;
174
210
  private startControlSend;
175
- private reportInfrastructureFailure;
211
+ reportInfrastructureFailure(error: unknown): void;
176
212
  private observeInfrastructureFailure;
177
213
  private send;
178
214
  private sendFailure;
@@ -177,13 +177,15 @@ class RawServiceMeshRuntime {
177
177
  router.disconnectRid(nodeRoutingId);
178
178
  }
179
179
  else {
180
- router.disconnect(endpoint);
180
+ try {
181
+ router.disconnect(endpoint);
182
+ }
183
+ catch (error) {
184
+ if (!isAlreadyDisconnectedError(error))
185
+ throw error;
186
+ }
181
187
  }
182
188
  }
183
- catch (error) {
184
- if (!isAlreadyDisconnectedError(error))
185
- throw error;
186
- }
187
189
  finally {
188
190
  if (current !== undefined)
189
191
  this.removePeer(current);
@@ -237,6 +239,34 @@ class RawServiceMeshRuntime {
237
239
  ready: admitted !== undefined && (selected === undefined || admitted === selected)
238
240
  };
239
241
  }
242
+ async waitForPeerRoute(nodeRoutingId, lifecycleGeneration, deadlineUnixMs, signal) {
243
+ const remaining = deadlineUnixMs - BigInt(Date.now());
244
+ if (remaining <= 0n)
245
+ throw new operation_registry_1.OperationTimeoutError(0n);
246
+ const pending = this.operations.register(Number(remaining));
247
+ const check = () => {
248
+ if (this.isPeerRouteReady(nodeRoutingId, lifecycleGeneration)) {
249
+ this.operations.complete(pending.id, { terminalResult: runtime_values_1.RequestResult.Ok, failureCode: 0 });
250
+ }
251
+ };
252
+ const unsubscribe = this.observePeerRouteChanged((rid) => {
253
+ if (rid === nodeRoutingId)
254
+ check();
255
+ });
256
+ const abort = () => this.operations.fail(pending.id, signal?.reason);
257
+ signal?.addEventListener('abort', abort, { once: true });
258
+ try {
259
+ if (signal?.aborted === true)
260
+ abort();
261
+ else
262
+ check();
263
+ await pending.promise;
264
+ }
265
+ finally {
266
+ unsubscribe();
267
+ signal?.removeEventListener('abort', abort);
268
+ }
269
+ }
240
270
  get requestStopSignal() {
241
271
  return this.applicationJobStop.signal;
242
272
  }
@@ -262,26 +292,29 @@ class RawServiceMeshRuntime {
262
292
  listener(nodeRoutingId);
263
293
  }
264
294
  announcePeer(nodeRoutingId) {
295
+ if (this.closed)
296
+ return false;
265
297
  const generation = this.selectedRoutes.get(nodeRoutingId);
266
298
  if (generation === undefined)
267
- return Promise.resolve(false);
268
- const current = () => {
269
- const admission = this.topology.routeAdmission(nodeRoutingId);
270
- return (this.selectedRoutes.get(nodeRoutingId) === generation &&
271
- !(admission?.connectionId === routeConnectionId(generation) &&
272
- admission.remoteAdmitReceived === true) &&
273
- this.peerAdmissionSealed?.() !== true);
274
- };
299
+ return false;
275
300
  const key = controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
276
- if (!current()) {
301
+ if (!this.isPeerAnnouncementCurrent(nodeRoutingId, generation)) {
277
302
  this.controlSends.delete(key);
278
- return Promise.resolve(false);
303
+ return false;
279
304
  }
305
+ const current = () => this.isPeerAnnouncementCurrent(nodeRoutingId, generation);
280
306
  const existing = this.controlSends.get(key);
281
307
  const hello = existing?.current?.() === true
282
308
  ? existing.hello
283
309
  : (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor());
284
- return Promise.resolve(this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [hello]), current, hello));
310
+ return this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [hello]), current, hello);
311
+ }
312
+ isPeerAnnouncementCurrent(nodeRoutingId, generation) {
313
+ const admission = this.topology.routeAdmission(nodeRoutingId);
314
+ return (this.selectedRoutes.get(nodeRoutingId) === generation &&
315
+ !(admission?.connectionId === routeConnectionId(generation) &&
316
+ admission.remoteAdmitReceived === true) &&
317
+ this.peerAdmissionSealed?.() !== true);
285
318
  }
286
319
  isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
287
320
  // Admission is bound to the observed selected route: the route observer
@@ -353,17 +386,42 @@ class RawServiceMeshRuntime {
353
386
  ? runtime_values_1.SubmitResult.Ok
354
387
  : runtime_values_1.SubmitResult.NotConnected;
355
388
  }
356
- requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted) {
357
- return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted);
389
+ requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted, observer, operationKind) {
390
+ return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted, observer, operationKind);
358
391
  }
359
- requestToChannel(channelName, payload, timeoutMs, onAdmitted) {
392
+ requestToChannel(channelName, payload, timeoutMs, onAdmitted, observer, operationKind) {
360
393
  const selection = this.selectChannelTarget(channelName);
361
394
  if (selection.kind !== 'selected') {
362
- const pending = this.operations.register(timeoutMs);
363
- this.operations.complete(pending.id, selection.requestResult);
395
+ const pending = this.registerRequest(timeoutMs, observer, operationKind);
396
+ this.completeRequest(pending, selection.requestResult);
364
397
  return pending;
365
398
  }
366
- return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName, onAdmitted);
399
+ return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName, onAdmitted, observer, operationKind);
400
+ }
401
+ /**
402
+ * One pending entry per request: an observed request reports its terminal
403
+ * to the caller's observer; any other request keeps the Promise contract.
404
+ */
405
+ registerRequest(timeoutMs, observer, operationKind) {
406
+ return observer === undefined
407
+ ? this.operations.register(timeoutMs)
408
+ : { id: this.operations.registerObserved(timeoutMs, observer, operationKind) };
409
+ }
410
+ /**
411
+ * An observed caller learns the operation id only when the request call
412
+ * returns, so a terminal decided inside that call is delivered after it.
413
+ */
414
+ completeRequest(pending, result) {
415
+ if (pending.promise === undefined)
416
+ queueMicrotask(() => this.operations.complete(pending.id, result));
417
+ else
418
+ this.operations.complete(pending.id, result);
419
+ }
420
+ failRequest(pending, error) {
421
+ if (pending.promise === undefined)
422
+ queueMicrotask(() => this.operations.fail(pending.id, error));
423
+ else
424
+ this.operations.fail(pending.id, error);
367
425
  }
368
426
  selectChannelTarget(channelName) {
369
427
  const selected = this.topology.selectChannel(channelName, (peer) => this.isPeerRouteReady(peer.descriptor.nodeRoutingId));
@@ -718,6 +776,7 @@ class RawServiceMeshRuntime {
718
776
  }
719
777
  else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
720
778
  this.controlSends.delete(helloKey);
779
+ this.refreshAdmissionPending(nowMs);
721
780
  if (result === 'notRequired') {
722
781
  this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
723
782
  }
@@ -779,12 +838,7 @@ class RawServiceMeshRuntime {
779
838
  }
780
839
  if (header.flags !== 0 ||
781
840
  received.parts.length !== 2 ||
782
- ![
783
- service_wire_m6a_codec_1.M6aServiceWireCommand.nodeSend,
784
- service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest,
785
- service_wire_m6a_codec_1.M6aServiceWireCommand.channelSend,
786
- service_wire_m6a_codec_1.M6aServiceWireCommand.channelRequest
787
- ].includes(header.command)) {
841
+ !isApplicationEnvelopeCommand(header.command)) {
788
842
  return 'protocolError';
789
843
  }
790
844
  let owner;
@@ -820,9 +874,9 @@ class RawServiceMeshRuntime {
820
874
  parts: received.parts,
821
875
  sourceRoutingId: received.sourceRid,
822
876
  sourceRoute: received.sourceRoute,
823
- ...(received.reply === undefined ? {} : { reply: received.reply }),
877
+ reply: received.reply,
824
878
  requestSequence: received.requestSeq,
825
- ...(correlation === undefined ? {} : { correlation }),
879
+ correlation,
826
880
  applicationJob
827
881
  });
828
882
  if (accepted)
@@ -845,11 +899,38 @@ class RawServiceMeshRuntime {
845
899
  get pendingOperationCount() {
846
900
  return this.operations.size;
847
901
  }
902
+ cancelPendingOperations(reason) {
903
+ this.operations.failAll(reason);
904
+ }
905
+ /**
906
+ * The next management deadline of this node (spec 08 §4.2): request expiry,
907
+ * liveness probe or timeout, or an owned HELLO exchange still awaiting
908
+ * ADMIT, which keeps the existing announce cadence.
909
+ */
910
+ nextMaintenanceDeadlineMs(nowMs) {
911
+ this.refreshAdmissionPending(nowMs);
912
+ return Math.min(this.operations.nextDeadlineMs(), this.liveness.nextDeadlineMs());
913
+ }
914
+ refreshAdmissionPending(nowMs) {
915
+ let pending = false;
916
+ if (!this.closed && this.controlSends.size !== 0) {
917
+ for (const nodeRoutingId of this.selectedRoutes.keys()) {
918
+ const exchange = this.controlSends.get(controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello));
919
+ if (exchange?.current?.() === true) {
920
+ pending = true;
921
+ break;
922
+ }
923
+ }
924
+ }
925
+ this.liveness.setAdmissionPending(pending, nowMs);
926
+ }
848
927
  tickLiveness(nowMs = performance.now()) {
928
+ const admissionDue = this.liveness.tickAdmission(nowMs);
849
929
  const result = this.liveness.tick(nowMs);
850
930
  this.requireStarted();
851
- for (const nodeRoutingId of this.selectedRoutes.keys())
852
- void this.announcePeer(nodeRoutingId);
931
+ if (admissionDue)
932
+ for (const nodeRoutingId of this.selectedRoutes.keys())
933
+ void this.announcePeer(nodeRoutingId);
853
934
  for (const probe of result.probes) {
854
935
  const parts = [
855
936
  livenessCodec.encodeLivenessRecord({
@@ -907,6 +988,7 @@ class RawServiceMeshRuntime {
907
988
  // A new selected route admits only through a new handshake.
908
989
  for (const nodeRoutingId of selected)
909
990
  await this.announcePeer(nodeRoutingId);
991
+ this.refreshAdmissionPending(performance.now());
910
992
  return changes;
911
993
  }
912
994
  close() {
@@ -933,13 +1015,12 @@ class RawServiceMeshRuntime {
933
1015
  this.router = undefined;
934
1016
  this.host = undefined;
935
1017
  }
936
- requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted) {
1018
+ requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted, observer, operationKind) {
937
1019
  const correlation = this.nextCorrelation++;
938
1020
  const header = channelName === undefined
939
1021
  ? (0, service_wire_m6a_codec_1.encodeNodeRequestHeader)(correlation)
940
1022
  : (0, service_wire_m6a_codec_1.encodeChannelRequestHeader)(correlation, channelName);
941
1023
  const encodedPayload = this.applicationFrame(payload);
942
- const pending = this.operations.register(timeoutMs);
943
1024
  let selectedTargetNodeRoutingId = targetNodeRoutingId;
944
1025
  if (selectedTargetNodeRoutingId !== this.descriptor.nodeRoutingId &&
945
1026
  !this.isPeerRouteReady(selectedTargetNodeRoutingId)) {
@@ -966,6 +1047,9 @@ class RawServiceMeshRuntime {
966
1047
  }
967
1048
  }
968
1049
  if (selectedTargetNodeRoutingId === this.descriptor.nodeRoutingId) {
1050
+ // The local admission path aborts its capacity wait on the terminal
1051
+ // Promise, so a local request always keeps the Promise entry.
1052
+ const pending = this.operations.register(timeoutMs);
969
1053
  const parts = [header, encodedPayload];
970
1054
  const capacityStop = new AbortController();
971
1055
  void pending.promise.finally(() => capacityStop.abort()).catch(() => undefined);
@@ -1009,12 +1093,13 @@ class RawServiceMeshRuntime {
1009
1093
  })().catch((error) => this.operations.fail(pending.id, error));
1010
1094
  return pending;
1011
1095
  }
1096
+ const pending = this.registerRequest(timeoutMs, observer, operationKind);
1012
1097
  const selectedPeer = this.topology.admittedPeer(selectedTargetNodeRoutingId);
1013
1098
  if (selectedPeer === undefined) {
1014
1099
  // Logical target selection is the requester's decision: an RID that is
1015
1100
  // not an admitted peer is not a target. Whether an admitted target's
1016
1101
  // route can carry the request is Core's REQUEST result.
1017
- this.operations.complete(pending.id, {
1102
+ this.completeRequest(pending, {
1018
1103
  terminalResult: runtime_values_1.RequestResult.NotFound,
1019
1104
  failureCode: REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
1020
1105
  });
@@ -1026,7 +1111,7 @@ class RawServiceMeshRuntime {
1026
1111
  request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived, onAdmitted);
1027
1112
  }
1028
1113
  catch (error) {
1029
- this.operations.fail(pending.id, error);
1114
+ this.failRequest(pending, error);
1030
1115
  return pending;
1031
1116
  }
1032
1117
  void request.then((replyParts) => {
@@ -1146,6 +1231,8 @@ class RawServiceMeshRuntime {
1146
1231
  }
1147
1232
  startControlSend(target, command, attempt, current, hello) {
1148
1233
  const key = controlSendKey(target, command);
1234
+ if (command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello)
1235
+ this.liveness.setAdmissionPending(true, performance.now());
1149
1236
  const existing = this.controlSends.get(key);
1150
1237
  if (existing !== undefined &&
1151
1238
  existing.task !== undefined &&
@@ -1185,15 +1272,17 @@ class RawServiceMeshRuntime {
1185
1272
  this.controlSends.set(key, state);
1186
1273
  task.then(() => { }, (error) => {
1187
1274
  completeSend();
1188
- if (this.infrastructureTaskRunner === undefined)
1189
- this.reportInfrastructureFailure(error);
1190
- });
1191
- this.infrastructureTaskRunner?.runDetached('RouteMesh control SEND', async () => {
1192
- await task;
1275
+ this.reportInfrastructureFailure(error);
1193
1276
  });
1194
1277
  return true;
1195
1278
  }
1196
1279
  reportInfrastructureFailure(error) {
1280
+ if (this.infrastructureTaskRunner !== undefined) {
1281
+ this.infrastructureTaskRunner.runDetached('RouteMesh infrastructure', async () => {
1282
+ throw error;
1283
+ });
1284
+ return;
1285
+ }
1197
1286
  this.infrastructureFailure = {
1198
1287
  error: this.infrastructureFailure === undefined
1199
1288
  ? error
@@ -1229,7 +1318,7 @@ class RawServiceMeshRuntime {
1229
1318
  }
1230
1319
  exports.RawServiceMeshRuntime = RawServiceMeshRuntime;
1231
1320
  function controlSendKey(target, command) {
1232
- return JSON.stringify([target, command]);
1321
+ return `${command}:${target}`;
1233
1322
  }
1234
1323
  function routeConnectionId(generation) {
1235
1324
  return `route:${generation}`;
@@ -1239,20 +1328,27 @@ function routeConnectionId(generation) {
1239
1328
  * not application NodeSend(16) envelopes. Keep this list closed: a bare
1240
1329
  * record outside the frozen control vocabulary remains a protocol error.
1241
1330
  */
1331
+ const BARE_INFRASTRUCTURE_CONTROLS = new Set([
1332
+ service_wire_constants_generated_1.ServiceWireCommand.relocationReady,
1333
+ service_wire_constants_generated_1.ServiceWireCommand.relocationData,
1334
+ service_wire_constants_generated_1.ServiceWireCommand.replyRelay,
1335
+ service_wire_constants_generated_1.ServiceWireCommand.relocationCutover,
1336
+ service_wire_constants_generated_1.ServiceWireCommand.relocationPrepare,
1337
+ service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationSeal,
1338
+ service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationSealed,
1339
+ service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationRoute,
1340
+ service_wire_constants_generated_1.ServiceWireCommand.replyRelayAck,
1341
+ service_wire_constants_generated_1.ServiceWireCommand.relocationState,
1342
+ service_wire_constants_generated_1.ServiceWireCommand.relocationFailed
1343
+ ]);
1242
1344
  function isBareInfrastructureControl(command) {
1243
- return [
1244
- service_wire_constants_generated_1.ServiceWireCommand.relocationReady,
1245
- service_wire_constants_generated_1.ServiceWireCommand.relocationData,
1246
- service_wire_constants_generated_1.ServiceWireCommand.replyRelay,
1247
- service_wire_constants_generated_1.ServiceWireCommand.relocationCutover,
1248
- service_wire_constants_generated_1.ServiceWireCommand.relocationPrepare,
1249
- service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationSeal,
1250
- service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationSealed,
1251
- service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationRoute,
1252
- service_wire_constants_generated_1.ServiceWireCommand.replyRelayAck,
1253
- service_wire_constants_generated_1.ServiceWireCommand.relocationState,
1254
- service_wire_constants_generated_1.ServiceWireCommand.relocationFailed
1255
- ].includes(command);
1345
+ return BARE_INFRASTRUCTURE_CONTROLS.has(command);
1346
+ }
1347
+ function isApplicationEnvelopeCommand(command) {
1348
+ return (command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeSend ||
1349
+ command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest ||
1350
+ command === service_wire_m6a_codec_1.M6aServiceWireCommand.channelSend ||
1351
+ command === service_wire_m6a_codec_1.M6aServiceWireCommand.channelRequest);
1256
1352
  }
1257
1353
  function protocolCommand(parts) {
1258
1354
  if (parts.length === 0)
@@ -22,14 +22,25 @@ export declare class ServiceLivenessConnection {
22
22
  tryGetProbe(nowMs: number, allocateProbeId: () => bigint): bigint | undefined;
23
23
  acknowledge(probeId: bigint, nowMs: number): boolean;
24
24
  }
25
- /** Uses monotonic milliseconds and never treats application traffic as a probe ACK. */
26
25
  export declare class ServiceLivenessRegistry {
27
26
  private readonly probeIntervalMs;
28
27
  private readonly peerTimeoutMs;
29
28
  private readonly peers;
30
29
  private nextProbeId;
30
+ /**
31
+ * The earliest probe or timeout among admitted peers. Received traffic only
32
+ * extends a peer's deadline, so this stays a lower bound between ticks.
33
+ */
34
+ private nextDueMs;
35
+ private admissionActivityMs?;
31
36
  constructor(probeIntervalMs?: number, peerTimeoutMs?: number);
32
37
  admit(nodeRoutingId: string, connectionId: string | bigint, nowMs: number): ServiceLivenessConnection;
38
+ /** When the next tick has probe or timeout work (spec 08 §4.2 management deadline). */
39
+ nextDeadlineMs(): number;
40
+ /** Pending admission shares the existing liveness management cadence (MeshNode §7.1). */
41
+ setAdmissionPending(pending: boolean, nowMs: number): void;
42
+ private nextAdmissionDeadlineMs;
43
+ tickAdmission(nowMs: number): boolean;
33
44
  recordReceived(connection: ServiceLivenessConnection, nowMs: number): void;
34
45
  disconnect(nodeRoutingId: string, connectionId: string | bigint): boolean;
35
46
  acknowledge(nodeRoutingId: string, connectionId: string | bigint, probeId: bigint, nowMs: number): boolean;