@zlink-systems/framework 0.30.0 → 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 (456) hide show
  1. package/LICENSE +150 -68
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
  4. package/dist/contracts/Channels/Calls.d.ts +2 -1
  5. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
  6. package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
  7. package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
  8. package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
  9. package/dist/contracts/Common/encoded-payload-storage.js +5 -2
  10. package/dist/contracts/Configuration/Builders.d.ts +1 -1
  11. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
  12. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
  13. package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
  14. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
  15. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
  16. package/dist/contracts/Handlers/Attributes.d.ts +5 -13
  17. package/dist/contracts/Handlers/Attributes.js +7 -11
  18. package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
  19. package/dist/contracts/Handlers/JsonContract.js +4 -153
  20. package/dist/contracts/Locations/Rows.d.ts +2 -0
  21. package/dist/contracts/Spots/Contracts.d.ts +6 -1
  22. package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
  23. package/dist/nest-integration.d.ts +1 -1
  24. package/dist/nest-integration.js +2 -1
  25. package/dist/runtime/abort.d.ts +5 -0
  26. package/dist/runtime/abort.js +10 -0
  27. package/dist/runtime/actors/actor-authority-publication.js +3 -2
  28. package/dist/runtime/actors/actor-client.d.ts +1 -2
  29. package/dist/runtime/actors/actor-client.js +52 -57
  30. package/dist/runtime/actors/actor-context.d.ts +2 -0
  31. package/dist/runtime/actors/actor-context.js +46 -9
  32. package/dist/runtime/actors/actor-handoff.d.ts +8 -4
  33. package/dist/runtime/actors/actor-handoff.js +219 -92
  34. package/dist/runtime/actors/actor-join-relocation.d.ts +3 -0
  35. package/dist/runtime/actors/actor-local-native-join.js +13 -12
  36. package/dist/runtime/actors/actor-mailbox.js +27 -1
  37. package/dist/runtime/actors/actor-remote-joiner.js +3 -1
  38. package/dist/runtime/actors/actor-remote-wire.js +15 -0
  39. package/dist/runtime/actors/actor-reply.d.ts +4 -0
  40. package/dist/runtime/actors/actor-reply.js +29 -0
  41. package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
  42. package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
  43. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
  44. package/dist/runtime/actors/actor-runtime-state.js +2 -20
  45. package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
  46. package/dist/runtime/actors/index.d.ts +8 -3
  47. package/dist/runtime/actors/index.js +55 -27
  48. package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
  49. package/dist/runtime/actors/session-disconnected-wire.js +48 -0
  50. package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
  51. package/dist/runtime/admission.d.ts +9 -1
  52. package/dist/runtime/admission.js +56 -23
  53. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +6 -8
  54. package/dist/runtime/application-jobs/application-ingress-record-owner.js +39 -22
  55. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +15 -1
  56. package/dist/runtime/application-jobs/application-job-queue-scope.js +61 -20
  57. package/dist/runtime/application-jobs/contracts.d.ts +12 -1
  58. package/dist/runtime/backend/contracts/index.d.ts +37 -12
  59. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
  60. package/dist/runtime/backend/mesh-completion-table.d.ts +9 -1
  61. package/dist/runtime/backend/mesh-completion-table.js +154 -49
  62. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +28 -1
  63. package/dist/runtime/backend/mesh-dispatch-pump.js +208 -101
  64. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  65. package/dist/runtime/backend/node/node-backend-adapter-support.js +16 -9
  66. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  67. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
  68. package/dist/runtime/backend/node/node-raw-binding-port.js +124 -72
  69. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +46 -13
  70. package/dist/runtime/backend/node/node-raw-mesh-backend.js +181 -164
  71. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
  72. package/dist/runtime/backend/node/node-socket-backend-adapter.js +11 -11
  73. package/dist/runtime/backend/raw-binding-port.d.ts +2 -2
  74. package/dist/runtime/backend/runtime-message.d.ts +1 -0
  75. package/dist/runtime/backend/runtime-message.js +5 -0
  76. package/dist/runtime/backend/runtime-values.d.ts +1 -0
  77. package/dist/runtime/backend/runtime-values.js +2 -1
  78. package/dist/runtime/channels/channel-clients.d.ts +2 -0
  79. package/dist/runtime/channels/channel-clients.js +75 -23
  80. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +25 -5
  81. package/dist/runtime/channels/channel-dispatch-pipeline.js +111 -56
  82. package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
  83. package/dist/runtime/channels/channel-dispatch-services.js +45 -0
  84. package/dist/runtime/channels/channel-dispatchers.d.ts +4 -3
  85. package/dist/runtime/channels/channel-dispatchers.js +62 -54
  86. package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
  87. package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
  88. package/dist/runtime/channels/channel-envelope.d.ts +2 -0
  89. package/dist/runtime/channels/channel-envelope.js +146 -28
  90. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  91. package/dist/runtime/channels/channel-outbound-operations.js +8 -8
  92. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
  93. package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
  94. package/dist/runtime/channels/channel-runtime-manager.d.ts +9 -8
  95. package/dist/runtime/channels/channel-runtime-manager.js +16 -16
  96. package/dist/runtime/channels/channel-transports.d.ts +18 -16
  97. package/dist/runtime/channels/channel-transports.js +77 -58
  98. package/dist/runtime/channels/client-server-location-runtime.js +5 -4
  99. package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
  100. package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
  101. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  102. package/dist/runtime/channels/fanout-location-runtime.js +3 -3
  103. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  104. package/dist/runtime/channels/local-spot-route-transport.js +2 -1
  105. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
  106. package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
  107. package/dist/runtime/channels/source-spot-router.d.ts +2 -2
  108. package/dist/runtime/channels/source-spot-router.js +4 -4
  109. package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
  110. package/dist/runtime/channels/spot-node-route-transport.js +4 -4
  111. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
  112. package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
  113. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
  114. package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
  115. package/dist/runtime/diagnostics/flow-context.js +19 -7
  116. package/dist/runtime/diagnostics/index.js +4 -9
  117. package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
  118. package/dist/runtime/diagnostics/message-flow.js +35 -5
  119. package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
  120. package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
  121. package/dist/runtime/execution/index.d.ts +4 -2
  122. package/dist/runtime/execution/index.js +33 -10
  123. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -0
  124. package/dist/runtime/execution/serial-execution-queue.js +22 -2
  125. package/dist/runtime/execution/state-lane.d.ts +2 -0
  126. package/dist/runtime/execution/state-lane.js +5 -0
  127. package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
  128. package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
  129. package/dist/runtime/foundation/durable-service-request.js +98 -0
  130. package/dist/runtime/foundation/operation-identity.d.ts +1 -0
  131. package/dist/runtime/foundation/operation-identity.js +5 -1
  132. package/dist/runtime/foundation/operation-registry.d.ts +25 -1
  133. package/dist/runtime/foundation/operation-registry.js +86 -18
  134. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +61 -8
  135. package/dist/runtime/foundation/raw-service-mesh-runtime.js +486 -266
  136. package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
  137. package/dist/runtime/foundation/service-liveness-registry.js +38 -0
  138. package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
  139. package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
  140. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +3 -3
  141. package/dist/runtime/foundation/service-relocation-object-owner.js +48 -34
  142. package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
  143. package/dist/runtime/foundation/service-relocation-runtime.js +20 -4
  144. package/dist/runtime/foundation/service-runtime-contracts.d.ts +10 -1
  145. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
  146. package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
  147. package/dist/runtime/foundation/service-stateful-registry.js +24 -26
  148. package/dist/runtime/foundation/service-stateful-runtime.d.ts +75 -9
  149. package/dist/runtime/foundation/service-stateful-runtime.js +486 -218
  150. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -6
  151. package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
  152. package/dist/runtime/foundation/service-topology-registry.d.ts +12 -2
  153. package/dist/runtime/foundation/service-topology-registry.js +61 -27
  154. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
  155. package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
  156. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  157. package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
  158. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +13 -3
  159. package/dist/runtime/foundation/service-wire-m6a-codec.js +189 -78
  160. package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
  161. package/dist/runtime/handlers/handler-instance-scope.js +54 -11
  162. package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
  163. package/dist/runtime/host/actor-packet-relay.js +59 -72
  164. package/dist/runtime/host/actor-placement-coordinator.js +25 -8
  165. package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
  166. package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
  167. package/dist/runtime/host/actor-transfer-runtime.js +85 -331
  168. package/dist/runtime/host/application-job-queue.d.ts +40 -7
  169. package/dist/runtime/host/application-job-queue.js +137 -42
  170. package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
  171. package/dist/runtime/host/entry-actor-runtime.js +3 -0
  172. package/dist/runtime/host/index.d.ts +12 -2
  173. package/dist/runtime/host/index.js +300 -202
  174. package/dist/runtime/host/location-runtime-owner.js +2 -6
  175. package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
  176. package/dist/runtime/host/mesh-router-resolver.js +14 -6
  177. package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
  178. package/dist/runtime/host/remote-bound-session-relay.js +73 -208
  179. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
  180. package/dist/runtime/host/route-mesh-runtime.js +6 -4
  181. package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
  182. package/dist/runtime/host/runtime-shutdown.js +3 -2
  183. package/dist/runtime/host/service-relocation-control.d.ts +1 -0
  184. package/dist/runtime/host/service-relocation-control.js +10 -4
  185. package/dist/runtime/host/service-relocation-host-runtime.d.ts +22 -14
  186. package/dist/runtime/host/service-relocation-host-runtime.js +754 -599
  187. package/dist/runtime/host/spot-address-transport.js +3 -2
  188. package/dist/runtime/host/spot-runtime-options-factory.js +16 -7
  189. package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
  190. package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
  191. package/dist/runtime/locations/actor-location-claims.js +34 -19
  192. package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
  193. package/dist/runtime/locations/auto-connect-loop.js +22 -14
  194. package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
  195. package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
  196. package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
  197. package/dist/runtime/locations/descriptor-publication.js +11 -0
  198. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  199. package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
  200. package/dist/runtime/locations/in-memory-authority-store.js +56 -19
  201. package/dist/runtime/locations/in-memory-location-store.js +1 -10
  202. package/dist/runtime/locations/index.d.ts +1 -0
  203. package/dist/runtime/locations/index.js +1 -0
  204. package/dist/runtime/locations/lease-tracker.js +1 -6
  205. package/dist/runtime/locations/lifecycle.d.ts +1 -2
  206. package/dist/runtime/locations/lifecycle.js +2 -5
  207. package/dist/runtime/locations/location-store-repository.d.ts +51 -1
  208. package/dist/runtime/locations/location-store-repository.js +363 -139
  209. package/dist/runtime/locations/relocation-blob.d.ts +18 -1
  210. package/dist/runtime/locations/relocation-blob.js +52 -1
  211. package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
  212. package/dist/runtime/locations/request-source-resolver.js +80 -0
  213. package/dist/runtime/locations/resolvers.js +1 -1
  214. package/dist/runtime/locations/runtime.d.ts +7 -3
  215. package/dist/runtime/locations/runtime.js +61 -53
  216. package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
  217. package/dist/runtime/messaging/framework-json-v1.js +38 -294
  218. package/dist/runtime/messaging/packet-name.d.ts +1 -1
  219. package/dist/runtime/messaging/packet-name.js +8 -24
  220. package/dist/runtime/messaging/payload-codec.d.ts +7 -1
  221. package/dist/runtime/messaging/payload-codec.js +7 -6
  222. package/dist/runtime/messaging/request-result.d.ts +2 -0
  223. package/dist/runtime/messaging/request-result.js +57 -0
  224. package/dist/runtime/messaging/submission-result.d.ts +1 -0
  225. package/dist/runtime/messaging/submission-result.js +5 -2
  226. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +34 -1
  227. package/dist/runtime/protocol/service_wire_codec.generated.js +229 -0
  228. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +16 -1
  229. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +37 -8
  230. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +7 -2
  231. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +36 -21
  232. package/dist/runtime/spots/index.d.ts +21 -11
  233. package/dist/runtime/spots/index.js +243 -178
  234. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  235. package/dist/runtime/spots/spot-activation-registry.js +21 -11
  236. package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
  237. package/dist/runtime/spots/spot-activation-state.js +7 -7
  238. package/dist/runtime/spots/spot-activation.d.ts +7 -3
  239. package/dist/runtime/spots/spot-activation.js +140 -52
  240. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
  241. package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
  242. package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
  243. package/dist/runtime/spots/spot-actor-membership.js +0 -8
  244. package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
  245. package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
  246. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
  247. package/dist/runtime/spots/spot-entry-activation.js +20 -11
  248. package/dist/runtime/spots/spot-handler-registry.d.ts +7 -4
  249. package/dist/runtime/spots/spot-handler-registry.js +24 -10
  250. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
  251. package/dist/runtime/spots/spot-manager-public.js +2 -2
  252. package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
  253. package/dist/runtime/spots/spot-node-autoconnect.js +22 -42
  254. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
  255. package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
  256. package/dist/runtime/spots/spot-outbound.d.ts +3 -0
  257. package/dist/runtime/spots/spot-outbound.js +27 -18
  258. package/dist/runtime/spots/spot-remote-codec.js +5 -1
  259. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
  260. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
  261. package/dist/runtime/spots/spot-runtime-ports.d.ts +1 -1
  262. package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
  263. package/dist/runtime/spots/spot-serial-executor.js +61 -8
  264. package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
  265. package/dist/runtime/spots/spot-subscription-dispatch.js +1 -4
  266. package/dist/runtime/spots/spot-timer.d.ts +57 -5
  267. package/dist/runtime/spots/spot-timer.js +288 -103
  268. package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
  269. package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
  270. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
  271. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
  272. package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
  273. package/dist/runtime/streams/bound-session-service.d.ts +1 -1
  274. package/dist/runtime/streams/bound-session-service.js +6 -11
  275. package/dist/runtime/streams/index.d.ts +3 -2
  276. package/dist/runtime/streams/index.js +6 -4
  277. package/dist/runtime/streams/managed-stream.js +3 -2
  278. package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
  279. package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
  280. package/dist/runtime/streams/session-actor-coordinator.js +15 -32
  281. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
  282. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
  283. package/dist/runtime/streams/stream-session-runtime.js +14 -31
  284. package/dist/runtime/workers/index.js +1 -1
  285. package/package.json +3 -3
  286. package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
  287. package/src/contracts/Channels/Calls.ts +2 -1
  288. package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
  289. package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
  290. package/src/contracts/Common/encoded-payload-storage.ts +6 -3
  291. package/src/contracts/Configuration/Builders.ts +4 -1
  292. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
  293. package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
  294. package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
  295. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
  296. package/src/contracts/Handlers/Attributes.ts +14 -21
  297. package/src/contracts/Handlers/JsonContract.ts +8 -216
  298. package/src/contracts/Locations/Rows.ts +2 -0
  299. package/src/contracts/Spots/Contracts.ts +10 -1
  300. package/src/contracts/Spots/ZLinkSpot.ts +3 -3
  301. package/src/nest-integration.ts +1 -0
  302. package/src/runtime/abort.ts +12 -0
  303. package/src/runtime/actors/actor-authority-publication.ts +3 -2
  304. package/src/runtime/actors/actor-client.ts +100 -85
  305. package/src/runtime/actors/actor-context.ts +49 -9
  306. package/src/runtime/actors/actor-handoff.ts +291 -110
  307. package/src/runtime/actors/actor-join-relocation.ts +3 -0
  308. package/src/runtime/actors/actor-local-native-join.ts +21 -26
  309. package/src/runtime/actors/actor-mailbox.ts +40 -2
  310. package/src/runtime/actors/actor-remote-joiner.ts +6 -1
  311. package/src/runtime/actors/actor-remote-wire.ts +17 -0
  312. package/src/runtime/actors/actor-reply.ts +42 -0
  313. package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
  314. package/src/runtime/actors/actor-routed-json-request.ts +10 -2
  315. package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
  316. package/src/runtime/actors/actor-runtime-state.ts +2 -20
  317. package/src/runtime/actors/actor-source-transfer.ts +1 -34
  318. package/src/runtime/actors/index.ts +60 -32
  319. package/src/runtime/actors/session-disconnected-wire.ts +66 -0
  320. package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
  321. package/src/runtime/admission.ts +69 -21
  322. package/src/runtime/application-jobs/application-ingress-record-owner.ts +41 -25
  323. package/src/runtime/application-jobs/application-job-queue-scope.ts +83 -22
  324. package/src/runtime/application-jobs/contracts.ts +16 -1
  325. package/src/runtime/backend/contracts/index.ts +92 -18
  326. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
  327. package/src/runtime/backend/mesh-completion-table.ts +160 -57
  328. package/src/runtime/backend/mesh-dispatch-pump.ts +237 -108
  329. package/src/runtime/backend/node/node-backend-adapter-support.ts +17 -8
  330. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
  331. package/src/runtime/backend/node/node-raw-binding-port.ts +148 -85
  332. package/src/runtime/backend/node/node-raw-mesh-backend.ts +315 -201
  333. package/src/runtime/backend/node/node-socket-backend-adapter.ts +26 -11
  334. package/src/runtime/backend/raw-binding-port.ts +7 -2
  335. package/src/runtime/backend/runtime-message.ts +6 -0
  336. package/src/runtime/backend/runtime-values.ts +1 -0
  337. package/src/runtime/channels/channel-clients.ts +132 -58
  338. package/src/runtime/channels/channel-dispatch-pipeline.ts +198 -114
  339. package/src/runtime/channels/channel-dispatch-services.ts +69 -1
  340. package/src/runtime/channels/channel-dispatchers.ts +136 -90
  341. package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
  342. package/src/runtime/channels/channel-envelope.ts +225 -31
  343. package/src/runtime/channels/channel-outbound-operations.ts +22 -8
  344. package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
  345. package/src/runtime/channels/channel-runtime-manager.ts +41 -17
  346. package/src/runtime/channels/channel-transports.ts +171 -112
  347. package/src/runtime/channels/client-server-location-runtime.ts +11 -10
  348. package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
  349. package/src/runtime/channels/fanout-location-runtime.ts +17 -9
  350. package/src/runtime/channels/local-spot-route-transport.ts +3 -1
  351. package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
  352. package/src/runtime/channels/source-spot-router.ts +8 -4
  353. package/src/runtime/channels/spot-node-route-transport.ts +8 -4
  354. package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
  355. package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
  356. package/src/runtime/diagnostics/flow-context.ts +20 -7
  357. package/src/runtime/diagnostics/index.ts +1 -7
  358. package/src/runtime/diagnostics/message-flow.ts +47 -9
  359. package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
  360. package/src/runtime/execution/index.ts +40 -14
  361. package/src/runtime/execution/serial-execution-queue.ts +33 -4
  362. package/src/runtime/execution/state-lane.ts +7 -0
  363. package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
  364. package/src/runtime/foundation/durable-service-request.ts +137 -0
  365. package/src/runtime/foundation/operation-identity.ts +5 -1
  366. package/src/runtime/foundation/operation-registry.ts +98 -20
  367. package/src/runtime/foundation/raw-service-mesh-runtime.ts +704 -336
  368. package/src/runtime/foundation/service-liveness-registry.ts +39 -0
  369. package/src/runtime/foundation/service-mailbox.ts +8 -0
  370. package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
  371. package/src/runtime/foundation/service-relocation-object-owner.ts +55 -36
  372. package/src/runtime/foundation/service-relocation-runtime.ts +25 -4
  373. package/src/runtime/foundation/service-runtime-contracts.ts +19 -2
  374. package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
  375. package/src/runtime/foundation/service-stateful-registry.ts +38 -35
  376. package/src/runtime/foundation/service-stateful-runtime.ts +732 -275
  377. package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -16
  378. package/src/runtime/foundation/service-topology-registry.ts +91 -36
  379. package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
  380. package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
  381. package/src/runtime/foundation/service-wire-m6a-codec.ts +231 -76
  382. package/src/runtime/handlers/handler-instance-scope.ts +67 -16
  383. package/src/runtime/host/actor-packet-relay.ts +113 -94
  384. package/src/runtime/host/actor-placement-coordinator.ts +31 -8
  385. package/src/runtime/host/actor-runtime-options-factory.ts +13 -2
  386. package/src/runtime/host/actor-transfer-runtime.ts +104 -430
  387. package/src/runtime/host/application-job-queue.ts +160 -41
  388. package/src/runtime/host/entry-actor-runtime.ts +4 -0
  389. package/src/runtime/host/index.ts +473 -271
  390. package/src/runtime/host/location-runtime-owner.ts +2 -6
  391. package/src/runtime/host/mesh-router-resolver.ts +13 -5
  392. package/src/runtime/host/remote-bound-session-relay.ts +88 -271
  393. package/src/runtime/host/route-mesh-runtime.ts +12 -6
  394. package/src/runtime/host/runtime-shutdown.ts +15 -4
  395. package/src/runtime/host/service-relocation-control.ts +11 -5
  396. package/src/runtime/host/service-relocation-host-runtime.ts +1092 -759
  397. package/src/runtime/host/spot-address-transport.ts +4 -2
  398. package/src/runtime/host/spot-runtime-options-factory.ts +20 -7
  399. package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
  400. package/src/runtime/locations/actor-location-claims.ts +52 -30
  401. package/src/runtime/locations/auto-connect-loop.ts +22 -14
  402. package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
  403. package/src/runtime/locations/auto-connect-types.ts +0 -1
  404. package/src/runtime/locations/descriptor-publication.ts +7 -0
  405. package/src/runtime/locations/domain-store-contract.ts +5 -0
  406. package/src/runtime/locations/in-memory-authority-store.ts +85 -23
  407. package/src/runtime/locations/in-memory-location-store.ts +1 -12
  408. package/src/runtime/locations/index.ts +1 -0
  409. package/src/runtime/locations/lease-tracker.ts +2 -9
  410. package/src/runtime/locations/lifecycle.ts +8 -26
  411. package/src/runtime/locations/location-store-repository.ts +628 -152
  412. package/src/runtime/locations/relocation-blob.ts +75 -1
  413. package/src/runtime/locations/request-source-resolver.ts +138 -0
  414. package/src/runtime/locations/resolvers.ts +2 -2
  415. package/src/runtime/locations/runtime.ts +98 -64
  416. package/src/runtime/messaging/framework-json-v1.ts +5 -325
  417. package/src/runtime/messaging/packet-name.ts +5 -25
  418. package/src/runtime/messaging/payload-codec.ts +8 -11
  419. package/src/runtime/messaging/request-result.ts +62 -0
  420. package/src/runtime/messaging/submission-result.ts +5 -1
  421. package/src/runtime/protocol/service_wire_codec.generated.ts +218 -5
  422. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +16 -13
  423. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +46 -25
  424. package/src/runtime/spots/index.ts +389 -283
  425. package/src/runtime/spots/spot-activation-registry.ts +25 -13
  426. package/src/runtime/spots/spot-activation-state.ts +12 -19
  427. package/src/runtime/spots/spot-activation.ts +198 -96
  428. package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
  429. package/src/runtime/spots/spot-actor-membership.ts +0 -15
  430. package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
  431. package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
  432. package/src/runtime/spots/spot-entry-activation.ts +33 -21
  433. package/src/runtime/spots/spot-handler-registry.ts +56 -12
  434. package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
  435. package/src/runtime/spots/spot-manager-public.ts +2 -2
  436. package/src/runtime/spots/spot-node-autoconnect.ts +28 -47
  437. package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
  438. package/src/runtime/spots/spot-outbound.ts +39 -19
  439. package/src/runtime/spots/spot-remote-codec.ts +9 -2
  440. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
  441. package/src/runtime/spots/spot-runtime-ports.ts +1 -1
  442. package/src/runtime/spots/spot-serial-executor.ts +97 -25
  443. package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
  444. package/src/runtime/spots/spot-subscription-dispatch.ts +1 -4
  445. package/src/runtime/spots/spot-timer.ts +418 -158
  446. package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
  447. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
  448. package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
  449. package/src/runtime/streams/bound-session-service.ts +7 -10
  450. package/src/runtime/streams/index.ts +12 -6
  451. package/src/runtime/streams/managed-stream.ts +4 -2
  452. package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
  453. package/src/runtime/streams/session-actor-coordinator.ts +39 -88
  454. package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
  455. package/src/runtime/streams/stream-session-runtime.ts +13 -34
  456. package/src/runtime/workers/index.ts +1 -1
@@ -6,6 +6,7 @@ const application_ingress_record_owner_1 = require("../application-jobs/applicat
6
6
  const submission_result_1 = require("../messaging/submission-result");
7
7
  const runtime_values_1 = require("../backend/runtime-values");
8
8
  const service_wire_codec_generated_1 = require("../protocol/service_wire_codec.generated");
9
+ const service_wire_binary_primitives_1 = require("./service-wire-binary-primitives");
9
10
  const operation_registry_1 = require("./operation-registry");
10
11
  const service_liveness_registry_1 = require("./service-liveness-registry");
11
12
  const service_mailbox_1 = require("./service-mailbox");
@@ -17,6 +18,7 @@ const nativeErrnoValues = node_os_1.constants.errno;
17
18
  // Framework error code 13 (RequestTargetNotFound) is encoded as 14 on a
18
19
  // RequestResult.NotFound reply. Boundary transport results keep failureCode 0.
19
20
  const RAW_MESH_RECEIVE_RECORD_BUDGET = 64;
21
+ const NODE_SEND_HEADER = (0, service_wire_m6a_codec_1.encodeNodeSendHeader)();
20
22
  const RAW_MESH_RECEIVE_BYTE_BUDGET = 4 * 1024 * 1024;
21
23
  exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS = 2;
22
24
  const REQUEST_TARGET_NOT_FOUND_FAILURE_CODE = service_wire_constants_generated_1.ServiceWireFrameworkErrorCode.requestTargetNotFound;
@@ -37,6 +39,7 @@ class RawServiceMeshRuntime {
37
39
  expectedPeers = new Map();
38
40
  endpointOnlyPeers = new Set();
39
41
  peerConnectionIntentRemoved = new Set();
42
+ peerRouteChanged = new Set();
40
43
  /**
41
44
  * The last observed Core selected route of each RID (Core ROUTER §10.1):
42
45
  * RID -> route generation. Only `observeSelectedRoutes` replaces it.
@@ -44,10 +47,12 @@ class RawServiceMeshRuntime {
44
47
  selectedRoutes = new Map();
45
48
  bindingPort;
46
49
  applicationJobQueue;
50
+ nodeMailboxOwner;
47
51
  peerAdmissionSealed;
48
52
  applicationJobStop = new AbortController();
49
53
  receiveAcquisition;
50
54
  receivePermit;
55
+ receiveRotation;
51
56
  controlSends = new Map();
52
57
  infrastructureFailure;
53
58
  onReceiveReady;
@@ -62,12 +67,14 @@ class RawServiceMeshRuntime {
62
67
  router;
63
68
  nextCorrelation = 1n;
64
69
  serviceIngress;
70
+ serviceIngressAccepts;
65
71
  closed = false;
66
72
  constructor(options) {
67
73
  this.onReceiveReady = options.onReceiveReady;
68
74
  this.infrastructureTaskRunner = options.infrastructureTaskRunner;
69
75
  this.operations = new operation_registry_1.OperationRegistry(undefined, options.onPendingOperationsChanged);
70
76
  this.descriptor = options.descriptor;
77
+ this.nodeMailboxOwner = `node:${options.descriptor.nodeRoutingId}`;
71
78
  this.topology = new service_topology_registry_1.ServiceTopologyRegistry(options.descriptor);
72
79
  this.mailbox = new service_mailbox_1.ServiceMailbox(options.onMailboxReady);
73
80
  this.liveness = new service_liveness_registry_1.ServiceLivenessRegistry(options.probeIntervalMs, options.peerTimeoutMs);
@@ -170,13 +177,15 @@ class RawServiceMeshRuntime {
170
177
  router.disconnectRid(nodeRoutingId);
171
178
  }
172
179
  else {
173
- router.disconnect(endpoint);
180
+ try {
181
+ router.disconnect(endpoint);
182
+ }
183
+ catch (error) {
184
+ if (!isAlreadyDisconnectedError(error))
185
+ throw error;
186
+ }
174
187
  }
175
188
  }
176
- catch (error) {
177
- if (!isAlreadyDisconnectedError(error))
178
- throw error;
179
- }
180
189
  finally {
181
190
  if (current !== undefined)
182
191
  this.removePeer(current);
@@ -222,6 +231,58 @@ class RawServiceMeshRuntime {
222
231
  this.peerConnectionIntentRemoved.delete(listener);
223
232
  };
224
233
  }
234
+ observePeerRoute(nodeRoutingId) {
235
+ const selected = this.selectedRoutes.get(nodeRoutingId);
236
+ const admitted = this.topology.admittedPeer(nodeRoutingId)?.liveness?.connectionId;
237
+ return {
238
+ generation: selected ?? (typeof admitted === 'bigint' ? admitted : undefined),
239
+ ready: admitted !== undefined && (selected === undefined || admitted === selected)
240
+ };
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
+ }
270
+ get requestStopSignal() {
271
+ return this.applicationJobStop.signal;
272
+ }
273
+ observePeerRouteChanged(listener) {
274
+ this.peerRouteChanged.add(listener);
275
+ return () => {
276
+ this.peerRouteChanged.delete(listener);
277
+ };
278
+ }
279
+ hasSelectedPeerRoute(nodeRoutingId) {
280
+ return this.selectedRoutes.has(nodeRoutingId);
281
+ }
282
+ notifyPeerRouteChanged(nodeRoutingId) {
283
+ for (const listener of this.peerRouteChanged)
284
+ listener(nodeRoutingId);
285
+ }
225
286
  notifyPeerConnectionIntentRemoved(nodeRoutingId) {
226
287
  // Only the logical owner's removal publishes lifecycle termination.
227
288
  // A physical disconnect alone retains the connection expectation.
@@ -231,26 +292,34 @@ class RawServiceMeshRuntime {
231
292
  listener(nodeRoutingId);
232
293
  }
233
294
  announcePeer(nodeRoutingId) {
234
- const expected = this.expectedPeers.get(nodeRoutingId);
295
+ if (this.closed)
296
+ return false;
235
297
  const generation = this.selectedRoutes.get(nodeRoutingId);
236
- if (expected === undefined ||
237
- generation === undefined ||
238
- expected.helloSubmittedGeneration === generation ||
239
- this.peerAdmissionSealed?.() === true)
240
- return Promise.resolve(false);
241
- const current = () => this.expectedPeers.get(nodeRoutingId) === expected &&
242
- this.selectedRoutes.get(nodeRoutingId) === generation;
243
- return Promise.resolve(this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [
244
- (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
245
- ], () => {
246
- if (current())
247
- expected.helloSubmittedGeneration = generation;
248
- }), current));
298
+ if (generation === undefined)
299
+ return false;
300
+ const key = controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
301
+ if (!this.isPeerAnnouncementCurrent(nodeRoutingId, generation)) {
302
+ this.controlSends.delete(key);
303
+ return false;
304
+ }
305
+ const current = () => this.isPeerAnnouncementCurrent(nodeRoutingId, generation);
306
+ 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());
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);
249
318
  }
250
319
  isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
251
320
  // Admission is bound to the observed selected route: the route observer
252
321
  // removes the peer when that route ends or is replaced.
253
- const peer = this.topology.peer(nodeRoutingId);
322
+ const peer = this.topology.admittedPeer(nodeRoutingId);
254
323
  return (peer !== undefined &&
255
324
  (lifecycleGeneration === undefined ||
256
325
  peer.descriptor.lifecycleGeneration === lifecycleGeneration));
@@ -287,22 +356,22 @@ class RawServiceMeshRuntime {
287
356
  // placement and channel selectors therefore need the new mutable fields
288
357
  // on that same connection before the next request is selected; waiting for
289
358
  // a reconnect would leave a race where a drained node is selected again.
359
+ await this.publishLocalDescriptor(this.topology.peers().map((peer) => peer.descriptor.nodeRoutingId));
360
+ }
361
+ async publishLocalDescriptor(targets) {
290
362
  const update = (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.update, this.topology.localDescriptor());
291
- for (const peer of this.topology.peers()) {
292
- await this.send(peer.descriptor.nodeRoutingId, [update]);
363
+ for (const target of targets) {
364
+ await this.sendService(target, [update]);
293
365
  }
294
366
  }
295
367
  replaceDiscoveredNotRequired(descriptors) {
296
368
  this.topology.replaceDiscoveredNotRequired(descriptors);
297
369
  }
298
370
  isObjectClientNodeDirectTarget(nodeRoutingId) {
299
- const descriptor = nodeRoutingId === this.descriptor.nodeRoutingId
300
- ? this.topology.localDescriptor()
301
- : this.topology.knownDescriptor(nodeRoutingId);
302
- return descriptor?.objectRole === 'client';
371
+ return this.topology.isObjectClientNodeDirectTarget(nodeRoutingId);
303
372
  }
304
- async sendToNode(targetNodeRoutingId, payload) {
305
- return this.send(targetNodeRoutingId, [(0, service_wire_m6a_codec_1.encodeNodeSendHeader)(), this.applicationFrame(payload)]);
373
+ sendToNode(targetNodeRoutingId, payload) {
374
+ return this.send(targetNodeRoutingId, [NODE_SEND_HEADER, this.applicationFrame(payload)]);
306
375
  }
307
376
  async sendToChannel(channelName, payload) {
308
377
  const selection = this.selectChannelTarget(channelName);
@@ -317,17 +386,42 @@ class RawServiceMeshRuntime {
317
386
  ? runtime_values_1.SubmitResult.Ok
318
387
  : runtime_values_1.SubmitResult.NotConnected;
319
388
  }
320
- requestToNode(targetNodeRoutingId, payload, timeoutMs) {
321
- return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs);
389
+ requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted, observer, operationKind) {
390
+ return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted, observer, operationKind);
322
391
  }
323
- requestToChannel(channelName, payload, timeoutMs) {
392
+ requestToChannel(channelName, payload, timeoutMs, onAdmitted, observer, operationKind) {
324
393
  const selection = this.selectChannelTarget(channelName);
325
394
  if (selection.kind !== 'selected') {
326
- const pending = this.operations.register(timeoutMs);
327
- this.operations.complete(pending.id, selection.requestResult);
395
+ const pending = this.registerRequest(timeoutMs, observer, operationKind);
396
+ this.completeRequest(pending, selection.requestResult);
328
397
  return pending;
329
398
  }
330
- return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName);
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);
331
425
  }
332
426
  selectChannelTarget(channelName) {
333
427
  const selected = this.topology.selectChannel(channelName, (peer) => this.isPeerRouteReady(peer.descriptor.nodeRoutingId));
@@ -348,11 +442,12 @@ class RawServiceMeshRuntime {
348
442
  }
349
443
  };
350
444
  }
351
- setServiceIngress(handler) {
445
+ setServiceIngress(handler, accepts) {
352
446
  if (this.serviceIngress !== undefined && this.serviceIngress !== handler) {
353
447
  throw new Error('Raw service ingress is already registered.');
354
448
  }
355
449
  this.serviceIngress = handler;
450
+ this.serviceIngressAccepts = accepts;
356
451
  }
357
452
  async reserveLocalIngress(signal) {
358
453
  const waitSignal = signal === undefined
@@ -362,11 +457,17 @@ class RawServiceMeshRuntime {
362
457
  return application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, { close() { } });
363
458
  }
364
459
  async sendService(targetNodeRoutingId, parts) {
365
- return this.send(targetNodeRoutingId, parts);
460
+ try {
461
+ await this.requireStarted().send(targetNodeRoutingId, parts);
462
+ return true;
463
+ }
464
+ catch (error) {
465
+ return this.sendFailure(error);
466
+ }
366
467
  }
367
- requestService(targetNodeRoutingId, parts, timeoutMs) {
368
- const admission = this.topology.peer(targetNodeRoutingId)?.liveness;
369
- return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, admission?.recordReceived);
468
+ requestService(targetNodeRoutingId, parts, timeoutMs, onAdmitted) {
469
+ const admission = this.topology.admittedPeer(targetNodeRoutingId)?.liveness;
470
+ return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, admission?.recordReceived, onAdmitted);
370
471
  }
371
472
  replyService(record, parts) {
372
473
  if (record.requestSequence === undefined) {
@@ -423,51 +524,59 @@ class RawServiceMeshRuntime {
423
524
  const observe = (_source, byteCount) => {
424
525
  bytes += byteCount;
425
526
  };
426
- while (receiveReady && messages < RAW_MESH_RECEIVE_RECORD_BUDGET && !this.closed) {
427
- const result = await this.receiveOne(performance.now(), observe);
428
- if (result === 'noData') {
429
- receiveReady = false;
430
- break;
527
+ const rotation = (this.receiveRotation ??= this.applicationJobQueue.createReceiveRotation(RAW_MESH_RECEIVE_RECORD_BUDGET, 'remote'));
528
+ if (receiveReady)
529
+ 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;
537
+ }
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;
431
544
  }
432
- messages += 1;
433
- // Core owns the per-peer fair-queue cursor. The Framework limit bounds
434
- // the entire round, so changing peers does not renew its byte/count budget.
435
- if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
436
- performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
437
- break;
545
+ }
546
+ finally {
547
+ rotation.releaseUnused();
438
548
  }
439
549
  if (!this.closed) {
440
- for (const nodeRoutingId of this.expectedPeers.keys()) {
441
- if (this.topology.peer(nodeRoutingId) === undefined)
442
- await this.announcePeer(nodeRoutingId);
443
- }
444
550
  this.tickLiveness();
445
551
  }
446
552
  return receiveReady && messages > 0;
447
553
  }
448
- async receiveOne(nowMs, observe) {
554
+ receiveOne(nowMs, observe, rotation) {
449
555
  const router = this.requireStarted();
450
556
  this.observeInfrastructureFailure();
451
- if (this.receivePermit === undefined && this.receiveAcquisition === undefined) {
557
+ let permit = this.receivePermit;
558
+ this.receivePermit = undefined;
559
+ permit ??= rotation?.take();
560
+ if (permit === undefined && this.receiveAcquisition === undefined) {
452
561
  let resolveAcquisition;
453
562
  let rejectAcquisition;
454
- const acquisition = new Promise((resolve, reject) => {
455
- resolveAcquisition = resolve;
456
- rejectAcquisition = reject;
457
- });
458
- const permit = this.applicationJobQueue.acquireOrResume((permit) => {
563
+ permit = this.applicationJobQueue.acquireOrResume((permit) => {
459
564
  this.receiveAcquisition = undefined;
460
- if (this.closed)
565
+ if (this.closed) {
461
566
  permit.releaseAfterInternalProcessing();
567
+ permit.releaseStorage?.();
568
+ }
462
569
  else {
463
570
  this.receivePermit = permit;
464
571
  this.onReceiveReady?.();
465
572
  }
466
- resolveAcquisition(permit);
467
- }, rejectAcquisition, this.applicationJobStop.signal, 'remote');
468
- if (permit !== undefined)
469
- this.receivePermit = permit;
470
- else {
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
+ });
471
580
  this.receiveAcquisition = acquisition;
472
581
  acquisition.catch((error) => {
473
582
  this.receiveAcquisition = undefined;
@@ -476,12 +585,11 @@ class RawServiceMeshRuntime {
476
585
  });
477
586
  }
478
587
  }
479
- const permit = this.receivePermit;
480
- this.receivePermit = undefined;
481
588
  if (permit === undefined)
482
589
  return 'noData';
483
590
  if (this.closed) {
484
591
  permit.releaseAfterInternalProcessing();
592
+ permit.releaseStorage?.();
485
593
  return 'noData';
486
594
  }
487
595
  let received;
@@ -490,23 +598,44 @@ class RawServiceMeshRuntime {
490
598
  }
491
599
  catch (error) {
492
600
  permit.releaseAfterInternalProcessing();
601
+ permit.releaseStorage?.();
493
602
  throw error;
494
603
  }
495
604
  if (received === undefined) {
496
605
  permit.releaseAfterInternalProcessing();
606
+ permit.releaseStorage?.();
497
607
  return 'noData';
498
608
  }
499
609
  const applicationJobOwner = application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, received);
610
+ let result;
611
+ try {
612
+ result = this.processReceived(received, nowMs, applicationJobOwner);
613
+ }
614
+ catch (error) {
615
+ applicationJobOwner.close();
616
+ throw error;
617
+ }
618
+ return result instanceof Promise
619
+ ? result.then((value) => this.finishReceive(received, applicationJobOwner, observe, value), (error) => {
620
+ applicationJobOwner.close();
621
+ throw error;
622
+ })
623
+ : this.finishReceive(received, applicationJobOwner, observe, result);
624
+ }
625
+ finishReceive(received, owner, observe, result) {
500
626
  try {
501
- const result = await this.processReceived(received, nowMs, applicationJobOwner);
502
- if (result === 'protocolError') {
627
+ if (result === 'protocolError')
503
628
  this.reportProtocolError(received);
629
+ if (observe !== undefined) {
630
+ let bytes = 0;
631
+ for (const part of received.parts)
632
+ bytes += part.byteLength;
633
+ observe(received.sourceRid, bytes);
504
634
  }
505
- observe?.(received.sourceRid, received.parts.reduce((sum, part) => sum + part.byteLength, 0));
506
635
  return result;
507
636
  }
508
637
  finally {
509
- applicationJobOwner.close();
638
+ owner.close();
510
639
  }
511
640
  }
512
641
  reportProtocolError(received) {
@@ -545,61 +674,19 @@ class RawServiceMeshRuntime {
545
674
  throw error;
546
675
  }
547
676
  }
548
- async processReceived(received, nowMs, applicationJobOwner) {
549
- if (received.parts.length === 0 ||
550
- (received.parts.length === 1 && received.parts[0].byteLength === 0)) {
551
- if (this.peerAdmissionSealed?.() === true)
552
- return 'dropped';
553
- return (await this.sendControl(received.sourceRid, [
554
- (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
555
- ]))
556
- ? 'infrastructure'
557
- : 'dropped';
558
- }
677
+ processReceived(received, nowMs, applicationJobOwner) {
678
+ const peer = this.topology.admittedPeer(received.sourceRid);
679
+ const currentSource = peer?.liveness !== undefined && peer.liveness.connectionId === received.routeGeneration;
680
+ if (received.parts.length === 0)
681
+ return currentSource ? 'protocolError' : 'dropped';
559
682
  try {
560
683
  const header = (0, service_wire_m6a_codec_1.decodeHeader)(received.parts[0]);
561
684
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello && this.peerAdmissionSealed?.() === true) {
562
685
  return 'dropped';
563
686
  }
564
687
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello ||
565
- header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit ||
566
- header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.update) {
567
- if (received.parts.length !== 1)
568
- return 'protocolError';
569
- const descriptor = (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(received.parts[0], header.command, received.sourceRid);
570
- const expected = this.expectedPeers.get(received.sourceRid);
571
- if (expected !== undefined &&
572
- (expected.meshName !== descriptor.meshName ||
573
- expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
574
- await this.sendControl(received.sourceRid, [
575
- (0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
576
- ]);
577
- return 'infrastructure';
578
- }
579
- const result = this.admitPeer(descriptor, received.routeGeneration, nowMs, expected);
580
- if (result !== 'admitted' && result !== 'notRequired') {
581
- const detail = result === 'invalidDescriptor'
582
- ? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
583
- : undefined;
584
- console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
585
- (detail === undefined ? '.' : ` (${detail}).`));
586
- await this.sendControl(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
587
- return 'infrastructure';
588
- }
589
- if (result === 'admitted')
590
- this.selectBilateralConnection(descriptor);
591
- if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
592
- // Hello supplies only the sender's descriptor. Even NotRequired
593
- // peers must receive ours before the intent owner closes transport;
594
- // submitting a response does not guarantee delivery before close.
595
- await this.sendControl(received.sourceRid, [
596
- (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, this.topology.localDescriptor())
597
- ]);
598
- }
599
- else if (result === 'notRequired') {
600
- this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
601
- }
602
- return 'infrastructure';
688
+ header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
689
+ return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
603
690
  }
604
691
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.reject) {
605
692
  if (received.parts.length !== 1)
@@ -607,47 +694,123 @@ class RawServiceMeshRuntime {
607
694
  (0, service_wire_m6a_codec_1.decodeReject)(received.parts[0]);
608
695
  return 'infrastructure';
609
696
  }
610
- const peer = this.topology.peer(received.sourceRid);
611
- if (peer === undefined)
612
- return 'protocolError';
613
- if (peer.liveness !== undefined && peer.liveness.connectionId === received.routeGeneration)
614
- this.liveness.recordReceived(peer.liveness, nowMs);
697
+ if (!currentSource)
698
+ return 'dropped';
699
+ this.liveness.recordReceived(peer.liveness, nowMs);
700
+ if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.update) {
701
+ return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
702
+ }
615
703
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe ||
616
704
  header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck) {
617
- if (received.parts.length !== 1)
618
- return 'protocolError';
619
- const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
620
- if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
621
- const ack = this.liveness.acknowledgeProbe(received.sourceRid, received.routeGeneration, record.probeId);
622
- if (ack === undefined)
623
- return 'protocolError';
624
- const sent = await this.sendControl(received.sourceRid, [
625
- livenessCodec.encodeLivenessRecord({
626
- command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
627
- probeId: record.probeId
628
- })
629
- ]);
630
- if (!sent)
631
- return 'dropped';
632
- }
633
- else {
634
- this.liveness.acknowledge(received.sourceRid, received.routeGeneration, record.probeId, nowMs);
635
- }
636
- return 'infrastructure';
705
+ return this.processLiveness(received, nowMs).catch((error) => this.receiveProtocolFailure(error));
637
706
  }
638
- const stateful = await this.serviceIngress?.({
639
- command: header.command,
640
- flags: header.flags,
641
- sourceRoutingId: received.sourceRid,
642
- sourceNodeGeneration: peer.descriptor.lifecycleGeneration,
643
- sourceRoute: received.sourceRoute,
644
- ...(received.reply === undefined ? {} : { reply: received.reply }),
645
- ...(received.requestSeq === undefined ? {} : { requestSequence: received.requestSeq }),
646
- parts: received.parts,
647
- applicationJobOwner
648
- });
707
+ const stateful = this.serviceIngress !== undefined && this.serviceIngressAccepts?.(header.command) !== false
708
+ ? this.serviceIngress({
709
+ command: header.command,
710
+ flags: header.flags,
711
+ sourceRoutingId: received.sourceRid,
712
+ sourceNodeGeneration: peer.descriptor.lifecycleGeneration,
713
+ sourceRoute: received.sourceRoute,
714
+ ...(received.reply === undefined ? {} : { reply: received.reply }),
715
+ ...(received.requestSeq === undefined
716
+ ? {}
717
+ : { requestSequence: received.requestSeq }),
718
+ parts: received.parts,
719
+ applicationJobOwner
720
+ })
721
+ : undefined;
722
+ if (stateful instanceof Promise)
723
+ return stateful.then((result) => result ?? this.processApplicationReceived(received, header, applicationJobOwner), (error) => this.receiveProtocolFailure(error));
649
724
  if (stateful !== undefined)
650
725
  return stateful;
726
+ return this.processApplicationReceived(received, header, applicationJobOwner);
727
+ }
728
+ catch (error) {
729
+ if (!currentSource && error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
730
+ return 'dropped';
731
+ return this.receiveProtocolFailure(error);
732
+ }
733
+ }
734
+ receiveProtocolFailure(error) {
735
+ if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
736
+ return 'protocolError';
737
+ throw error;
738
+ }
739
+ async processAdmission(received, header, nowMs) {
740
+ if (received.parts.length !== 1)
741
+ return 'protocolError';
742
+ const descriptor = (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(received.parts[0], header.command, received.sourceRid);
743
+ const expected = this.expectedPeers.get(received.sourceRid);
744
+ if (expected !== undefined &&
745
+ (expected.meshName !== descriptor.meshName ||
746
+ expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
747
+ await this.sendControl(received.sourceRid, [
748
+ (0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
749
+ ]);
750
+ return 'infrastructure';
751
+ }
752
+ const helloKey = controlSendKey(received.sourceRid, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
753
+ const exchange = this.controlSends.get(helloKey);
754
+ const result = this.admitPeer(descriptor, received.routeGeneration, nowMs, expected, header.command, received.parts[0].subarray(service_wire_binary_primitives_1.SERVICE_WIRE_PREFIX_SIZE));
755
+ if (result !== 'admitted' && result !== 'notRequired') {
756
+ const detail = result === 'invalidDescriptor'
757
+ ? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
758
+ : undefined;
759
+ console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
760
+ (detail === undefined ? '.' : ` (${detail}).`));
761
+ await this.sendControl(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
762
+ return 'infrastructure';
763
+ }
764
+ if (result === 'admitted')
765
+ this.selectBilateralConnection(descriptor);
766
+ if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
767
+ // Hello supplies only the sender's descriptor. Even NotRequired
768
+ // peers must receive ours before the intent owner closes transport;
769
+ // submitting a response does not guarantee delivery before close.
770
+ const local = exchange?.current?.() === true && exchange.hello !== undefined
771
+ ? (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(exchange.hello, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.descriptor.nodeRoutingId)
772
+ : this.topology.localDescriptor();
773
+ await this.sendControl(received.sourceRid, [
774
+ (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, local)
775
+ ]);
776
+ }
777
+ else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
778
+ this.controlSends.delete(helloKey);
779
+ this.refreshAdmissionPending(nowMs);
780
+ if (result === 'notRequired') {
781
+ this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
782
+ }
783
+ else if (exchange?.hello !== undefined &&
784
+ (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(exchange.hello, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.descriptor.nodeRoutingId).descriptorRevision < this.descriptor.descriptorRevision) {
785
+ await this.publishLocalDescriptor([received.sourceRid]);
786
+ }
787
+ }
788
+ return 'infrastructure';
789
+ }
790
+ async processLiveness(received, nowMs) {
791
+ if (received.parts.length !== 1)
792
+ return 'protocolError';
793
+ const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
794
+ if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
795
+ const ack = this.liveness.acknowledgeProbe(received.sourceRid, received.routeGeneration, record.probeId);
796
+ if (ack === undefined)
797
+ return 'protocolError';
798
+ const sent = await this.sendControl(received.sourceRid, [
799
+ livenessCodec.encodeLivenessRecord({
800
+ command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
801
+ probeId: record.probeId
802
+ })
803
+ ]);
804
+ if (!sent)
805
+ return 'dropped';
806
+ }
807
+ else {
808
+ this.liveness.acknowledge(received.sourceRid, received.routeGeneration, record.probeId, nowMs);
809
+ }
810
+ return 'infrastructure';
811
+ }
812
+ processApplicationReceived(received, header, applicationJobOwner) {
813
+ try {
651
814
  if (header.flags === 0 &&
652
815
  // A bare infrastructure control is normally exactly one frame, but a
653
816
  // relocation Prepare now rides its bound-session journal as
@@ -663,7 +826,7 @@ class RawServiceMeshRuntime {
663
826
  received.parts.length >= 1 &&
664
827
  isBareInfrastructureControl(header.command)) {
665
828
  const accepted = this.mailbox.tryEnqueue({
666
- owner: `node:${this.descriptor.nodeRoutingId}`,
829
+ owner: this.nodeMailboxOwner,
667
830
  domain: 'infrastructure',
668
831
  parts: received.parts,
669
832
  sourceRoutingId: received.sourceRid,
@@ -675,62 +838,60 @@ class RawServiceMeshRuntime {
675
838
  }
676
839
  if (header.flags !== 0 ||
677
840
  received.parts.length !== 2 ||
678
- ![
679
- service_wire_m6a_codec_1.M6aServiceWireCommand.nodeSend,
680
- service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest,
681
- service_wire_m6a_codec_1.M6aServiceWireCommand.channelSend,
682
- service_wire_m6a_codec_1.M6aServiceWireCommand.channelRequest
683
- ].includes(header.command)) {
841
+ !isApplicationEnvelopeCommand(header.command)) {
684
842
  return 'protocolError';
685
843
  }
686
844
  let owner;
687
845
  let correlation;
688
846
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeSend) {
689
- owner = `node:${this.descriptor.nodeRoutingId}`;
847
+ owner = this.nodeMailboxOwner;
690
848
  }
691
849
  else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest) {
692
- owner = `node:${this.descriptor.nodeRoutingId}`;
693
- correlation = (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0]);
850
+ owner = this.nodeMailboxOwner;
851
+ correlation = (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0], header);
694
852
  }
695
853
  else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.channelSend) {
696
- owner = `channel:${(0, service_wire_m6a_codec_1.decodeChannelSendHeader)(received.parts[0])}`;
854
+ owner = `channel:${(0, service_wire_m6a_codec_1.decodeChannelSendHeader)(received.parts[0], header)}`;
697
855
  }
698
856
  else {
699
- const channel = (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0]);
857
+ const channel = (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0], header);
700
858
  owner = `channel:${channel.channelName}`;
701
859
  correlation = channel.correlation;
702
860
  }
703
- const applicationJob = await applicationJobOwner.acquire('application');
704
- const accepted = this.mailbox.tryEnqueue({
705
- owner,
706
- domain: 'application',
707
- parts: received.parts,
861
+ const job = applicationJobOwner.acquire('application');
862
+ return job instanceof Promise
863
+ ? job.then((permit) => this.enqueueOrdinaryRecord(received, owner, correlation, permit))
864
+ : this.enqueueOrdinaryRecord(received, owner, correlation, job);
865
+ }
866
+ catch (error) {
867
+ return this.receiveProtocolFailure(error);
868
+ }
869
+ }
870
+ enqueueOrdinaryRecord(received, owner, correlation, applicationJob) {
871
+ const accepted = this.mailbox.tryEnqueue({
872
+ owner,
873
+ domain: 'application',
874
+ parts: received.parts,
875
+ sourceRoutingId: received.sourceRid,
876
+ sourceRoute: received.sourceRoute,
877
+ reply: received.reply,
878
+ requestSequence: received.requestSeq,
879
+ correlation,
880
+ applicationJob
881
+ });
882
+ if (accepted)
883
+ return 'application';
884
+ applicationJob.close();
885
+ if (correlation !== undefined && received.requestSeq !== undefined) {
886
+ this.replyService({
708
887
  sourceRoutingId: received.sourceRid,
709
888
  sourceRoute: received.sourceRoute,
710
- ...(received.reply === undefined ? {} : { reply: received.reply }),
711
889
  requestSequence: received.requestSeq,
712
- ...(correlation === undefined ? {} : { correlation }),
713
- applicationJob
714
- });
715
- if (accepted)
716
- return 'application';
717
- applicationJob.close();
718
- if (correlation !== undefined && received.requestSeq !== undefined) {
719
- this.replyService({
720
- sourceRoutingId: received.sourceRid,
721
- sourceRoute: received.sourceRoute,
722
- requestSequence: received.requestSeq,
723
- ...(received.reply === undefined ? {} : { reply: received.reply })
724
- }, [(0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.NotConnected, 0)]);
725
- return 'infrastructure';
726
- }
727
- return 'dropped';
728
- }
729
- catch (error) {
730
- if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
731
- return 'protocolError';
732
- throw error;
890
+ ...(received.reply === undefined ? {} : { reply: received.reply })
891
+ }, [(0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.NotConnected, 0)]);
892
+ return 'infrastructure';
733
893
  }
894
+ return 'dropped';
734
895
  }
735
896
  expireOperations(nowMs, turnDeadlineMs) {
736
897
  return this.operations.expire(nowMs, turnDeadlineMs);
@@ -738,9 +899,38 @@ class RawServiceMeshRuntime {
738
899
  get pendingOperationCount() {
739
900
  return this.operations.size;
740
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
+ }
741
927
  tickLiveness(nowMs = performance.now()) {
928
+ const admissionDue = this.liveness.tickAdmission(nowMs);
742
929
  const result = this.liveness.tick(nowMs);
743
930
  this.requireStarted();
931
+ if (admissionDue)
932
+ for (const nodeRoutingId of this.selectedRoutes.keys())
933
+ void this.announcePeer(nodeRoutingId);
744
934
  for (const probe of result.probes) {
745
935
  const parts = [
746
936
  livenessCodec.encodeLivenessRecord({
@@ -777,10 +967,8 @@ class RawServiceMeshRuntime {
777
967
  for (const [nodeRoutingId, generation] of this.selectedRoutes) {
778
968
  if (observed.get(nodeRoutingId) === generation)
779
969
  continue;
970
+ this.controlSends.delete(controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello));
780
971
  changes++;
781
- const expected = this.expectedPeers.get(nodeRoutingId);
782
- if (expected !== undefined)
783
- delete expected.helloSubmittedGeneration;
784
972
  const peer = this.topology.peer(nodeRoutingId);
785
973
  if (peer?.liveness?.connectionId === generation) {
786
974
  this.removePeer(peer);
@@ -795,9 +983,12 @@ class RawServiceMeshRuntime {
795
983
  selected.push(nodeRoutingId);
796
984
  }
797
985
  this.selectedRoutes = observed;
986
+ for (const nodeRoutingId of selected)
987
+ this.notifyPeerRouteChanged(nodeRoutingId);
798
988
  // A new selected route admits only through a new handshake.
799
989
  for (const nodeRoutingId of selected)
800
990
  await this.announcePeer(nodeRoutingId);
991
+ this.refreshAdmissionPending(performance.now());
801
992
  return changes;
802
993
  }
803
994
  close() {
@@ -806,9 +997,11 @@ class RawServiceMeshRuntime {
806
997
  this.closed = true;
807
998
  this.applicationJobStop.abort(new Error('Raw service runtime application job admission stopped.'));
808
999
  this.receivePermit?.releaseAfterInternalProcessing();
1000
+ this.receivePermit?.releaseStorage?.();
809
1001
  this.receivePermit = undefined;
810
1002
  for (const send of this.controlSends.values())
811
1003
  delete send.next;
1004
+ this.controlSends.clear();
812
1005
  this.mailbox.close();
813
1006
  this.operations.close('Raw service runtime closed.');
814
1007
  this.serviceIngress = undefined;
@@ -822,13 +1015,12 @@ class RawServiceMeshRuntime {
822
1015
  this.router = undefined;
823
1016
  this.host = undefined;
824
1017
  }
825
- requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName) {
1018
+ requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted, observer, operationKind) {
826
1019
  const correlation = this.nextCorrelation++;
827
1020
  const header = channelName === undefined
828
1021
  ? (0, service_wire_m6a_codec_1.encodeNodeRequestHeader)(correlation)
829
1022
  : (0, service_wire_m6a_codec_1.encodeChannelRequestHeader)(correlation, channelName);
830
1023
  const encodedPayload = this.applicationFrame(payload);
831
- const pending = this.operations.register(timeoutMs);
832
1024
  let selectedTargetNodeRoutingId = targetNodeRoutingId;
833
1025
  if (selectedTargetNodeRoutingId !== this.descriptor.nodeRoutingId &&
834
1026
  !this.isPeerRouteReady(selectedTargetNodeRoutingId)) {
@@ -855,6 +1047,9 @@ class RawServiceMeshRuntime {
855
1047
  }
856
1048
  }
857
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);
858
1053
  const parts = [header, encodedPayload];
859
1054
  const capacityStop = new AbortController();
860
1055
  void pending.promise.finally(() => capacityStop.abort()).catch(() => undefined);
@@ -888,6 +1083,9 @@ class RawServiceMeshRuntime {
888
1083
  failureCode: 0
889
1084
  });
890
1085
  }
1086
+ else {
1087
+ onAdmitted?.();
1088
+ }
891
1089
  }
892
1090
  finally {
893
1091
  applicationJobOwner.close();
@@ -895,12 +1093,13 @@ class RawServiceMeshRuntime {
895
1093
  })().catch((error) => this.operations.fail(pending.id, error));
896
1094
  return pending;
897
1095
  }
898
- const selectedPeer = this.topology.peer(selectedTargetNodeRoutingId);
1096
+ const pending = this.registerRequest(timeoutMs, observer, operationKind);
1097
+ const selectedPeer = this.topology.admittedPeer(selectedTargetNodeRoutingId);
899
1098
  if (selectedPeer === undefined) {
900
1099
  // Logical target selection is the requester's decision: an RID that is
901
1100
  // not an admitted peer is not a target. Whether an admitted target's
902
1101
  // route can carry the request is Core's REQUEST result.
903
- this.operations.complete(pending.id, {
1102
+ this.completeRequest(pending, {
904
1103
  terminalResult: runtime_values_1.RequestResult.NotFound,
905
1104
  failureCode: REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
906
1105
  });
@@ -909,10 +1108,10 @@ class RawServiceMeshRuntime {
909
1108
  const parts = [header, encodedPayload];
910
1109
  let request;
911
1110
  try {
912
- request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived);
1111
+ request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived, onAdmitted);
913
1112
  }
914
1113
  catch (error) {
915
- this.operations.fail(pending.id, error);
1114
+ this.failRequest(pending, error);
916
1115
  return pending;
917
1116
  }
918
1117
  void request.then((replyParts) => {
@@ -958,24 +1157,22 @@ class RawServiceMeshRuntime {
958
1157
  applicationPayload(payload) {
959
1158
  return Buffer.isBuffer(payload) ? (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payload) : payload;
960
1159
  }
961
- admitPeer(descriptor, connectionId, nowMs, expected) {
1160
+ admitPeer(descriptor, connectionId, nowMs, expected, command = service_wire_m6a_codec_1.M6aServiceWireCommand.hello, descriptorBytes) {
962
1161
  const previous = this.topology.peer(descriptor.nodeRoutingId);
963
- if (previous !== undefined &&
964
- previous.descriptor.lifecycleGeneration === descriptor.lifecycleGeneration &&
965
- (descriptor.descriptorRevision < previous.descriptor.descriptorRevision ||
966
- (descriptor.descriptorRevision === previous.descriptor.descriptorRevision &&
967
- !(0, service_topology_registry_1.sameServiceNodeDescriptor)(previous.descriptor, descriptor)))) {
968
- throw new service_wire_m6a_codec_1.ServiceWireProtocolError(`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`);
969
- }
970
- const topologyConnectionId = typeof connectionId === 'bigint' ? `route:${connectionId}` : connectionId;
1162
+ const topologyConnectionId = typeof connectionId === 'bigint' ? routeConnectionId(connectionId) : connectionId;
971
1163
  const result = this.topology.admit(descriptor, topologyConnectionId, expected, () => {
972
1164
  const admission = this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
973
1165
  this.liveness.recordReceived(admission, nowMs);
974
1166
  return admission;
975
- });
1167
+ }, command, descriptorBytes);
1168
+ if (result === 'staleDescriptor') {
1169
+ throw new service_wire_m6a_codec_1.ServiceWireProtocolError(`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`);
1170
+ }
976
1171
  if (result === 'notRequired' && previous !== undefined) {
977
1172
  this.liveness.disconnect(descriptor.nodeRoutingId, previous.liveness?.connectionId ?? previous.connectionId);
978
1173
  }
1174
+ if (result === 'admitted')
1175
+ this.notifyPeerRouteChanged(descriptor.nodeRoutingId);
979
1176
  return result;
980
1177
  }
981
1178
  retireNotRequiredExpectedPeer(nodeRoutingId, advertisedEndpoint) {
@@ -1020,7 +1217,7 @@ class RawServiceMeshRuntime {
1020
1217
  async sendControl(targetNodeRoutingId, parts) {
1021
1218
  return this.startControlSend(targetNodeRoutingId, (0, service_wire_m6a_codec_1.decodeHeader)(parts[0]).command, () => this.submitControl(targetNodeRoutingId, parts));
1022
1219
  }
1023
- submitControl(target, parts, accepted) {
1220
+ submitControl(target, parts) {
1024
1221
  let submission;
1025
1222
  try {
1026
1223
  submission = this.requireStarted().submitSend(target, parts);
@@ -1028,19 +1225,17 @@ class RawServiceMeshRuntime {
1028
1225
  catch (error) {
1029
1226
  return this.sendFailure(error);
1030
1227
  }
1031
- if (submission.result === runtime_values_1.SubmitResult.Ok) {
1032
- accepted?.();
1033
- return true;
1034
- }
1035
- return submission.admitted.then(() => {
1036
- accepted?.();
1228
+ if (submission.result === runtime_values_1.SubmitResult.Ok)
1037
1229
  return true;
1038
- }, (error) => this.sendFailure(error));
1230
+ return submission.admitted.then(() => true, (error) => this.sendFailure(error));
1039
1231
  }
1040
- startControlSend(target, command, attempt, current) {
1041
- const key = JSON.stringify([target, command]);
1232
+ startControlSend(target, command, attempt, current, hello) {
1233
+ const key = controlSendKey(target, command);
1234
+ if (command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello)
1235
+ this.liveness.setAdmissionPending(true, performance.now());
1042
1236
  const existing = this.controlSends.get(key);
1043
1237
  if (existing !== undefined &&
1238
+ existing.task !== undefined &&
1044
1239
  (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello || existing.current?.() === true)) {
1045
1240
  if (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
1046
1241
  existing.next = attempt;
@@ -1049,35 +1244,45 @@ class RawServiceMeshRuntime {
1049
1244
  return true;
1050
1245
  }
1051
1246
  const first = attempt();
1052
- if (typeof first === 'boolean')
1247
+ if (typeof first === 'boolean') {
1248
+ if (hello !== undefined)
1249
+ this.controlSends.set(key, { current, hello });
1053
1250
  return first;
1251
+ }
1054
1252
  const owner = this;
1055
- const state = {
1056
- current,
1057
- task: first.then(function drain(accepted) {
1058
- if (!owner.closed && state.next !== undefined) {
1059
- const next = state.next;
1060
- delete state.next;
1061
- return Promise.resolve(next()).then(drain);
1062
- }
1063
- if (owner.controlSends.get(key) === state)
1064
- owner.controlSends.delete(key);
1065
- return accepted;
1066
- })
1253
+ const state = { current, hello };
1254
+ const completeSend = () => {
1255
+ if (owner.controlSends.get(key) !== state)
1256
+ return;
1257
+ if (hello !== undefined && current?.() === true)
1258
+ delete state.task;
1259
+ else
1260
+ owner.controlSends.delete(key);
1067
1261
  };
1068
- this.controlSends.set(key, state);
1069
- state.task.then(() => { }, (error) => {
1070
- if (this.controlSends.get(key) === state)
1071
- this.controlSends.delete(key);
1072
- if (this.infrastructureTaskRunner === undefined)
1073
- this.reportInfrastructureFailure(error);
1262
+ const task = first.then(function drain(accepted) {
1263
+ if (!owner.closed && state.next !== undefined) {
1264
+ const next = state.next;
1265
+ delete state.next;
1266
+ return Promise.resolve(next()).then(drain);
1267
+ }
1268
+ completeSend();
1269
+ return accepted;
1074
1270
  });
1075
- this.infrastructureTaskRunner?.runDetached('RouteMesh control SEND', async () => {
1076
- await state.task;
1271
+ state.task = task;
1272
+ this.controlSends.set(key, state);
1273
+ task.then(() => { }, (error) => {
1274
+ completeSend();
1275
+ this.reportInfrastructureFailure(error);
1077
1276
  });
1078
1277
  return true;
1079
1278
  }
1080
1279
  reportInfrastructureFailure(error) {
1280
+ if (this.infrastructureTaskRunner !== undefined) {
1281
+ this.infrastructureTaskRunner.runDetached('RouteMesh infrastructure', async () => {
1282
+ throw error;
1283
+ });
1284
+ return;
1285
+ }
1081
1286
  this.infrastructureFailure = {
1082
1287
  error: this.infrastructureFailure === undefined
1083
1288
  ? error
@@ -1092,13 +1297,15 @@ class RawServiceMeshRuntime {
1092
1297
  throw failure.error;
1093
1298
  }
1094
1299
  send(targetNodeRoutingId, parts) {
1095
- return this.requireStarted()
1096
- .send(targetNodeRoutingId, parts)
1097
- .then(() => {
1098
- return true;
1099
- }, (error) => {
1300
+ try {
1301
+ const submission = this.requireStarted().submitSend(targetNodeRoutingId, parts);
1302
+ if (submission.result === runtime_values_1.SubmitResult.Ok)
1303
+ return true;
1304
+ return submission.admitted.then(() => true, (error) => this.sendFailure(error));
1305
+ }
1306
+ catch (error) {
1100
1307
  return this.sendFailure(error);
1101
- });
1308
+ }
1102
1309
  }
1103
1310
  sendFailure(error) {
1104
1311
  if ((0, runtime_values_1.isZLinkBackendResultError)(error) && error.operation === 'submit') {
@@ -1110,25 +1317,38 @@ class RawServiceMeshRuntime {
1110
1317
  }
1111
1318
  }
1112
1319
  exports.RawServiceMeshRuntime = RawServiceMeshRuntime;
1320
+ function controlSendKey(target, command) {
1321
+ return `${command}:${target}`;
1322
+ }
1323
+ function routeConnectionId(generation) {
1324
+ return `route:${generation}`;
1325
+ }
1113
1326
  /**
1114
1327
  * Relocation and bound-Session controls are service-wire records themselves,
1115
1328
  * not application NodeSend(16) envelopes. Keep this list closed: a bare
1116
1329
  * record outside the frozen control vocabulary remains a protocol error.
1117
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
+ ]);
1118
1344
  function isBareInfrastructureControl(command) {
1119
- return [
1120
- service_wire_constants_generated_1.ServiceWireCommand.relocationReady,
1121
- service_wire_constants_generated_1.ServiceWireCommand.relocationData,
1122
- service_wire_constants_generated_1.ServiceWireCommand.replyRelay,
1123
- service_wire_constants_generated_1.ServiceWireCommand.relocationCutover,
1124
- service_wire_constants_generated_1.ServiceWireCommand.relocationPrepare,
1125
- service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationSeal,
1126
- service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationSealed,
1127
- service_wire_constants_generated_1.ServiceWireCommand.sessionRelocationRoute,
1128
- service_wire_constants_generated_1.ServiceWireCommand.replyRelayAck,
1129
- service_wire_constants_generated_1.ServiceWireCommand.relocationState,
1130
- service_wire_constants_generated_1.ServiceWireCommand.relocationFailed
1131
- ].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);
1132
1352
  }
1133
1353
  function protocolCommand(parts) {
1134
1354
  if (parts.length === 0)