@zlink-systems/framework 0.30.3 → 0.32.0

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 (398) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Actors/ZLinkActor.d.ts +2 -0
  3. package/dist/contracts/Actors/ZLinkSessionBindingIdentity.d.ts +6 -0
  4. package/dist/contracts/Actors/ZLinkSessionBindingIdentity.js +2 -0
  5. package/dist/contracts/Actors/index.d.ts +1 -0
  6. package/dist/contracts/Actors/index.js +1 -0
  7. package/dist/contracts/Common/CoreTypes.d.ts +1 -0
  8. package/dist/contracts/Common/HandlerMessageType.d.ts +8 -0
  9. package/dist/contracts/Common/HandlerMessageType.js +41 -0
  10. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +1 -1
  11. package/dist/contracts/Common/ZLinkEncodedPayload.js +12 -20
  12. package/dist/contracts/Common/ZLinkMessage.js +11 -7
  13. package/dist/contracts/Common/encoded-payload-storage.d.ts +0 -2
  14. package/dist/contracts/Common/encoded-payload-storage.js +4 -16
  15. package/dist/contracts/Common/index.d.ts +1 -1
  16. package/dist/contracts/Common/payload-slab.d.ts +4 -0
  17. package/dist/contracts/Common/payload-slab.js +30 -0
  18. package/dist/contracts/Configuration/RegistrationBuilders.js +15 -9
  19. package/dist/contracts/Configuration/RegistrationTypes.d.ts +19 -0
  20. package/dist/contracts/Handlers/Contexts.d.ts +1 -0
  21. package/dist/contracts/Locations/Authority.d.ts +2 -0
  22. package/dist/internal.d.ts +9 -0
  23. package/dist/internal.js +23 -1
  24. package/dist/nest-integration.d.ts +1 -0
  25. package/dist/nest-integration.js +3 -1
  26. package/dist/runtime/actors/actor-client.d.ts +6 -2
  27. package/dist/runtime/actors/actor-client.js +120 -82
  28. package/dist/runtime/actors/actor-context.js +16 -5
  29. package/dist/runtime/actors/actor-execution-context.js +2 -2
  30. package/dist/runtime/actors/actor-handoff.d.ts +12 -1
  31. package/dist/runtime/actors/actor-handoff.js +79 -34
  32. package/dist/runtime/actors/actor-join-deferred-scope.js +6 -6
  33. package/dist/runtime/actors/actor-local-native-join.d.ts +2 -2
  34. package/dist/runtime/actors/actor-local-native-join.js +19 -17
  35. package/dist/runtime/actors/actor-mailbox.d.ts +1 -1
  36. package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
  37. package/dist/runtime/actors/actor-remote-joiner.js +4 -4
  38. package/dist/runtime/actors/actor-routed-join-transport.d.ts +9 -3
  39. package/dist/runtime/actors/actor-routed-json-request.d.ts +3 -0
  40. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -2
  41. package/dist/runtime/actors/actor-runtime-state.d.ts +1 -1
  42. package/dist/runtime/actors/spot-actor-dispatch.d.ts +9 -5
  43. package/dist/runtime/actors/spot-actor-dispatch.js +60 -38
  44. package/dist/runtime/admission.d.ts +6 -4
  45. package/dist/runtime/admission.js +21 -10
  46. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +1 -0
  47. package/dist/runtime/application-jobs/application-ingress-record-owner.js +3 -0
  48. package/dist/runtime/backend/contracts/index.d.ts +26 -10
  49. package/dist/runtime/backend/mesh-completion-table.d.ts +7 -1
  50. package/dist/runtime/backend/mesh-completion-table.js +84 -20
  51. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +19 -6
  52. package/dist/runtime/backend/mesh-dispatch-pump.js +246 -147
  53. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -2
  54. package/dist/runtime/backend/node/node-backend-adapter-support.js +27 -19
  55. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +5 -2
  56. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +70 -13
  57. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +2 -2
  58. package/dist/runtime/backend/node/node-event-loop-poller.js +4 -3
  59. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +5 -1
  60. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +7 -2
  61. package/dist/runtime/backend/node/node-raw-binding-port.js +99 -63
  62. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +34 -16
  63. package/dist/runtime/backend/node/node-raw-mesh-backend.js +210 -106
  64. package/dist/runtime/backend/node/node-socket-backend-adapter.js +20 -6
  65. package/dist/runtime/backend/raw-binding-port.d.ts +6 -3
  66. package/dist/runtime/channels/channel-clients.js +3 -3
  67. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +11 -7
  68. package/dist/runtime/channels/channel-dispatch-pipeline.js +40 -22
  69. package/dist/runtime/channels/channel-dispatch-services.d.ts +3 -1
  70. package/dist/runtime/channels/channel-dispatch-services.js +7 -6
  71. package/dist/runtime/channels/channel-dispatchers.d.ts +13 -6
  72. package/dist/runtime/channels/channel-dispatchers.js +57 -36
  73. package/dist/runtime/channels/channel-envelope.d.ts +2 -2
  74. package/dist/runtime/channels/channel-envelope.js +609 -83
  75. package/dist/runtime/channels/channel-multipart.d.ts +1 -0
  76. package/dist/runtime/channels/channel-multipart.js +10 -6
  77. package/dist/runtime/channels/channel-outbound-operations.d.ts +6 -9
  78. package/dist/runtime/channels/channel-outbound-operations.js +107 -105
  79. package/dist/runtime/channels/channel-receive-loops.d.ts +9 -7
  80. package/dist/runtime/channels/channel-receive-loops.js +126 -90
  81. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +23 -6
  82. package/dist/runtime/channels/channel-runtime-lifecycle.js +47 -38
  83. package/dist/runtime/channels/channel-runtime-manager.d.ts +13 -6
  84. package/dist/runtime/channels/channel-runtime-manager.js +32 -14
  85. package/dist/runtime/channels/channel-socket-registry.d.ts +28 -4
  86. package/dist/runtime/channels/channel-socket-registry.js +9 -1
  87. package/dist/runtime/channels/channel-transports.d.ts +23 -16
  88. package/dist/runtime/channels/channel-transports.js +139 -119
  89. package/dist/runtime/channels/dispatch-error-reporter.d.ts +4 -4
  90. package/dist/runtime/channels/dispatch-error-reporter.js +5 -5
  91. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  92. package/dist/runtime/channels/local-spot-route-transport.d.ts +5 -2
  93. package/dist/runtime/channels/local-spot-route-transport.js +15 -18
  94. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +6 -3
  95. package/dist/runtime/channels/router-socket-spot-route-transport.js +33 -19
  96. package/dist/runtime/channels/source-spot-router.d.ts +6 -3
  97. package/dist/runtime/channels/source-spot-router.js +34 -23
  98. package/dist/runtime/channels/spot-node-route-transport.d.ts +6 -3
  99. package/dist/runtime/channels/spot-node-route-transport.js +23 -17
  100. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +6 -3
  101. package/dist/runtime/channels/spot-route-bridge-transport.js +38 -24
  102. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +8 -4
  103. package/dist/runtime/channels/spot-route-dispatch-strategy.js +36 -23
  104. package/dist/runtime/diagnostics/dispatch-error-details.js +9 -3
  105. package/dist/runtime/diagnostics/message-flow-bootstrap.d.ts +1 -0
  106. package/dist/runtime/diagnostics/message-flow-bootstrap.js +8 -0
  107. package/dist/runtime/diagnostics/message-flow-delivery.d.ts +47 -0
  108. package/dist/runtime/diagnostics/message-flow-delivery.js +149 -0
  109. package/dist/runtime/diagnostics/message-flow-record.d.ts +50 -0
  110. package/dist/runtime/diagnostics/message-flow-record.js +228 -0
  111. package/dist/runtime/diagnostics/message-flow-worker.d.ts +1 -0
  112. package/dist/runtime/diagnostics/message-flow-worker.js +118 -0
  113. package/dist/runtime/diagnostics/message-flow.d.ts +7 -19
  114. package/dist/runtime/diagnostics/message-flow.js +42 -290
  115. package/dist/runtime/diagnostics/runtime-metrics.d.ts +4 -3
  116. package/dist/runtime/diagnostics/runtime-metrics.js +8 -4
  117. package/dist/runtime/execution/index.d.ts +1 -0
  118. package/dist/runtime/execution/index.js +6 -3
  119. package/dist/runtime/execution/serial-execution-queue.d.ts +26 -13
  120. package/dist/runtime/execution/serial-execution-queue.js +75 -71
  121. package/dist/runtime/foundation/durable-service-request.d.ts +12 -3
  122. package/dist/runtime/foundation/durable-service-request.js +158 -73
  123. package/dist/runtime/foundation/operation-registry.d.ts +33 -3
  124. package/dist/runtime/foundation/operation-registry.js +272 -33
  125. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +62 -23
  126. package/dist/runtime/foundation/raw-service-mesh-runtime.js +373 -194
  127. package/dist/runtime/foundation/request-runtime.d.ts +17 -0
  128. package/dist/runtime/foundation/request-runtime.js +163 -0
  129. package/dist/runtime/foundation/service-discovery-registry.d.ts +4 -0
  130. package/dist/runtime/foundation/service-discovery-registry.js +6 -0
  131. package/dist/runtime/foundation/service-liveness-registry.d.ts +1 -1
  132. package/dist/runtime/foundation/service-mailbox.d.ts +4 -2
  133. package/dist/runtime/foundation/service-mailbox.js +4 -1
  134. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -2
  135. package/dist/runtime/foundation/service-relocation-object-owner.js +12 -5
  136. package/dist/runtime/foundation/service-runtime-contracts.d.ts +7 -2
  137. package/dist/runtime/foundation/service-stateful-registry.d.ts +6 -2
  138. package/dist/runtime/foundation/service-stateful-registry.js +38 -17
  139. package/dist/runtime/foundation/service-stateful-runtime.d.ts +91 -26
  140. package/dist/runtime/foundation/service-stateful-runtime.js +245 -120
  141. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +3 -0
  142. package/dist/runtime/foundation/service-stateful-wire-codec.js +15 -0
  143. package/dist/runtime/foundation/service-topology-registry.d.ts +2 -0
  144. package/dist/runtime/foundation/service-topology-registry.js +13 -3
  145. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  146. package/dist/runtime/foundation/service-wire-constants.generated.js +12 -0
  147. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +5 -1
  148. package/dist/runtime/foundation/service-wire-m6a-codec.js +50 -15
  149. package/dist/runtime/host/actor-packet-relay.d.ts +5 -6
  150. package/dist/runtime/host/actor-packet-relay.js +58 -57
  151. package/dist/runtime/host/actor-placement-coordinator.d.ts +1 -1
  152. package/dist/runtime/host/actor-runtime-options-factory.d.ts +2 -0
  153. package/dist/runtime/host/actor-runtime-options-factory.js +3 -2
  154. package/dist/runtime/host/actor-transfer-runtime.d.ts +3 -3
  155. package/dist/runtime/host/application-job-queue.d.ts +7 -5
  156. package/dist/runtime/host/application-job-queue.js +33 -21
  157. package/dist/runtime/host/bound-session-relay.js +0 -1
  158. package/dist/runtime/host/channel-runtime-options-factory.d.ts +2 -0
  159. package/dist/runtime/host/channel-runtime-options-factory.js +1 -0
  160. package/dist/runtime/host/entry-actor-runtime.d.ts +5 -2
  161. package/dist/runtime/host/entry-actor-runtime.js +2 -2
  162. package/dist/runtime/host/index.d.ts +106 -37
  163. package/dist/runtime/host/index.js +303 -151
  164. package/dist/runtime/host/location-runtime-owner.d.ts +2 -2
  165. package/dist/runtime/host/location-runtime-owner.js +1 -1
  166. package/dist/runtime/host/service-relocation-host-runtime.d.ts +195 -45
  167. package/dist/runtime/host/service-relocation-host-runtime.js +257 -144
  168. package/dist/runtime/host/spot-address-transport.d.ts +3 -0
  169. package/dist/runtime/host/spot-address-transport.js +73 -76
  170. package/dist/runtime/host/spot-runtime-options-factory.js +2 -0
  171. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +3 -1
  172. package/dist/runtime/host/user-spot-creation-coordinator.js +49 -21
  173. package/dist/runtime/internal-observation.d.ts +1 -0
  174. package/dist/runtime/internal-observation.js +5 -0
  175. package/dist/runtime/locations/actor-location-claims.d.ts +1 -1
  176. package/dist/runtime/locations/actor-location-claims.js +15 -6
  177. package/dist/runtime/locations/auto-connect-loop.d.ts +0 -1
  178. package/dist/runtime/locations/auto-connect-loop.js +25 -19
  179. package/dist/runtime/locations/auto-connect-planner.js +2 -5
  180. package/dist/runtime/locations/auto-connect-reconciler.d.ts +1 -0
  181. package/dist/runtime/locations/auto-connect-reconciler.js +35 -23
  182. package/dist/runtime/locations/in-memory-authority-store.d.ts +1 -0
  183. package/dist/runtime/locations/in-memory-authority-store.js +15 -5
  184. package/dist/runtime/locations/in-memory-location-store.d.ts +0 -2
  185. package/dist/runtime/locations/in-memory-location-store.js +1 -38
  186. package/dist/runtime/locations/lifecycle.d.ts +1 -1
  187. package/dist/runtime/locations/lifecycle.js +2 -2
  188. package/dist/runtime/locations/location-store-repository.d.ts +0 -1
  189. package/dist/runtime/locations/location-store-repository.js +163 -246
  190. package/dist/runtime/locations/resolvers.d.ts +8 -1
  191. package/dist/runtime/locations/resolvers.js +16 -2
  192. package/dist/runtime/locations/runtime.d.ts +3 -3
  193. package/dist/runtime/locations/runtime.js +12 -16
  194. package/dist/runtime/messaging/creation-payload-codec.js +8 -7
  195. package/dist/runtime/messaging/framework-json-v1.d.ts +1 -1
  196. package/dist/runtime/messaging/framework-json-v1.js +6 -2
  197. package/dist/runtime/messaging/payload-codec.js +21 -35
  198. package/dist/runtime/messaging/request-deadline.d.ts +4 -2
  199. package/dist/runtime/messaging/request-deadline.js +40 -25
  200. package/dist/runtime/messaging/request-result.d.ts +14 -1
  201. package/dist/runtime/messaging/request-result.js +74 -13
  202. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +4 -0
  203. package/dist/runtime/protocol/service_wire_codec.generated.js +17 -7
  204. package/dist/runtime/spots/index.d.ts +28 -7
  205. package/dist/runtime/spots/index.js +31 -6
  206. package/dist/runtime/spots/spot-activation-registry.d.ts +3 -2
  207. package/dist/runtime/spots/spot-activation-registry.js +13 -8
  208. package/dist/runtime/spots/spot-activation-state.d.ts +2 -0
  209. package/dist/runtime/spots/spot-activation-state.js +1 -0
  210. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +9 -4
  211. package/dist/runtime/spots/spot-actor-admission-coordinator.js +33 -12
  212. package/dist/runtime/spots/spot-actor-ingress-admission.d.ts +40 -0
  213. package/dist/runtime/spots/spot-actor-ingress-admission.js +78 -0
  214. package/dist/runtime/spots/spot-actor-membership.js +3 -3
  215. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +16 -43
  216. package/dist/runtime/spots/spot-actor-packet-dispatch.js +56 -113
  217. package/dist/runtime/spots/spot-actor-packet-drain.d.ts +1 -0
  218. package/dist/runtime/spots/spot-actor-packet-drain.js +12 -5
  219. package/dist/runtime/spots/spot-entry-activation.d.ts +4 -3
  220. package/dist/runtime/spots/spot-entry-activation.js +7 -12
  221. package/dist/runtime/spots/spot-handler-registry.d.ts +5 -1
  222. package/dist/runtime/spots/spot-handler-registry.js +31 -15
  223. package/dist/runtime/spots/spot-manager-public.js +3 -2
  224. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +11 -6
  225. package/dist/runtime/spots/spot-node-runtime-manager.js +6 -1
  226. package/dist/runtime/spots/spot-outbound.d.ts +8 -2
  227. package/dist/runtime/spots/spot-outbound.js +5 -5
  228. package/dist/runtime/spots/spot-route-packet-dispatch.js +13 -8
  229. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +3 -3
  230. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +9 -5
  231. package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -2
  232. package/dist/runtime/spots/spot-serial-executor.d.ts +2 -1
  233. package/dist/runtime/spots/spot-serial-turn-executor.js +20 -26
  234. package/dist/runtime/spots/spot-subscription-dispatch.js +5 -2
  235. package/dist/runtime/spots/spot-timer.d.ts +1 -1
  236. package/dist/runtime/streams/actor-session-binding-registry.d.ts +11 -3
  237. package/dist/runtime/streams/actor-session-binding-registry.js +28 -0
  238. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -2
  239. package/dist/runtime/streams/bound-actor-relay-sender.js +3 -4
  240. package/dist/runtime/streams/bound-session-service.js +6 -7
  241. package/dist/runtime/streams/index.d.ts +3 -3
  242. package/dist/runtime/streams/index.js +22 -2
  243. package/dist/runtime/streams/managed-stream.js +2 -1
  244. package/dist/runtime/streams/session-calls.d.ts +1 -1
  245. package/dist/runtime/streams/session-calls.js +3 -9
  246. package/dist/runtime/streams/session-context.d.ts +2 -2
  247. package/dist/runtime/streams/session-context.js +2 -2
  248. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -0
  249. package/dist/runtime/streams/stream-session-runtime.js +64 -33
  250. package/package.json +3 -3
  251. package/src/contracts/Actors/ZLinkActor.ts +6 -0
  252. package/src/contracts/Actors/ZLinkSessionBindingIdentity.ts +7 -0
  253. package/src/contracts/Actors/index.ts +1 -0
  254. package/src/contracts/Common/CoreTypes.ts +1 -0
  255. package/src/contracts/Common/HandlerMessageType.ts +50 -0
  256. package/src/contracts/Common/ZLinkEncodedPayload.ts +13 -25
  257. package/src/contracts/Common/ZLinkMessage.ts +11 -7
  258. package/src/contracts/Common/encoded-payload-storage.ts +4 -16
  259. package/src/contracts/Common/index.ts +1 -1
  260. package/src/contracts/Common/payload-slab.ts +29 -0
  261. package/src/contracts/Configuration/RegistrationBuilders.ts +29 -15
  262. package/src/contracts/Configuration/RegistrationTypes.ts +19 -0
  263. package/src/contracts/Handlers/Contexts.ts +1 -0
  264. package/src/contracts/Locations/Authority.ts +7 -1
  265. package/src/internal.ts +17 -0
  266. package/src/nest-integration.ts +1 -0
  267. package/src/runtime/actors/actor-client.ts +257 -163
  268. package/src/runtime/actors/actor-context.ts +26 -14
  269. package/src/runtime/actors/actor-execution-context.ts +2 -2
  270. package/src/runtime/actors/actor-handoff.ts +86 -51
  271. package/src/runtime/actors/actor-join-deferred-scope.ts +6 -6
  272. package/src/runtime/actors/actor-local-native-join.ts +38 -17
  273. package/src/runtime/actors/actor-mailbox.ts +1 -1
  274. package/src/runtime/actors/actor-remote-joiner.ts +8 -4
  275. package/src/runtime/actors/actor-routed-join-transport.ts +13 -5
  276. package/src/runtime/actors/actor-routed-json-request.ts +3 -0
  277. package/src/runtime/actors/actor-runtime-contracts.ts +4 -2
  278. package/src/runtime/actors/actor-runtime-state.ts +1 -1
  279. package/src/runtime/actors/spot-actor-dispatch.ts +70 -68
  280. package/src/runtime/admission.ts +42 -15
  281. package/src/runtime/application-jobs/application-ingress-record-owner.ts +4 -0
  282. package/src/runtime/backend/contracts/index.ts +77 -10
  283. package/src/runtime/backend/mesh-completion-table.ts +106 -15
  284. package/src/runtime/backend/mesh-dispatch-pump.ts +294 -146
  285. package/src/runtime/backend/node/node-backend-adapter-support.ts +42 -32
  286. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +91 -34
  287. package/src/runtime/backend/node/node-event-loop-poller.ts +14 -5
  288. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +5 -1
  289. package/src/runtime/backend/node/node-raw-binding-port.ts +180 -69
  290. package/src/runtime/backend/node/node-raw-mesh-backend.ts +386 -157
  291. package/src/runtime/backend/node/node-socket-backend-adapter.ts +56 -11
  292. package/src/runtime/backend/raw-binding-port.ts +13 -5
  293. package/src/runtime/channels/channel-clients.ts +26 -11
  294. package/src/runtime/channels/channel-dispatch-pipeline.ts +77 -65
  295. package/src/runtime/channels/channel-dispatch-services.ts +7 -12
  296. package/src/runtime/channels/channel-dispatchers.ts +93 -39
  297. package/src/runtime/channels/channel-envelope.ts +680 -144
  298. package/src/runtime/channels/channel-multipart.ts +17 -13
  299. package/src/runtime/channels/channel-outbound-operations.ts +204 -178
  300. package/src/runtime/channels/channel-receive-loops.ts +160 -107
  301. package/src/runtime/channels/channel-runtime-lifecycle.ts +64 -59
  302. package/src/runtime/channels/channel-runtime-manager.ts +74 -27
  303. package/src/runtime/channels/channel-socket-registry.ts +20 -5
  304. package/src/runtime/channels/channel-transports.ts +414 -287
  305. package/src/runtime/channels/dispatch-error-reporter.ts +4 -9
  306. package/src/runtime/channels/local-spot-route-transport.ts +27 -29
  307. package/src/runtime/channels/router-socket-spot-route-transport.ts +63 -32
  308. package/src/runtime/channels/source-spot-router.ts +75 -38
  309. package/src/runtime/channels/spot-node-route-transport.ts +67 -37
  310. package/src/runtime/channels/spot-route-bridge-transport.ts +62 -30
  311. package/src/runtime/channels/spot-route-dispatch-strategy.ts +105 -34
  312. package/src/runtime/diagnostics/dispatch-error-details.ts +10 -2
  313. package/src/runtime/diagnostics/message-flow-bootstrap.ts +6 -0
  314. package/src/runtime/diagnostics/message-flow-delivery.ts +171 -0
  315. package/src/runtime/diagnostics/message-flow-record.ts +295 -0
  316. package/src/runtime/diagnostics/message-flow-worker.ts +146 -0
  317. package/src/runtime/diagnostics/message-flow.ts +49 -362
  318. package/src/runtime/diagnostics/runtime-metrics.ts +10 -4
  319. package/src/runtime/execution/index.ts +6 -0
  320. package/src/runtime/execution/serial-execution-queue.ts +94 -96
  321. package/src/runtime/foundation/durable-service-request.ts +212 -89
  322. package/src/runtime/foundation/operation-registry.ts +287 -38
  323. package/src/runtime/foundation/raw-service-mesh-runtime.ts +617 -292
  324. package/src/runtime/foundation/request-runtime.ts +227 -0
  325. package/src/runtime/foundation/service-discovery-registry.ts +7 -0
  326. package/src/runtime/foundation/service-liveness-registry.ts +1 -1
  327. package/src/runtime/foundation/service-mailbox.ts +7 -2
  328. package/src/runtime/foundation/service-relocation-object-owner.ts +21 -6
  329. package/src/runtime/foundation/service-runtime-contracts.ts +12 -2
  330. package/src/runtime/foundation/service-stateful-registry.ts +52 -19
  331. package/src/runtime/foundation/service-stateful-runtime.ts +365 -198
  332. package/src/runtime/foundation/service-stateful-wire-codec.ts +18 -0
  333. package/src/runtime/foundation/service-topology-registry.ts +21 -3
  334. package/src/runtime/foundation/service-wire-constants.generated.ts +10 -0
  335. package/src/runtime/foundation/service-wire-m6a-codec.ts +69 -17
  336. package/src/runtime/host/actor-packet-relay.ts +160 -156
  337. package/src/runtime/host/actor-placement-coordinator.ts +1 -1
  338. package/src/runtime/host/actor-runtime-options-factory.ts +7 -2
  339. package/src/runtime/host/actor-transfer-runtime.ts +3 -3
  340. package/src/runtime/host/application-job-queue.ts +56 -27
  341. package/src/runtime/host/bound-session-relay.ts +0 -1
  342. package/src/runtime/host/channel-runtime-options-factory.ts +3 -0
  343. package/src/runtime/host/entry-actor-runtime.ts +14 -6
  344. package/src/runtime/host/index.ts +388 -113
  345. package/src/runtime/host/location-runtime-owner.ts +3 -3
  346. package/src/runtime/host/service-relocation-host-runtime.ts +380 -252
  347. package/src/runtime/host/spot-address-transport.ts +110 -95
  348. package/src/runtime/host/spot-runtime-options-factory.ts +3 -0
  349. package/src/runtime/host/user-spot-creation-coordinator.ts +69 -22
  350. package/src/runtime/internal-observation.ts +2 -0
  351. package/src/runtime/locations/actor-location-claims.ts +42 -16
  352. package/src/runtime/locations/auto-connect-loop.ts +24 -16
  353. package/src/runtime/locations/auto-connect-planner.ts +2 -5
  354. package/src/runtime/locations/auto-connect-reconciler.ts +37 -24
  355. package/src/runtime/locations/in-memory-authority-store.ts +27 -7
  356. package/src/runtime/locations/in-memory-location-store.ts +1 -74
  357. package/src/runtime/locations/lifecycle.ts +4 -2
  358. package/src/runtime/locations/location-store-repository.ts +228 -308
  359. package/src/runtime/locations/resolvers.ts +20 -8
  360. package/src/runtime/locations/runtime.ts +16 -28
  361. package/src/runtime/messaging/creation-payload-codec.ts +12 -10
  362. package/src/runtime/messaging/framework-json-v1.ts +10 -1
  363. package/src/runtime/messaging/payload-codec.ts +50 -75
  364. package/src/runtime/messaging/request-deadline.ts +47 -39
  365. package/src/runtime/messaging/request-result.ts +88 -17
  366. package/src/runtime/protocol/service_wire_codec.generated.ts +18 -8
  367. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
  368. package/src/runtime/spots/index.ts +57 -10
  369. package/src/runtime/spots/spot-activation-registry.ts +12 -8
  370. package/src/runtime/spots/spot-activation-state.ts +2 -0
  371. package/src/runtime/spots/spot-actor-admission-coordinator.ts +62 -37
  372. package/src/runtime/spots/spot-actor-ingress-admission.ts +157 -0
  373. package/src/runtime/spots/spot-actor-membership.ts +8 -5
  374. package/src/runtime/spots/spot-actor-packet-dispatch.ts +122 -206
  375. package/src/runtime/spots/spot-actor-packet-drain.ts +21 -6
  376. package/src/runtime/spots/spot-entry-activation.ts +25 -35
  377. package/src/runtime/spots/spot-handler-registry.ts +72 -15
  378. package/src/runtime/spots/spot-manager-public.ts +4 -2
  379. package/src/runtime/spots/spot-node-runtime-manager.ts +16 -7
  380. package/src/runtime/spots/spot-outbound.ts +26 -10
  381. package/src/runtime/spots/spot-route-packet-dispatch.ts +18 -8
  382. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +14 -8
  383. package/src/runtime/spots/spot-runtime-ports.ts +5 -2
  384. package/src/runtime/spots/spot-serial-executor.ts +1 -1
  385. package/src/runtime/spots/spot-serial-turn-executor.ts +25 -40
  386. package/src/runtime/spots/spot-subscription-dispatch.ts +9 -2
  387. package/src/runtime/spots/spot-timer.ts +1 -1
  388. package/src/runtime/streams/actor-session-binding-registry.ts +46 -3
  389. package/src/runtime/streams/bound-actor-relay-sender.ts +16 -5
  390. package/src/runtime/streams/bound-session-service.ts +10 -7
  391. package/src/runtime/streams/index.ts +30 -4
  392. package/src/runtime/streams/managed-stream.ts +2 -1
  393. package/src/runtime/streams/session-calls.ts +9 -14
  394. package/src/runtime/streams/session-context.ts +6 -11
  395. package/src/runtime/streams/stream-session-runtime.ts +79 -40
  396. package/dist/runtime/spots/spot-lifecycle-metrics.d.ts +0 -8
  397. package/dist/runtime/spots/spot-lifecycle-metrics.js +0 -17
  398. package/src/runtime/spots/spot-lifecycle-metrics.ts +0 -16
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RawServiceMeshRuntime = exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS = void 0;
4
+ const framework_errors_internal_1 = require("../framework-errors-internal");
5
+ const durable_service_request_1 = require("./durable-service-request");
6
+ const request_deadline_1 = require("../messaging/request-deadline");
7
+ const internal_observation_1 = require("../internal-observation");
4
8
  const node_os_1 = require("node:os");
5
9
  const application_ingress_record_owner_1 = require("../application-jobs/application-ingress-record-owner");
6
10
  const submission_result_1 = require("../messaging/submission-result");
11
+ const payload_slab_1 = require("../../contracts/Common/payload-slab");
7
12
  const runtime_values_1 = require("../backend/runtime-values");
8
13
  const service_wire_codec_generated_1 = require("../protocol/service_wire_codec.generated");
9
14
  const service_wire_binary_primitives_1 = require("./service-wire-binary-primitives");
@@ -32,9 +37,20 @@ const livenessCodec = (0, service_wire_codec_1.createServiceWireCodec)({
32
37
  * It owns protocol, admission, mailbox, request and liveness state.
33
38
  */
34
39
  class RawServiceMeshRuntime {
40
+ [internal_observation_1.inspectRuntime](nodeRoutingId) {
41
+ return Object.freeze({
42
+ pendingControlSends: this.controlSends.size,
43
+ selectedRouteGeneration: nodeRoutingId === undefined ? undefined : this.selectedRoutes.get(nodeRoutingId),
44
+ peerRouteObservers: this.peerRouteChanged.size,
45
+ peerConnectionIntentObservers: this.peerConnectionIntentRemoved.size,
46
+ expectedPeers: this.expectedPeers.size
47
+ });
48
+ }
35
49
  topology;
36
50
  mailbox;
37
51
  liveness;
52
+ requestOwner;
53
+ releaseOperations;
38
54
  operations;
39
55
  expectedPeers = new Map();
40
56
  endpointOnlyPeers = new Set();
@@ -45,6 +61,7 @@ class RawServiceMeshRuntime {
45
61
  * RID -> route generation. Only `observeSelectedRoutes` replaces it.
46
62
  */
47
63
  selectedRoutes = new Map();
64
+ connectionAttempts = [];
48
65
  bindingPort;
49
66
  applicationJobQueue;
50
67
  nodeMailboxOwner;
@@ -70,9 +87,16 @@ class RawServiceMeshRuntime {
70
87
  serviceIngressAccepts;
71
88
  closed = false;
72
89
  constructor(options) {
90
+ this.requestOwner = options.requests;
73
91
  this.onReceiveReady = options.onReceiveReady;
74
92
  this.infrastructureTaskRunner = options.infrastructureTaskRunner;
75
- this.operations = new operation_registry_1.OperationRegistry(undefined, options.onPendingOperationsChanged);
93
+ this.operations =
94
+ options.requests?.operations() ??
95
+ new operation_registry_1.OperationRegistry(undefined, options.onPendingOperationsChanged, (reason) => (0, request_deadline_1.requestTerminalError)('Request', reason));
96
+ this.releaseOperations =
97
+ options.requests === undefined
98
+ ? () => this.operations.close('Raw service runtime closed.')
99
+ : () => { };
76
100
  this.descriptor = options.descriptor;
77
101
  this.nodeMailboxOwner = `node:${options.descriptor.nodeRoutingId}`;
78
102
  this.topology = new service_topology_registry_1.ServiceTopologyRegistry(options.descriptor);
@@ -132,6 +156,7 @@ class RawServiceMeshRuntime {
132
156
  securityIdentity: expected.securityIdentity,
133
157
  lifecycleGeneration: expected.lifecycleGeneration
134
158
  }));
159
+ this.notifyPeerRouteChanged(expected.nodeRoutingId);
135
160
  }
136
161
  connectPeerByRoutingId(endpoint, nodeRoutingId, securityIdentity, lifecycleGeneration) {
137
162
  this.requireStarted().connectToRoutingId(nodeRoutingId, endpoint);
@@ -142,6 +167,7 @@ class RawServiceMeshRuntime {
142
167
  securityIdentity,
143
168
  lifecycleGeneration
144
169
  }));
170
+ this.notifyPeerRouteChanged(nodeRoutingId);
145
171
  }
146
172
  expectPeerByRoutingId(endpoint, nodeRoutingId, securityIdentity, lifecycleGeneration) {
147
173
  this.expectedPeers.set(nodeRoutingId, Object.assign(this.expectedPeers.get(nodeRoutingId) ?? {}, {
@@ -151,6 +177,7 @@ class RawServiceMeshRuntime {
151
177
  securityIdentity,
152
178
  lifecycleGeneration
153
179
  }));
180
+ this.notifyPeerRouteChanged(nodeRoutingId);
154
181
  }
155
182
  connectPeerEndpoint(endpoint) {
156
183
  this.requireStarted().connect(endpoint);
@@ -233,12 +260,23 @@ class RawServiceMeshRuntime {
233
260
  }
234
261
  observePeerRoute(nodeRoutingId) {
235
262
  const selected = this.selectedRoutes.get(nodeRoutingId);
236
- const admitted = this.topology.admittedPeer(nodeRoutingId)?.liveness?.connectionId;
263
+ const peer = this.topology.admittedPeer(nodeRoutingId);
264
+ const expected = this.expectedPeers.get(nodeRoutingId);
265
+ const admitted = peer?.liveness?.connectionId;
237
266
  return {
238
267
  generation: selected ?? (typeof admitted === 'bigint' ? admitted : undefined),
239
- ready: admitted !== undefined && (selected === undefined || admitted === selected)
268
+ ready: peer?.remoteAdmitReceived === true,
269
+ selected: selected !== undefined,
270
+ lifecycleGeneration: expected?.lifecycleGeneration ?? peer?.descriptor.lifecycleGeneration,
271
+ endpoint: expected?.endpoint ?? peer?.descriptor.advertisedEndpoint,
272
+ // The immutable socket snapshot is borrowed; only waiting admission filters it.
273
+ connectionAttempts: this.connectionAttempts
240
274
  };
241
275
  }
276
+ peerLifecycleGeneration(nodeRoutingId) {
277
+ return (this.expectedPeers.get(nodeRoutingId)?.lifecycleGeneration ??
278
+ this.topology.admittedPeer(nodeRoutingId)?.descriptor.lifecycleGeneration);
279
+ }
242
280
  async waitForPeerRoute(nodeRoutingId, lifecycleGeneration, deadlineUnixMs, signal) {
243
281
  const remaining = deadlineUnixMs - BigInt(Date.now());
244
282
  if (remaining <= 0n)
@@ -246,14 +284,14 @@ class RawServiceMeshRuntime {
246
284
  const pending = this.operations.register(Number(remaining));
247
285
  const check = () => {
248
286
  if (this.isPeerRouteReady(nodeRoutingId, lifecycleGeneration)) {
249
- this.operations.complete(pending.id, { terminalResult: runtime_values_1.RequestResult.Ok, failureCode: 0 });
287
+ pending.reply({ terminalResult: runtime_values_1.RequestResult.Ok, failureCode: 0 });
250
288
  }
251
289
  };
252
290
  const unsubscribe = this.observePeerRouteChanged((rid) => {
253
291
  if (rid === nodeRoutingId)
254
292
  check();
255
293
  });
256
- const abort = () => this.operations.fail(pending.id, signal?.reason);
294
+ const abort = () => pending.replyFailure(signal?.reason);
257
295
  signal?.addEventListener('abort', abort, { once: true });
258
296
  try {
259
297
  if (signal?.aborted === true)
@@ -299,27 +337,28 @@ class RawServiceMeshRuntime {
299
337
  return false;
300
338
  const key = controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
301
339
  if (!this.isPeerAnnouncementCurrent(nodeRoutingId, generation)) {
302
- this.controlSends.delete(key);
303
340
  return false;
304
341
  }
305
- const current = () => this.isPeerAnnouncementCurrent(nodeRoutingId, generation);
342
+ const current = () => this.isPeerAnnouncementCurrent(nodeRoutingId, generation) &&
343
+ this.peerAdmissionSealed?.() !== true;
306
344
  const existing = this.controlSends.get(key);
307
- const hello = existing?.current?.() === true
308
- ? existing.hello
309
- : (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor());
345
+ if (!current()) {
346
+ if (existing === undefined)
347
+ this.controlSends.set(key, { current });
348
+ return false;
349
+ }
350
+ const hello = existing?.hello ??
351
+ (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor());
310
352
  return this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [hello]), current, hello);
311
353
  }
312
354
  isPeerAnnouncementCurrent(nodeRoutingId, generation) {
313
- const admission = this.topology.routeAdmission(nodeRoutingId);
314
355
  return (this.selectedRoutes.get(nodeRoutingId) === generation &&
315
- !(admission?.connectionId === routeConnectionId(generation) &&
316
- admission.remoteAdmitReceived === true) &&
317
- this.peerAdmissionSealed?.() !== true);
356
+ !this.topology.hasRemoteAdmit(nodeRoutingId, routeConnectionId(generation)));
318
357
  }
319
358
  isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
320
359
  // Admission is bound to the observed selected route: the route observer
321
360
  // removes the peer when that route ends or is replaced.
322
- const peer = this.topology.admittedPeer(nodeRoutingId);
361
+ const peer = this.topology.readyPeer(nodeRoutingId);
323
362
  return (peer !== undefined &&
324
363
  (lifecycleGeneration === undefined ||
325
364
  peer.descriptor.lifecycleGeneration === lifecycleGeneration));
@@ -373,58 +412,78 @@ class RawServiceMeshRuntime {
373
412
  sendToNode(targetNodeRoutingId, payload) {
374
413
  return this.send(targetNodeRoutingId, [NODE_SEND_HEADER, this.applicationFrame(payload)]);
375
414
  }
376
- async sendToChannel(channelName, payload) {
415
+ sendToChannel(channelName, payload) {
377
416
  const selection = this.selectChannelTarget(channelName);
378
417
  if (selection.kind !== 'selected')
379
418
  return selection.submitResult;
380
419
  const selected = selection.peer;
381
420
  const applicationFrame = this.applicationFrame(payload);
382
- return (await this.send(selected.descriptor.nodeRoutingId, [
421
+ const submitted = this.send(selected.descriptor.nodeRoutingId, [
383
422
  (0, service_wire_m6a_codec_1.encodeChannelSendHeader)(channelName),
384
423
  applicationFrame
385
- ]))
386
- ? runtime_values_1.SubmitResult.Ok
387
- : runtime_values_1.SubmitResult.NotConnected;
424
+ ]);
425
+ return typeof submitted === 'boolean'
426
+ ? channelSendSubmitResult(submitted)
427
+ : submitted.then(channelSendSubmitResult);
388
428
  }
389
- requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted, observer, operationKind) {
390
- return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted, observer, operationKind);
429
+ requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted, observer, operationKind, requestOperation) {
430
+ return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted, observer, operationKind, requestOperation);
391
431
  }
392
- requestToChannel(channelName, payload, timeoutMs, onAdmitted, observer, operationKind) {
432
+ requestToChannel(channelName, payload, timeoutMs, onAdmitted, observer, operationKind, requestOperation) {
393
433
  const selection = this.selectChannelTarget(channelName);
394
434
  if (selection.kind !== 'selected') {
395
- const pending = this.registerRequest(timeoutMs, observer, operationKind);
396
- this.completeRequest(pending, selection.requestResult);
435
+ const pending = this.registerRequest(timeoutMs, observer, operationKind, requestOperation);
436
+ this.completeRequest(pending, selection.requestResult, requestOperation === undefined ? undefined : observer, operationKind);
397
437
  return pending;
398
438
  }
399
439
  return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName, onAdmitted, observer, operationKind);
400
440
  }
441
+ beginInfrastructureRequest(timeoutMs, signal, absoluteDeadlineMs = performance.now() + timeoutMs) {
442
+ const pending = this.operations.register(timeoutMs, 'registry', undefined, absoluteDeadlineMs);
443
+ pending.setSignal(signal);
444
+ return pending;
445
+ }
401
446
  /**
402
447
  * One pending entry per request: an observed request reports its terminal
403
448
  * to the caller's observer; any other request keeps the Promise contract.
404
449
  */
405
- registerRequest(timeoutMs, observer, operationKind) {
450
+ registerRequest(timeoutMs, observer, operationKind, requestOperation) {
451
+ if (requestOperation !== undefined) {
452
+ return requestOperation;
453
+ }
406
454
  return observer === undefined
407
455
  ? this.operations.register(timeoutMs)
408
- : { id: this.operations.registerObserved(timeoutMs, observer, operationKind) };
456
+ : this.observedRequest(this.operations.registerObserved(timeoutMs, observer, operationKind));
457
+ }
458
+ observedRequest(id) {
459
+ return this.operations.handle(id);
409
460
  }
410
461
  /**
411
462
  * An observed caller learns the operation id only when the request call
412
463
  * returns, so a terminal decided inside that call is delivered after it.
413
464
  */
414
- completeRequest(pending, result) {
415
- if (pending.promise === undefined)
416
- queueMicrotask(() => this.operations.complete(pending.id, result));
465
+ completeRequest(pending, result, observer, operationKind) {
466
+ if (observer !== undefined) {
467
+ queueMicrotask(() => observer.operationCompleted(pending.id, result, operationKind));
468
+ return;
469
+ }
470
+ if (pending.promise === undefined || pending.hasObserver())
471
+ queueMicrotask(() => pending.reply(result));
417
472
  else
418
- this.operations.complete(pending.id, result);
473
+ pending.reply(result);
419
474
  }
420
- failRequest(pending, error) {
475
+ failRequest(pending, error, observer, operationKind) {
476
+ if (observer !== undefined) {
477
+ queueMicrotask(() => observer.operationFailed(pending.id, error, operationKind));
478
+ return;
479
+ }
421
480
  if (pending.promise === undefined)
422
- queueMicrotask(() => this.operations.fail(pending.id, error));
481
+ queueMicrotask(() => pending.replyFailure(error));
423
482
  else
424
- this.operations.fail(pending.id, error);
483
+ pending.replyFailure(error);
425
484
  }
426
485
  selectChannelTarget(channelName) {
427
- const selected = this.topology.selectChannel(channelName, (peer) => this.isPeerRouteReady(peer.descriptor.nodeRoutingId));
486
+ const selected = this.topology.selectChannel(channelName);
428
487
  if (selected !== undefined)
429
488
  return { kind: 'selected', peer: selected };
430
489
  return this.topology.hasKnownChannelTarget(channelName)
@@ -465,9 +524,27 @@ class RawServiceMeshRuntime {
465
524
  return this.sendFailure(error);
466
525
  }
467
526
  }
468
- requestService(targetNodeRoutingId, parts, timeoutMs, onAdmitted) {
527
+ requestService(targetNodeRoutingId, parts, timeoutMs, onAdmitted, existing, receiver, onSubmitted) {
528
+ if (receiver !== undefined) {
529
+ try {
530
+ this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, (reply) => receiver.operationCompleted(existing?.id ?? 0n, reply, undefined), (error) => receiver.operationFailed(existing?.id ?? 0n, error, undefined), this.topology.admittedPeer(targetNodeRoutingId)?.liveness?.recordReceived, onAdmitted, existing);
531
+ }
532
+ catch (error) {
533
+ receiver.operationFailed(existing?.id ?? 0n, error, undefined);
534
+ }
535
+ return;
536
+ }
469
537
  const admission = this.topology.admittedPeer(targetNodeRoutingId)?.liveness;
470
- return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, admission?.recordReceived, onAdmitted);
538
+ try {
539
+ const reply = this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, (reply) => reply, (error) => {
540
+ throw error;
541
+ }, admission?.recordReceived, onAdmitted, existing);
542
+ onSubmitted?.();
543
+ return reply;
544
+ }
545
+ catch (error) {
546
+ return Promise.reject(error);
547
+ }
471
548
  }
472
549
  replyService(record, parts) {
473
550
  if (record.requestSequence === undefined) {
@@ -486,10 +563,8 @@ class RawServiceMeshRuntime {
486
563
  if (request.reply === undefined || request.correlation === undefined) {
487
564
  throw new TypeError('Reply requires a request mailbox record.');
488
565
  }
489
- request.reply([
490
- (0, service_wire_m6a_codec_1.encodeReplyHeader)(request.correlation, terminalResult, failureCode),
491
- ...(terminalResult === 0 ? [this.applicationFrame(payload)] : [])
492
- ]);
566
+ const header = (0, service_wire_m6a_codec_1.encodeReplyHeader)(request.correlation, terminalResult, failureCode);
567
+ request.reply(terminalResult === 0 ? [header, this.applicationFrame(payload)] : [header]);
493
568
  }
494
569
  async pumpOne(nowMs = performance.now(), observe) {
495
570
  const result = await this.receiveOne(nowMs, observe);
@@ -514,10 +589,35 @@ class RawServiceMeshRuntime {
514
589
  this.requireStarted().setReadableHandler(handler);
515
590
  }
516
591
  /** Returns whether a receive budget ended before no-data; idle ticks only maintain peers. */
517
- async pumpBatch(receiveReady = true, routeReady = false) {
518
- this.observeInfrastructureFailure();
592
+ pumpBatch(receiveReady = true, routeReady = false, connectReady = false) {
593
+ try {
594
+ this.observeInfrastructureFailure();
595
+ if (routeReady || connectReady) {
596
+ return this.receiveBatchAfterObservations(receiveReady, routeReady, connectReady);
597
+ }
598
+ return this.receiveBatch(receiveReady);
599
+ }
600
+ catch (error) {
601
+ return Promise.reject(error);
602
+ }
603
+ }
604
+ async receiveBatchAfterObservations(receiveReady, routeReady, connectReady) {
605
+ // Both facts are applied before admission observers run in this socket turn.
606
+ if (connectReady)
607
+ this.connectionAttempts = this.requireStarted().connectionAttemptsSnapshot();
519
608
  if (routeReady)
520
609
  await this.observeSelectedRoutes();
610
+ if (connectReady) {
611
+ for (const target of this.expectedPeers.keys())
612
+ this.notifyPeerRouteChanged(target);
613
+ for (const peer of this.topology.peers()) {
614
+ if (!this.expectedPeers.has(peer.descriptor.nodeRoutingId))
615
+ this.notifyPeerRouteChanged(peer.descriptor.nodeRoutingId);
616
+ }
617
+ }
618
+ return this.receiveBatch(receiveReady);
619
+ }
620
+ receiveBatch(receiveReady) {
521
621
  const startedAtMs = performance.now();
522
622
  let messages = 0;
523
623
  let bytes = 0;
@@ -527,29 +627,46 @@ class RawServiceMeshRuntime {
527
627
  const rotation = (this.receiveRotation ??= this.applicationJobQueue.createReceiveRotation(RAW_MESH_RECEIVE_RECORD_BUDGET, 'remote'));
528
628
  if (receiveReady)
529
629
  rotation.reserve();
530
- try {
531
- while (receiveReady && messages < RAW_MESH_RECEIVE_RECORD_BUDGET && !this.closed) {
532
- const received = this.receiveOne(performance.now(), observe, rotation);
533
- const result = received instanceof Promise ? await received : received;
534
- if (result === 'noData') {
535
- receiveReady = false;
536
- break;
630
+ // The same loop owns both immediate receives and a suspended receive's
631
+ // continuation; only the latter needs a Promise and retains this frame.
632
+ const drain = (received) => {
633
+ try {
634
+ while (received !== undefined ||
635
+ (receiveReady && messages < RAW_MESH_RECEIVE_RECORD_BUDGET && !this.closed)) {
636
+ if (received === undefined) {
637
+ const pending = this.receiveOne(performance.now(), observe, rotation);
638
+ if (pending instanceof Promise) {
639
+ return pending.then(drain, (error) => {
640
+ rotation.releaseUnused();
641
+ throw error;
642
+ });
643
+ }
644
+ received = pending;
645
+ }
646
+ if (received === 'noData') {
647
+ receiveReady = false;
648
+ break;
649
+ }
650
+ messages += 1;
651
+ received = undefined;
652
+ // Core owns the per-peer fair-queue cursor. The Framework limit bounds
653
+ // the entire round, so changing peers does not renew its byte/count budget.
654
+ if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
655
+ performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
656
+ break;
537
657
  }
538
- messages += 1;
539
- // Core owns the per-peer fair-queue cursor. The Framework limit bounds
540
- // the entire round, so changing peers does not renew its byte/count budget.
541
- if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
542
- performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
543
- break;
544
658
  }
545
- }
546
- finally {
659
+ catch (error) {
660
+ rotation.releaseUnused();
661
+ throw error;
662
+ }
547
663
  rotation.releaseUnused();
548
- }
549
- if (!this.closed) {
550
- this.tickLiveness();
551
- }
552
- return receiveReady && messages > 0;
664
+ if (!this.closed) {
665
+ this.tickLiveness();
666
+ }
667
+ return receiveReady && messages > 0;
668
+ };
669
+ return drain();
553
670
  }
554
671
  receiveOne(nowMs, observe, rotation) {
555
672
  const router = this.requireStarted();
@@ -558,32 +675,7 @@ class RawServiceMeshRuntime {
558
675
  this.receivePermit = undefined;
559
676
  permit ??= rotation?.take();
560
677
  if (permit === undefined && this.receiveAcquisition === undefined) {
561
- let resolveAcquisition;
562
- let rejectAcquisition;
563
- permit = this.applicationJobQueue.acquireOrResume((permit) => {
564
- this.receiveAcquisition = undefined;
565
- if (this.closed) {
566
- permit.releaseAfterInternalProcessing();
567
- permit.releaseStorage?.();
568
- }
569
- else {
570
- this.receivePermit = permit;
571
- this.onReceiveReady?.();
572
- }
573
- resolveAcquisition?.(permit);
574
- }, (error) => rejectAcquisition?.(error), this.applicationJobStop.signal, 'remote');
575
- if (permit === undefined) {
576
- const acquisition = new Promise((resolve, reject) => {
577
- resolveAcquisition = resolve;
578
- rejectAcquisition = reject;
579
- });
580
- this.receiveAcquisition = acquisition;
581
- acquisition.catch((error) => {
582
- this.receiveAcquisition = undefined;
583
- if (!this.applicationJobStop.signal.aborted)
584
- this.reportInfrastructureFailure(error);
585
- });
586
- }
678
+ permit = this.acquireReceivePermit();
587
679
  }
588
680
  if (permit === undefined)
589
681
  return 'noData';
@@ -616,20 +708,52 @@ class RawServiceMeshRuntime {
616
708
  throw error;
617
709
  }
618
710
  return result instanceof Promise
619
- ? result.then((value) => this.finishReceive(received, applicationJobOwner, observe, value), (error) => {
620
- applicationJobOwner.close();
621
- throw error;
622
- })
711
+ ? this.finishPendingReceive(result, received, applicationJobOwner, observe)
623
712
  : this.finishReceive(received, applicationJobOwner, observe, result);
624
713
  }
714
+ acquireReceivePermit() {
715
+ let resolveAcquisition;
716
+ let rejectAcquisition;
717
+ const permit = this.applicationJobQueue.acquireOrResume((permit) => {
718
+ this.receiveAcquisition = undefined;
719
+ if (this.closed) {
720
+ permit.releaseAfterInternalProcessing();
721
+ permit.releaseStorage?.();
722
+ }
723
+ else {
724
+ this.receivePermit = permit;
725
+ this.onReceiveReady?.();
726
+ }
727
+ resolveAcquisition?.(permit);
728
+ }, (error) => rejectAcquisition?.(error), this.applicationJobStop.signal, 'remote');
729
+ if (permit === undefined) {
730
+ const acquisition = new Promise((resolve, reject) => {
731
+ resolveAcquisition = resolve;
732
+ rejectAcquisition = reject;
733
+ });
734
+ this.receiveAcquisition = acquisition;
735
+ acquisition.catch((error) => {
736
+ this.receiveAcquisition = undefined;
737
+ if (!this.applicationJobStop.signal.aborted)
738
+ this.reportInfrastructureFailure(error);
739
+ });
740
+ }
741
+ return permit;
742
+ }
743
+ finishPendingReceive(result, received, owner, observe) {
744
+ return result.then((value) => this.finishReceive(received, owner, observe, value), (error) => {
745
+ owner.close();
746
+ throw error;
747
+ });
748
+ }
625
749
  finishReceive(received, owner, observe, result) {
626
750
  try {
627
751
  if (result === 'protocolError')
628
752
  this.reportProtocolError(received);
629
753
  if (observe !== undefined) {
630
754
  let bytes = 0;
631
- for (const part of received.parts)
632
- bytes += part.byteLength;
755
+ for (let index = 0; index < received.parts.length; index += 1)
756
+ bytes += received.parts[index].byteLength;
633
757
  observe(received.sourceRid, bytes);
634
758
  }
635
759
  return result;
@@ -651,28 +775,13 @@ class RawServiceMeshRuntime {
651
775
  replyGenericProtocolError(received) {
652
776
  if (received.requestSeq === undefined || received.parts.length === 0)
653
777
  return false;
654
- try {
655
- const header = (0, service_wire_m6a_codec_1.decodeHeader)(received.parts[0]);
656
- const correlation = header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest
657
- ? (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0])
658
- : header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.channelRequest
659
- ? (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0]).correlation
660
- : undefined;
661
- if (correlation === undefined)
662
- return false;
663
- const reply = [
664
- (0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.ProtocolError, service_wire_constants_generated_1.ServiceWireFrameworkErrorCode.requestProtocolError)
665
- ];
666
- if (received.reply === undefined)
667
- return false;
668
- received.reply(reply);
669
- return true;
670
- }
671
- catch (error) {
672
- if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
673
- return false;
674
- throw error;
675
- }
778
+ const correlation = (0, service_wire_constants_generated_1.recoverRequestCorrelation)(received.parts[0]);
779
+ if (correlation === undefined || received.reply === undefined)
780
+ return false;
781
+ received.reply([
782
+ (0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.ProtocolError, service_wire_constants_generated_1.ServiceWireFrameworkErrorCode.requestProtocolError)
783
+ ]);
784
+ return true;
676
785
  }
677
786
  processReceived(received, nowMs, applicationJobOwner) {
678
787
  const peer = this.topology.admittedPeer(received.sourceRid);
@@ -686,7 +795,7 @@ class RawServiceMeshRuntime {
686
795
  }
687
796
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello ||
688
797
  header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
689
- return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
798
+ return this.finishPendingProtocolReceive(this.processAdmission(received, header, nowMs));
690
799
  }
691
800
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.reject) {
692
801
  if (received.parts.length !== 1)
@@ -698,11 +807,11 @@ class RawServiceMeshRuntime {
698
807
  return 'dropped';
699
808
  this.liveness.recordReceived(peer.liveness, nowMs);
700
809
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.update) {
701
- return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
810
+ return this.finishPendingProtocolReceive(this.processAdmission(received, header, nowMs));
702
811
  }
703
812
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe ||
704
813
  header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck) {
705
- return this.processLiveness(received, nowMs).catch((error) => this.receiveProtocolFailure(error));
814
+ return this.finishPendingProtocolReceive(this.processLiveness(received, nowMs));
706
815
  }
707
816
  const stateful = this.serviceIngress !== undefined && this.serviceIngressAccepts?.(header.command) !== false
708
817
  ? this.serviceIngress({
@@ -720,7 +829,7 @@ class RawServiceMeshRuntime {
720
829
  })
721
830
  : undefined;
722
831
  if (stateful instanceof Promise)
723
- return stateful.then((result) => result ?? this.processApplicationReceived(received, header, applicationJobOwner), (error) => this.receiveProtocolFailure(error));
832
+ return this.finishPendingStatefulReceive(stateful, received, header, applicationJobOwner);
724
833
  if (stateful !== undefined)
725
834
  return stateful;
726
835
  return this.processApplicationReceived(received, header, applicationJobOwner);
@@ -731,6 +840,12 @@ class RawServiceMeshRuntime {
731
840
  return this.receiveProtocolFailure(error);
732
841
  }
733
842
  }
843
+ finishPendingProtocolReceive(pending) {
844
+ return pending.catch((error) => this.receiveProtocolFailure(error));
845
+ }
846
+ finishPendingStatefulReceive(pending, received, header, owner) {
847
+ return pending.then((result) => result ?? this.processApplicationReceived(received, header, owner), (error) => this.receiveProtocolFailure(error));
848
+ }
734
849
  receiveProtocolFailure(error) {
735
850
  if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
736
851
  return 'protocolError';
@@ -776,7 +891,7 @@ class RawServiceMeshRuntime {
776
891
  }
777
892
  else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
778
893
  this.controlSends.delete(helloKey);
779
- this.refreshAdmissionPending(nowMs);
894
+ this.progressPeerAdmission(nowMs);
780
895
  if (result === 'notRequired') {
781
896
  this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
782
897
  }
@@ -860,13 +975,16 @@ class RawServiceMeshRuntime {
860
975
  }
861
976
  const job = applicationJobOwner.acquire('application');
862
977
  return job instanceof Promise
863
- ? job.then((permit) => this.enqueueOrdinaryRecord(received, owner, correlation, permit))
978
+ ? this.enqueuePendingOrdinaryRecord(job, received, owner, correlation)
864
979
  : this.enqueueOrdinaryRecord(received, owner, correlation, job);
865
980
  }
866
981
  catch (error) {
867
982
  return this.receiveProtocolFailure(error);
868
983
  }
869
984
  }
985
+ enqueuePendingOrdinaryRecord(pending, received, owner, correlation) {
986
+ return pending.then((permit) => this.enqueueOrdinaryRecord(received, owner, correlation, permit));
987
+ }
870
988
  enqueueOrdinaryRecord(received, owner, correlation, applicationJob) {
871
989
  const accepted = this.mailbox.tryEnqueue({
872
990
  owner,
@@ -894,7 +1012,9 @@ class RawServiceMeshRuntime {
894
1012
  return 'dropped';
895
1013
  }
896
1014
  expireOperations(nowMs, turnDeadlineMs) {
897
- return this.operations.expire(nowMs, turnDeadlineMs);
1015
+ return this.requestOwner === undefined && nowMs >= this.operations.nextDeadlineMs()
1016
+ ? this.operations.expire(nowMs, turnDeadlineMs)
1017
+ : 0;
898
1018
  }
899
1019
  get pendingOperationCount() {
900
1020
  return this.operations.size;
@@ -908,26 +1028,33 @@ class RawServiceMeshRuntime {
908
1028
  * ADMIT, which keeps the existing announce cadence.
909
1029
  */
910
1030
  nextMaintenanceDeadlineMs(nowMs) {
911
- this.refreshAdmissionPending(nowMs);
912
- return Math.min(this.operations.nextDeadlineMs(), this.liveness.nextDeadlineMs());
1031
+ this.progressPeerAdmission(nowMs);
1032
+ return Math.min(this.requestOwner === undefined ? this.operations.nextDeadlineMs() : Infinity, this.liveness.nextDeadlineMs());
913
1033
  }
914
- refreshAdmissionPending(nowMs) {
1034
+ progressPeerAdmission(nowMs) {
915
1035
  let pending = false;
916
1036
  if (!this.closed && this.controlSends.size !== 0) {
917
1037
  for (const nodeRoutingId of this.selectedRoutes.keys()) {
918
- const exchange = this.controlSends.get(controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello));
1038
+ const key = controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
1039
+ const exchange = this.controlSends.get(key);
1040
+ // An unsent HELLO intent may resume after the host admission seal opens.
1041
+ // Only retransmission of submitted bytes waits for the management cadence.
919
1042
  if (exchange?.current?.() === true) {
1043
+ if (exchange.hello === undefined)
1044
+ this.announcePeer(nodeRoutingId);
920
1045
  pending = true;
921
- break;
922
1046
  }
923
1047
  }
924
1048
  }
925
1049
  this.liveness.setAdmissionPending(pending, nowMs);
926
1050
  }
927
1051
  tickLiveness(nowMs = performance.now()) {
1052
+ this.progressPeerAdmission(nowMs);
928
1053
  const admissionDue = this.liveness.tickAdmission(nowMs);
929
1054
  const result = this.liveness.tick(nowMs);
930
1055
  this.requireStarted();
1056
+ if (!admissionDue && result.probes.length === 0 && result.timedOutNodes.length === 0)
1057
+ return result;
931
1058
  if (admissionDue)
932
1059
  for (const nodeRoutingId of this.selectedRoutes.keys())
933
1060
  void this.announcePeer(nodeRoutingId);
@@ -940,13 +1067,29 @@ class RawServiceMeshRuntime {
940
1067
  ];
941
1068
  this.startControlSend(probe.nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe, () => this.submitControl(probe.nodeRoutingId, parts));
942
1069
  }
1070
+ const failures = [];
943
1071
  for (const nodeRoutingId of result.timedOutNodes) {
944
1072
  const peer = this.topology.peer(nodeRoutingId);
945
1073
  if (peer === undefined)
946
1074
  continue;
947
- this.requireStarted().disconnectRid(nodeRoutingId);
948
- this.removePeer(peer);
1075
+ try {
1076
+ this.removePeer(peer, () => {
1077
+ try {
1078
+ this.requireStarted().disconnectRid(nodeRoutingId);
1079
+ }
1080
+ catch (error) {
1081
+ failures.push(error);
1082
+ }
1083
+ });
1084
+ }
1085
+ catch (error) {
1086
+ failures.push(error);
1087
+ }
949
1088
  }
1089
+ if (failures.length === 1)
1090
+ throw failures[0];
1091
+ if (failures.length > 1)
1092
+ throw new AggregateError(failures, 'Liveness peer cleanup failed.');
950
1093
  return result;
951
1094
  }
952
1095
  /**
@@ -985,42 +1128,50 @@ class RawServiceMeshRuntime {
985
1128
  this.selectedRoutes = observed;
986
1129
  for (const nodeRoutingId of selected)
987
1130
  this.notifyPeerRouteChanged(nodeRoutingId);
988
- // A new selected route admits only through a new handshake.
1131
+ // Selected routes begin admission before waiting for the management cadence.
989
1132
  for (const nodeRoutingId of selected)
990
1133
  await this.announcePeer(nodeRoutingId);
991
- this.refreshAdmissionPending(performance.now());
1134
+ this.progressPeerAdmission(performance.now());
992
1135
  return changes;
993
1136
  }
994
1137
  close() {
995
- if (this.closed)
996
- return;
997
- this.closed = true;
998
- this.applicationJobStop.abort(new Error('Raw service runtime application job admission stopped.'));
999
- this.receivePermit?.releaseAfterInternalProcessing();
1000
- this.receivePermit?.releaseStorage?.();
1001
- this.receivePermit = undefined;
1002
- for (const send of this.controlSends.values())
1003
- delete send.next;
1004
- this.controlSends.clear();
1005
- this.mailbox.close();
1006
- this.operations.close('Raw service runtime closed.');
1007
- this.serviceIngress = undefined;
1008
- const router = this.router;
1009
- if (router !== undefined) {
1010
- this.applicationJobQueue.unregisterReceiveFlowTarget?.(router);
1011
- }
1012
1138
  const host = this.host;
1013
- if (host !== undefined)
1014
- host.close();
1015
- this.router = undefined;
1139
+ if (this.closed && host === undefined)
1140
+ return;
1016
1141
  this.host = undefined;
1142
+ try {
1143
+ if (!this.closed) {
1144
+ this.closed = true;
1145
+ this.applicationJobStop.abort((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RuntimeShutdown, 'Raw service runtime application job admission stopped.'));
1146
+ this.receivePermit?.releaseAfterInternalProcessing();
1147
+ this.receivePermit?.releaseStorage?.();
1148
+ this.receivePermit = undefined;
1149
+ for (const send of this.controlSends.values())
1150
+ delete send.next;
1151
+ this.controlSends.clear();
1152
+ this.mailbox.close();
1153
+ this.releaseOperations();
1154
+ this.serviceIngress = undefined;
1155
+ const router = this.router;
1156
+ if (router !== undefined) {
1157
+ this.applicationJobQueue.unregisterReceiveFlowTarget?.(router);
1158
+ }
1159
+ }
1160
+ if (host !== undefined)
1161
+ host.close();
1162
+ this.router = undefined;
1163
+ }
1164
+ catch (error) {
1165
+ this.host = host;
1166
+ throw error;
1167
+ }
1017
1168
  }
1018
- requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted, observer, operationKind) {
1169
+ requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted, observer, operationKind, requestOperation) {
1019
1170
  const correlation = this.nextCorrelation++;
1020
1171
  const header = channelName === undefined
1021
1172
  ? (0, service_wire_m6a_codec_1.encodeNodeRequestHeader)(correlation)
1022
1173
  : (0, service_wire_m6a_codec_1.encodeChannelRequestHeader)(correlation, channelName);
1023
- const encodedPayload = this.applicationFrame(payload);
1174
+ let encodedPayload = this.applicationFrame(payload);
1024
1175
  let selectedTargetNodeRoutingId = targetNodeRoutingId;
1025
1176
  if (selectedTargetNodeRoutingId !== this.descriptor.nodeRoutingId &&
1026
1177
  !this.isPeerRouteReady(selectedTargetNodeRoutingId)) {
@@ -1047,19 +1198,22 @@ class RawServiceMeshRuntime {
1047
1198
  }
1048
1199
  }
1049
1200
  if (selectedTargetNodeRoutingId === this.descriptor.nodeRoutingId) {
1201
+ encodedPayload = (0, payload_slab_1.copyPayloadBytes)(encodedPayload);
1050
1202
  // The local admission path aborts its capacity wait on the terminal
1051
1203
  // Promise, so a local request always keeps the Promise entry.
1052
- const pending = this.operations.register(timeoutMs);
1204
+ const pending = requestOperation === undefined
1205
+ ? this.operations.register(timeoutMs)
1206
+ : this.registerRequest(timeoutMs, observer, operationKind, requestOperation);
1053
1207
  const parts = [header, encodedPayload];
1054
1208
  const capacityStop = new AbortController();
1055
1209
  void pending.promise.finally(() => capacityStop.abort()).catch(() => undefined);
1056
1210
  void (async () => {
1057
1211
  const applicationJobOwner = await this.reserveLocalIngress(capacityStop.signal);
1058
1212
  try {
1059
- if (!this.operations.isPending(pending.id))
1213
+ if (!pending.isPending())
1060
1214
  return;
1061
1215
  const applicationJob = await applicationJobOwner.acquire('application', capacityStop.signal);
1062
- if (!this.operations.isPending(pending.id)) {
1216
+ if (!pending.isPending()) {
1063
1217
  applicationJob.close();
1064
1218
  return;
1065
1219
  }
@@ -1069,19 +1223,19 @@ class RawServiceMeshRuntime {
1069
1223
  parts,
1070
1224
  sourceRoutingId: this.descriptor.nodeRoutingId,
1071
1225
  correlation,
1072
- localReply: (terminalResult, failureCode, reply) => this.operations.complete(pending.id, {
1226
+ localReply: (terminalResult, failureCode, reply) => this.completeRequest(pending, {
1073
1227
  terminalResult,
1074
1228
  failureCode,
1075
1229
  ...(reply === undefined ? {} : { payload: reply })
1076
- }),
1230
+ }, requestOperation === undefined ? undefined : observer, operationKind),
1077
1231
  applicationJob
1078
1232
  });
1079
1233
  if (!accepted) {
1080
1234
  applicationJob.close();
1081
- this.operations.complete(pending.id, {
1235
+ this.completeRequest(pending, {
1082
1236
  terminalResult: runtime_values_1.RequestResult.NotConnected,
1083
1237
  failureCode: 0
1084
- });
1238
+ }, requestOperation === undefined ? undefined : observer, operationKind);
1085
1239
  }
1086
1240
  else {
1087
1241
  onAdmitted?.();
@@ -1090,31 +1244,22 @@ class RawServiceMeshRuntime {
1090
1244
  finally {
1091
1245
  applicationJobOwner.close();
1092
1246
  }
1093
- })().catch((error) => this.operations.fail(pending.id, error));
1247
+ })().catch((error) => this.failRequest(pending, error, requestOperation === undefined ? undefined : observer, operationKind));
1094
1248
  return pending;
1095
1249
  }
1096
- const pending = this.registerRequest(timeoutMs, observer, operationKind);
1097
- const selectedPeer = this.topology.admittedPeer(selectedTargetNodeRoutingId);
1098
- if (selectedPeer === undefined) {
1099
- // Logical target selection is the requester's decision: an RID that is
1100
- // not an admitted peer is not a target. Whether an admitted target's
1101
- // route can carry the request is Core's REQUEST result.
1250
+ const pending = this.registerRequest(timeoutMs, observer, operationKind, requestOperation);
1251
+ const selectedPeer = this.topology.readyPeer(selectedTargetNodeRoutingId);
1252
+ if (selectedPeer === undefined &&
1253
+ !this.expectedPeers.has(selectedTargetNodeRoutingId) &&
1254
+ this.topology.peer(selectedTargetNodeRoutingId) === undefined) {
1102
1255
  this.completeRequest(pending, {
1103
1256
  terminalResult: runtime_values_1.RequestResult.NotFound,
1104
1257
  failureCode: REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
1105
- });
1258
+ }, requestOperation === undefined ? undefined : observer, operationKind);
1106
1259
  return pending;
1107
1260
  }
1108
1261
  const parts = [header, encodedPayload];
1109
- let request;
1110
- try {
1111
- request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived, onAdmitted);
1112
- }
1113
- catch (error) {
1114
- this.failRequest(pending, error);
1115
- return pending;
1116
- }
1117
- void request.then((replyParts) => {
1262
+ const completed = (replyParts) => {
1118
1263
  try {
1119
1264
  if (replyParts.length < 1 || replyParts.length > 2) {
1120
1265
  throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Invalid reply parts.');
@@ -1135,16 +1280,37 @@ class RawServiceMeshRuntime {
1135
1280
  terminalResult: reply.terminalResult,
1136
1281
  failureCode: reply.failureCode
1137
1282
  };
1138
- this.operations.complete(pending.id, reply.terminalResult === 0
1283
+ const value = reply.terminalResult === 0
1139
1284
  ? { ...result, payload: (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(replyParts[1]) }
1140
- : result);
1285
+ : result;
1286
+ if (requestOperation !== undefined && observer !== undefined)
1287
+ observer.operationCompleted(pending.id, value, operationKind);
1288
+ else
1289
+ pending.reply(value);
1141
1290
  }
1142
1291
  catch (error) {
1143
- this.operations.fail(pending.id, error);
1292
+ this.failRequest(pending, error, requestOperation === undefined ? undefined : observer, operationKind);
1144
1293
  }
1145
- }, (error) => {
1146
- this.operations.fail(pending.id, error);
1147
- });
1294
+ };
1295
+ const failed = (error) => this.failRequest(pending, error, requestOperation === undefined ? undefined : observer, operationKind);
1296
+ if (selectedPeer !== undefined) {
1297
+ try {
1298
+ this.requireStarted().request(selectedTargetNodeRoutingId, parts, (0, request_deadline_1.remainingRequestTimeout)('Request', pending.deadlineMs), completed, failed, selectedPeer.liveness?.recordReceived, onAdmitted, pending);
1299
+ }
1300
+ catch (error) {
1301
+ failed(error);
1302
+ }
1303
+ return pending;
1304
+ }
1305
+ (0, durable_service_request_1.admitServiceRequest)(this, selectedTargetNodeRoutingId, pending, (remaining, finished) => {
1306
+ this.requireStarted().request(selectedTargetNodeRoutingId, parts, remaining, (reply) => {
1307
+ finished();
1308
+ completed(reply);
1309
+ }, (error) => {
1310
+ finished();
1311
+ failed(error);
1312
+ }, this.topology.admittedPeer(selectedTargetNodeRoutingId)?.liveness?.recordReceived, onAdmitted, pending);
1313
+ }, failed);
1148
1314
  return pending;
1149
1315
  }
1150
1316
  /**
@@ -1155,10 +1321,10 @@ class RawServiceMeshRuntime {
1155
1321
  return Buffer.isBuffer(payload) ? payload : (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload);
1156
1322
  }
1157
1323
  applicationPayload(payload) {
1158
- return Buffer.isBuffer(payload) ? (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payload) : payload;
1324
+ return Buffer.isBuffer(payload) ? (0, service_wire_m6a_codec_1.decodeApplicationPayload)(payload) : payload;
1159
1325
  }
1160
1326
  admitPeer(descriptor, connectionId, nowMs, expected, command = service_wire_m6a_codec_1.M6aServiceWireCommand.hello, descriptorBytes) {
1161
- const previous = this.topology.peer(descriptor.nodeRoutingId);
1327
+ const previous = this.topology.admittedPeer(descriptor.nodeRoutingId);
1162
1328
  const topologyConnectionId = typeof connectionId === 'bigint' ? routeConnectionId(connectionId) : connectionId;
1163
1329
  const result = this.topology.admit(descriptor, topologyConnectionId, expected, () => {
1164
1330
  const admission = this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
@@ -1171,7 +1337,11 @@ class RawServiceMeshRuntime {
1171
1337
  if (result === 'notRequired' && previous !== undefined) {
1172
1338
  this.liveness.disconnect(descriptor.nodeRoutingId, previous.liveness?.connectionId ?? previous.connectionId);
1173
1339
  }
1174
- if (result === 'admitted')
1340
+ if (result === 'admitted' &&
1341
+ (previous?.connectionId !== topologyConnectionId ||
1342
+ previous.descriptor.lifecycleGeneration !== descriptor.lifecycleGeneration ||
1343
+ previous.remoteAdmitReceived !==
1344
+ this.topology.admittedPeer(descriptor.nodeRoutingId)?.remoteAdmitReceived))
1175
1345
  this.notifyPeerRouteChanged(descriptor.nodeRoutingId);
1176
1346
  return result;
1177
1347
  }
@@ -1204,10 +1374,16 @@ class RawServiceMeshRuntime {
1204
1374
  });
1205
1375
  this.endpointOnlyPeers.delete(endpoint);
1206
1376
  }
1207
- removePeer(peer) {
1377
+ removePeer(peer, disconnectPhysical) {
1208
1378
  this.topology.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
1209
1379
  this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.liveness?.connectionId ?? peer.connectionId);
1210
- this.onPeerDisconnected?.(peer.descriptor.nodeRoutingId, peer.descriptor.advertisedEndpoint, peer.descriptor.lifecycleGeneration);
1380
+ try {
1381
+ disconnectPhysical?.();
1382
+ }
1383
+ finally {
1384
+ // The logical admission has ended even when the physical disconnect reports a failure.
1385
+ this.onPeerDisconnected?.(peer.descriptor.nodeRoutingId, peer.descriptor.advertisedEndpoint, peer.descriptor.lifecycleGeneration);
1386
+ }
1211
1387
  }
1212
1388
  requireStarted() {
1213
1389
  if (this.router === undefined)
@@ -1234,9 +1410,7 @@ class RawServiceMeshRuntime {
1234
1410
  if (command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello)
1235
1411
  this.liveness.setAdmissionPending(true, performance.now());
1236
1412
  const existing = this.controlSends.get(key);
1237
- if (existing !== undefined &&
1238
- existing.task !== undefined &&
1239
- (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello || existing.current?.() === true)) {
1413
+ if (existing?.task !== undefined) {
1240
1414
  if (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
1241
1415
  existing.next = attempt;
1242
1416
  existing.current = current;
@@ -1254,7 +1428,7 @@ class RawServiceMeshRuntime {
1254
1428
  const completeSend = () => {
1255
1429
  if (owner.controlSends.get(key) !== state)
1256
1430
  return;
1257
- if (hello !== undefined && current?.() === true)
1431
+ if (hello !== undefined)
1258
1432
  delete state.task;
1259
1433
  else
1260
1434
  owner.controlSends.delete(key);
@@ -1297,6 +1471,8 @@ class RawServiceMeshRuntime {
1297
1471
  throw failure.error;
1298
1472
  }
1299
1473
  send(targetNodeRoutingId, parts) {
1474
+ if (!this.isPeerRouteReady(targetNodeRoutingId))
1475
+ return false;
1300
1476
  try {
1301
1477
  const submission = this.requireStarted().submitSend(targetNodeRoutingId, parts);
1302
1478
  if (submission.result === runtime_values_1.SubmitResult.Ok)
@@ -1317,6 +1493,9 @@ class RawServiceMeshRuntime {
1317
1493
  }
1318
1494
  }
1319
1495
  exports.RawServiceMeshRuntime = RawServiceMeshRuntime;
1496
+ function channelSendSubmitResult(accepted) {
1497
+ return accepted ? runtime_values_1.SubmitResult.Ok : runtime_values_1.SubmitResult.NotConnected;
1498
+ }
1320
1499
  function controlSendKey(target, command) {
1321
1500
  return `${command}:${target}`;
1322
1501
  }