@zlink-systems/framework 0.29.1 → 0.30.1

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 (322) 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/ZLinkMessageMetadata.js +11 -5
  6. package/dist/contracts/Configuration/Builders.d.ts +1 -2
  7. package/dist/contracts/Configuration/Configs.d.ts +0 -5
  8. package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
  9. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
  10. package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
  11. package/dist/contracts/Configuration/index.d.ts +1 -1
  12. package/dist/contracts/Handlers/Attributes.d.ts +5 -13
  13. package/dist/contracts/Handlers/Attributes.js +7 -11
  14. package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
  15. package/dist/contracts/Handlers/JsonContract.js +4 -153
  16. package/dist/contracts/Spots/Contracts.d.ts +2 -1
  17. package/dist/internal.d.ts +1 -0
  18. package/dist/internal.js +3 -1
  19. package/dist/nest-integration.d.ts +1 -1
  20. package/dist/nest-integration.js +2 -1
  21. package/dist/runtime/actors/actor-client.d.ts +1 -1
  22. package/dist/runtime/actors/actor-client.js +14 -12
  23. package/dist/runtime/actors/actor-handoff.d.ts +3 -2
  24. package/dist/runtime/actors/actor-handoff.js +15 -7
  25. package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
  26. package/dist/runtime/actors/actor-local-native-join.js +9 -12
  27. package/dist/runtime/actors/actor-remote-wire.js +15 -0
  28. package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
  29. package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
  30. package/dist/runtime/actors/index.d.ts +2 -1
  31. package/dist/runtime/actors/index.js +18 -6
  32. package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
  33. package/dist/runtime/admission.d.ts +1 -1
  34. package/dist/runtime/admission.js +15 -5
  35. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +9 -9
  36. package/dist/runtime/application-jobs/application-ingress-record-owner.js +45 -23
  37. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +5 -2
  38. package/dist/runtime/application-jobs/application-job-queue-scope.js +41 -21
  39. package/dist/runtime/application-jobs/contracts.d.ts +15 -2
  40. package/dist/runtime/backend/contracts/index.d.ts +27 -27
  41. package/dist/runtime/backend/mesh-completion-table.d.ts +15 -5
  42. package/dist/runtime/backend/mesh-completion-table.js +160 -50
  43. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
  44. package/dist/runtime/backend/mesh-dispatch-pump.js +53 -36
  45. package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
  46. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
  47. package/dist/runtime/backend/node/node-backend-adapter-support.js +33 -31
  48. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  49. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
  50. package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
  51. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
  52. package/dist/runtime/backend/node/node-raw-binding-port.js +50 -25
  53. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +22 -16
  54. package/dist/runtime/backend/node/node-raw-mesh-backend.js +133 -149
  55. package/dist/runtime/backend/node/node-socket-backend-adapter.js +15 -10
  56. package/dist/runtime/backend/raw-binding-port.d.ts +10 -3
  57. package/dist/runtime/backend/runtime-message.d.ts +1 -0
  58. package/dist/runtime/backend/runtime-message.js +5 -0
  59. package/dist/runtime/backend/runtime-values.d.ts +1 -0
  60. package/dist/runtime/backend/runtime-values.js +2 -1
  61. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  62. package/dist/runtime/channels/channel-clients.js +58 -21
  63. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
  64. package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
  65. package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
  66. package/dist/runtime/channels/channel-dispatch-services.js +45 -0
  67. package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
  68. package/dist/runtime/channels/channel-dispatchers.js +27 -26
  69. package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
  70. package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
  71. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  72. package/dist/runtime/channels/channel-envelope.js +83 -8
  73. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  74. package/dist/runtime/channels/channel-outbound-operations.js +8 -8
  75. package/dist/runtime/channels/channel-receive-loops.js +3 -3
  76. package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
  77. package/dist/runtime/channels/channel-runtime-manager.d.ts +6 -6
  78. package/dist/runtime/channels/channel-runtime-manager.js +12 -12
  79. package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
  80. package/dist/runtime/channels/channel-socket-registry.js +59 -82
  81. package/dist/runtime/channels/channel-transports.d.ts +18 -15
  82. package/dist/runtime/channels/channel-transports.js +48 -31
  83. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  84. package/dist/runtime/channels/local-spot-route-transport.js +2 -1
  85. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
  86. package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
  87. package/dist/runtime/channels/source-spot-router.d.ts +2 -2
  88. package/dist/runtime/channels/source-spot-router.js +4 -4
  89. package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
  90. package/dist/runtime/channels/spot-node-route-transport.js +4 -4
  91. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
  92. package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
  93. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
  94. package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
  95. package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
  96. package/dist/runtime/diagnostics/message-flow.js +3 -3
  97. package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
  98. package/dist/runtime/execution/serial-execution-queue.js +1 -0
  99. package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
  100. package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
  101. package/dist/runtime/foundation/durable-service-request.js +98 -0
  102. package/dist/runtime/foundation/operation-identity.d.ts +1 -0
  103. package/dist/runtime/foundation/operation-identity.js +5 -1
  104. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +37 -6
  105. package/dist/runtime/foundation/raw-service-mesh-runtime.js +473 -220
  106. package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
  107. package/dist/runtime/foundation/service-liveness-registry.js +57 -44
  108. package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
  109. package/dist/runtime/foundation/service-mailbox.js +2 -1
  110. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +1 -0
  111. package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
  112. package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
  113. package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
  114. package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
  115. package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -9
  116. package/dist/runtime/foundation/service-stateful-runtime.js +78 -126
  117. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -7
  118. package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
  119. package/dist/runtime/foundation/service-topology-registry.d.ts +16 -4
  120. package/dist/runtime/foundation/service-topology-registry.js +69 -30
  121. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
  122. package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
  123. package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
  124. package/dist/runtime/handlers/handler-instance-scope.js +54 -11
  125. package/dist/runtime/host/actor-packet-relay.js +7 -7
  126. package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
  127. package/dist/runtime/host/application-job-queue.d.ts +28 -9
  128. package/dist/runtime/host/application-job-queue.js +214 -50
  129. package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
  130. package/dist/runtime/host/entry-actor-runtime.js +4 -1
  131. package/dist/runtime/host/index.d.ts +7 -1
  132. package/dist/runtime/host/index.js +154 -126
  133. package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
  134. package/dist/runtime/host/instance-activation-authority.js +89 -25
  135. package/dist/runtime/host/remote-bound-session-relay.js +2 -18
  136. package/dist/runtime/host/route-mesh-runtime.js +1 -1
  137. package/dist/runtime/host/service-relocation-control.d.ts +1 -0
  138. package/dist/runtime/host/service-relocation-control.js +10 -4
  139. package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
  140. package/dist/runtime/host/service-relocation-host-runtime.js +215 -243
  141. package/dist/runtime/host/spot-address-transport.d.ts +1 -0
  142. package/dist/runtime/host/spot-address-transport.js +28 -14
  143. package/dist/runtime/host/spot-runtime-options-factory.js +3 -2
  144. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
  145. package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
  146. package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
  147. package/dist/runtime/locations/actor-location-claims.js +34 -19
  148. package/dist/runtime/locations/domain-store-contract.d.ts +2 -2
  149. package/dist/runtime/locations/in-memory-authority-store.d.ts +4 -2
  150. package/dist/runtime/locations/in-memory-authority-store.js +80 -8
  151. package/dist/runtime/locations/in-memory-location-store.d.ts +2 -2
  152. package/dist/runtime/locations/in-memory-location-store.js +19 -3
  153. package/dist/runtime/locations/internal-location-contracts.d.ts +3 -0
  154. package/dist/runtime/locations/lifecycle.d.ts +1 -2
  155. package/dist/runtime/locations/lifecycle.js +2 -5
  156. package/dist/runtime/locations/location-store-repository.d.ts +3 -2
  157. package/dist/runtime/locations/location-store-repository.js +165 -22
  158. package/dist/runtime/locations/resolvers.d.ts +2 -1
  159. package/dist/runtime/locations/resolvers.js +10 -1
  160. package/dist/runtime/locations/runtime.d.ts +1 -1
  161. package/dist/runtime/locations/runtime.js +24 -23
  162. package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
  163. package/dist/runtime/messaging/framework-json-v1.js +38 -294
  164. package/dist/runtime/messaging/packet-name.d.ts +1 -1
  165. package/dist/runtime/messaging/packet-name.js +8 -24
  166. package/dist/runtime/messaging/request-result.d.ts +2 -0
  167. package/dist/runtime/messaging/request-result.js +54 -0
  168. package/dist/runtime/messaging/submission-result.d.ts +2 -1
  169. package/dist/runtime/messaging/submission-result.js +7 -4
  170. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
  171. package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
  172. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
  173. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
  174. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +9 -2
  175. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
  176. package/dist/runtime/spots/index.d.ts +7 -3
  177. package/dist/runtime/spots/index.js +23 -16
  178. package/dist/runtime/spots/spot-activation.d.ts +3 -1
  179. package/dist/runtime/spots/spot-activation.js +21 -12
  180. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
  181. package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
  182. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
  183. package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
  184. package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
  185. package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
  186. package/dist/runtime/spots/spot-entry-activation.js +9 -3
  187. package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
  188. package/dist/runtime/spots/spot-handler-registry.js +18 -8
  189. package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
  190. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +2 -1
  191. package/dist/runtime/spots/spot-node-runtime-manager.js +4 -11
  192. package/dist/runtime/spots/spot-outbound.d.ts +3 -0
  193. package/dist/runtime/spots/spot-outbound.js +24 -15
  194. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
  195. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
  196. package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
  197. package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -1
  198. package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
  199. package/dist/runtime/spots/spot-timer.js +1 -0
  200. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
  201. package/dist/runtime/streams/stream-session-runtime.js +14 -28
  202. package/package.json +3 -3
  203. package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
  204. package/src/contracts/Channels/Calls.ts +2 -1
  205. package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
  206. package/src/contracts/Configuration/Builders.ts +1 -2
  207. package/src/contracts/Configuration/Configs.ts +0 -6
  208. package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
  209. package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
  210. package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
  211. package/src/contracts/Configuration/index.ts +1 -6
  212. package/src/contracts/Handlers/Attributes.ts +14 -21
  213. package/src/contracts/Handlers/JsonContract.ts +8 -216
  214. package/src/contracts/Spots/Contracts.ts +2 -1
  215. package/src/internal.ts +1 -0
  216. package/src/nest-integration.ts +1 -0
  217. package/src/runtime/actors/actor-client.ts +40 -16
  218. package/src/runtime/actors/actor-handoff.ts +22 -8
  219. package/src/runtime/actors/actor-join-relocation.ts +1 -0
  220. package/src/runtime/actors/actor-local-native-join.ts +17 -26
  221. package/src/runtime/actors/actor-remote-wire.ts +17 -0
  222. package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
  223. package/src/runtime/actors/actor-routed-json-request.ts +10 -2
  224. package/src/runtime/actors/index.ts +19 -5
  225. package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
  226. package/src/runtime/admission.ts +18 -5
  227. package/src/runtime/application-jobs/application-ingress-record-owner.ts +53 -27
  228. package/src/runtime/application-jobs/application-job-queue-scope.ts +56 -22
  229. package/src/runtime/application-jobs/contracts.ts +28 -2
  230. package/src/runtime/backend/contracts/index.ts +63 -32
  231. package/src/runtime/backend/mesh-completion-table.ts +175 -59
  232. package/src/runtime/backend/mesh-dispatch-pump.ts +59 -32
  233. package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
  234. package/src/runtime/backend/node/node-backend-adapter-support.ts +42 -31
  235. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
  236. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
  237. package/src/runtime/backend/node/node-raw-binding-port.ts +73 -37
  238. package/src/runtime/backend/node/node-raw-mesh-backend.ts +209 -176
  239. package/src/runtime/backend/node/node-socket-backend-adapter.ts +32 -13
  240. package/src/runtime/backend/raw-binding-port.ts +18 -3
  241. package/src/runtime/backend/runtime-message.ts +6 -0
  242. package/src/runtime/backend/runtime-values.ts +1 -0
  243. package/src/runtime/channels/channel-clients.ts +90 -41
  244. package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
  245. package/src/runtime/channels/channel-dispatch-services.ts +69 -1
  246. package/src/runtime/channels/channel-dispatchers.ts +29 -27
  247. package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
  248. package/src/runtime/channels/channel-envelope.ts +133 -8
  249. package/src/runtime/channels/channel-outbound-operations.ts +22 -8
  250. package/src/runtime/channels/channel-receive-loops.ts +3 -3
  251. package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
  252. package/src/runtime/channels/channel-runtime-manager.ts +29 -12
  253. package/src/runtime/channels/channel-socket-registry.ts +84 -130
  254. package/src/runtime/channels/channel-transports.ts +128 -60
  255. package/src/runtime/channels/local-spot-route-transport.ts +3 -1
  256. package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
  257. package/src/runtime/channels/source-spot-router.ts +8 -4
  258. package/src/runtime/channels/spot-node-route-transport.ts +8 -4
  259. package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
  260. package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
  261. package/src/runtime/diagnostics/message-flow.ts +1 -1
  262. package/src/runtime/execution/serial-execution-queue.ts +2 -0
  263. package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
  264. package/src/runtime/foundation/durable-service-request.ts +137 -0
  265. package/src/runtime/foundation/operation-identity.ts +5 -1
  266. package/src/runtime/foundation/raw-service-mesh-runtime.ts +642 -253
  267. package/src/runtime/foundation/service-liveness-registry.ts +68 -59
  268. package/src/runtime/foundation/service-mailbox.ts +7 -1
  269. package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
  270. package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
  271. package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
  272. package/src/runtime/foundation/service-stateful-runtime.ts +128 -160
  273. package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -84
  274. package/src/runtime/foundation/service-topology-registry.ts +103 -42
  275. package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
  276. package/src/runtime/handlers/handler-instance-scope.ts +67 -16
  277. package/src/runtime/host/actor-packet-relay.ts +7 -0
  278. package/src/runtime/host/actor-runtime-options-factory.ts +14 -2
  279. package/src/runtime/host/application-job-queue.ts +249 -48
  280. package/src/runtime/host/entry-actor-runtime.ts +5 -0
  281. package/src/runtime/host/index.ts +224 -160
  282. package/src/runtime/host/instance-activation-authority.ts +132 -27
  283. package/src/runtime/host/remote-bound-session-relay.ts +2 -23
  284. package/src/runtime/host/route-mesh-runtime.ts +1 -1
  285. package/src/runtime/host/service-relocation-control.ts +11 -5
  286. package/src/runtime/host/service-relocation-host-runtime.ts +317 -291
  287. package/src/runtime/host/spot-address-transport.ts +49 -24
  288. package/src/runtime/host/spot-runtime-options-factory.ts +4 -0
  289. package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
  290. package/src/runtime/locations/actor-location-claims.ts +52 -30
  291. package/src/runtime/locations/domain-store-contract.ts +6 -2
  292. package/src/runtime/locations/in-memory-authority-store.ts +113 -9
  293. package/src/runtime/locations/in-memory-location-store.ts +25 -3
  294. package/src/runtime/locations/internal-location-contracts.ts +4 -0
  295. package/src/runtime/locations/lifecycle.ts +8 -26
  296. package/src/runtime/locations/location-store-repository.ts +220 -15
  297. package/src/runtime/locations/resolvers.ts +25 -2
  298. package/src/runtime/locations/runtime.ts +28 -24
  299. package/src/runtime/messaging/framework-json-v1.ts +5 -325
  300. package/src/runtime/messaging/packet-name.ts +5 -25
  301. package/src/runtime/messaging/request-result.ts +58 -0
  302. package/src/runtime/messaging/submission-result.ts +7 -3
  303. package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
  304. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  305. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +45 -23
  306. package/src/runtime/spots/index.ts +30 -2
  307. package/src/runtime/spots/spot-activation.ts +33 -10
  308. package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
  309. package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
  310. package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
  311. package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
  312. package/src/runtime/spots/spot-entry-activation.ts +12 -2
  313. package/src/runtime/spots/spot-handler-registry.ts +41 -8
  314. package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
  315. package/src/runtime/spots/spot-node-runtime-manager.ts +7 -12
  316. package/src/runtime/spots/spot-outbound.ts +36 -16
  317. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
  318. package/src/runtime/spots/spot-routing-internal.ts +14 -0
  319. package/src/runtime/spots/spot-runtime-ports.ts +3 -0
  320. package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
  321. package/src/runtime/spots/spot-timer.ts +5 -1
  322. package/src/runtime/streams/stream-session-runtime.ts +13 -30
@@ -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,8 +47,16 @@ class RawServiceMeshRuntime {
44
47
  selectedRoutes = new Map();
45
48
  bindingPort;
46
49
  applicationJobQueue;
50
+ nodeMailboxOwner;
47
51
  peerAdmissionSealed;
48
52
  applicationJobStop = new AbortController();
53
+ receiveAcquisition;
54
+ receivePermit;
55
+ receiveRotation;
56
+ controlSends = new Map();
57
+ infrastructureFailure;
58
+ onReceiveReady;
59
+ infrastructureTaskRunner;
49
60
  onPeerNotRequired;
50
61
  onPeerDisconnected;
51
62
  onProtocolError;
@@ -56,10 +67,14 @@ class RawServiceMeshRuntime {
56
67
  router;
57
68
  nextCorrelation = 1n;
58
69
  serviceIngress;
70
+ serviceIngressAccepts;
59
71
  closed = false;
60
72
  constructor(options) {
73
+ this.onReceiveReady = options.onReceiveReady;
74
+ this.infrastructureTaskRunner = options.infrastructureTaskRunner;
61
75
  this.operations = new operation_registry_1.OperationRegistry(undefined, options.onPendingOperationsChanged);
62
76
  this.descriptor = options.descriptor;
77
+ this.nodeMailboxOwner = `node:${options.descriptor.nodeRoutingId}`;
63
78
  this.topology = new service_topology_registry_1.ServiceTopologyRegistry(options.descriptor);
64
79
  this.mailbox = new service_mailbox_1.ServiceMailbox(options.onMailboxReady);
65
80
  this.liveness = new service_liveness_registry_1.ServiceLivenessRegistry(options.probeIntervalMs, options.peerTimeoutMs);
@@ -214,6 +229,30 @@ class RawServiceMeshRuntime {
214
229
  this.peerConnectionIntentRemoved.delete(listener);
215
230
  };
216
231
  }
232
+ observePeerRoute(nodeRoutingId) {
233
+ const selected = this.selectedRoutes.get(nodeRoutingId);
234
+ const admitted = this.topology.admittedPeer(nodeRoutingId)?.liveness?.connectionId;
235
+ return {
236
+ generation: selected ?? (typeof admitted === 'bigint' ? admitted : undefined),
237
+ ready: admitted !== undefined && (selected === undefined || admitted === selected)
238
+ };
239
+ }
240
+ get requestStopSignal() {
241
+ return this.applicationJobStop.signal;
242
+ }
243
+ observePeerRouteChanged(listener) {
244
+ this.peerRouteChanged.add(listener);
245
+ return () => {
246
+ this.peerRouteChanged.delete(listener);
247
+ };
248
+ }
249
+ hasSelectedPeerRoute(nodeRoutingId) {
250
+ return this.selectedRoutes.has(nodeRoutingId);
251
+ }
252
+ notifyPeerRouteChanged(nodeRoutingId) {
253
+ for (const listener of this.peerRouteChanged)
254
+ listener(nodeRoutingId);
255
+ }
217
256
  notifyPeerConnectionIntentRemoved(nodeRoutingId) {
218
257
  // Only the logical owner's removal publishes lifecycle termination.
219
258
  // A physical disconnect alone retains the connection expectation.
@@ -222,31 +261,35 @@ class RawServiceMeshRuntime {
222
261
  for (const listener of this.peerConnectionIntentRemoved)
223
262
  listener(nodeRoutingId);
224
263
  }
225
- async announcePeer(nodeRoutingId) {
226
- const expected = this.expectedPeers.get(nodeRoutingId);
264
+ announcePeer(nodeRoutingId) {
227
265
  const generation = this.selectedRoutes.get(nodeRoutingId);
228
- if (expected === undefined ||
229
- generation === undefined ||
230
- expected.helloSubmittedGeneration === generation ||
231
- this.peerAdmissionSealed?.() === true)
232
- return false;
233
- const accepted = await this.send(nodeRoutingId, [
234
- (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
235
- ]);
236
- if (accepted &&
237
- this.expectedPeers.get(nodeRoutingId) === expected &&
238
- this.selectedRoutes.get(nodeRoutingId) === generation)
239
- expected.helloSubmittedGeneration = generation;
240
- return accepted;
266
+ if (generation === undefined)
267
+ return Promise.resolve(false);
268
+ const current = () => {
269
+ const admission = this.topology.routeAdmission(nodeRoutingId);
270
+ return (this.selectedRoutes.get(nodeRoutingId) === generation &&
271
+ !(admission?.connectionId === routeConnectionId(generation) &&
272
+ admission.remoteAdmitReceived === true) &&
273
+ this.peerAdmissionSealed?.() !== true);
274
+ };
275
+ const key = controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
276
+ if (!current()) {
277
+ this.controlSends.delete(key);
278
+ return Promise.resolve(false);
279
+ }
280
+ const existing = this.controlSends.get(key);
281
+ const hello = existing?.current?.() === true
282
+ ? existing.hello
283
+ : (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor());
284
+ return Promise.resolve(this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [hello]), current, hello));
241
285
  }
242
286
  isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
243
287
  // Admission is bound to the observed selected route: the route observer
244
288
  // removes the peer when that route ends or is replaced.
245
- const peer = this.topology.peer(nodeRoutingId);
289
+ const peer = this.topology.admittedPeer(nodeRoutingId);
246
290
  return (peer !== undefined &&
247
291
  (lifecycleGeneration === undefined ||
248
- peer.descriptor.lifecycleGeneration === lifecycleGeneration) &&
249
- this.liveness.isReady(nodeRoutingId, peer.connectionId));
292
+ peer.descriptor.lifecycleGeneration === lifecycleGeneration));
250
293
  }
251
294
  async announceExpectedPeers() {
252
295
  let accepted = 0;
@@ -280,22 +323,22 @@ class RawServiceMeshRuntime {
280
323
  // placement and channel selectors therefore need the new mutable fields
281
324
  // on that same connection before the next request is selected; waiting for
282
325
  // a reconnect would leave a race where a drained node is selected again.
326
+ await this.publishLocalDescriptor(this.topology.peers().map((peer) => peer.descriptor.nodeRoutingId));
327
+ }
328
+ async publishLocalDescriptor(targets) {
283
329
  const update = (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.update, this.topology.localDescriptor());
284
- for (const peer of this.topology.peers()) {
285
- await this.send(peer.descriptor.nodeRoutingId, [update]);
330
+ for (const target of targets) {
331
+ await this.sendService(target, [update]);
286
332
  }
287
333
  }
288
334
  replaceDiscoveredNotRequired(descriptors) {
289
335
  this.topology.replaceDiscoveredNotRequired(descriptors);
290
336
  }
291
337
  isObjectClientNodeDirectTarget(nodeRoutingId) {
292
- const descriptor = nodeRoutingId === this.descriptor.nodeRoutingId
293
- ? this.topology.localDescriptor()
294
- : this.topology.knownDescriptor(nodeRoutingId);
295
- return descriptor?.objectRole === 'client';
338
+ return this.topology.isObjectClientNodeDirectTarget(nodeRoutingId);
296
339
  }
297
- async sendToNode(targetNodeRoutingId, payload) {
298
- return this.send(targetNodeRoutingId, [(0, service_wire_m6a_codec_1.encodeNodeSendHeader)(), this.applicationFrame(payload)]);
340
+ sendToNode(targetNodeRoutingId, payload) {
341
+ return this.send(targetNodeRoutingId, [NODE_SEND_HEADER, this.applicationFrame(payload)]);
299
342
  }
300
343
  async sendToChannel(channelName, payload) {
301
344
  const selection = this.selectChannelTarget(channelName);
@@ -310,17 +353,17 @@ class RawServiceMeshRuntime {
310
353
  ? runtime_values_1.SubmitResult.Ok
311
354
  : runtime_values_1.SubmitResult.NotConnected;
312
355
  }
313
- requestToNode(targetNodeRoutingId, payload, timeoutMs) {
314
- return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs);
356
+ requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted) {
357
+ return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted);
315
358
  }
316
- requestToChannel(channelName, payload, timeoutMs) {
359
+ requestToChannel(channelName, payload, timeoutMs, onAdmitted) {
317
360
  const selection = this.selectChannelTarget(channelName);
318
361
  if (selection.kind !== 'selected') {
319
362
  const pending = this.operations.register(timeoutMs);
320
363
  this.operations.complete(pending.id, selection.requestResult);
321
364
  return pending;
322
365
  }
323
- return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName);
366
+ return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName, onAdmitted);
324
367
  }
325
368
  selectChannelTarget(channelName) {
326
369
  const selected = this.topology.selectChannel(channelName, (peer) => this.isPeerRouteReady(peer.descriptor.nodeRoutingId));
@@ -341,24 +384,32 @@ class RawServiceMeshRuntime {
341
384
  }
342
385
  };
343
386
  }
344
- setServiceIngress(handler) {
387
+ setServiceIngress(handler, accepts) {
345
388
  if (this.serviceIngress !== undefined && this.serviceIngress !== handler) {
346
389
  throw new Error('Raw service ingress is already registered.');
347
390
  }
348
391
  this.serviceIngress = handler;
392
+ this.serviceIngressAccepts = accepts;
349
393
  }
350
394
  async reserveLocalIngress(signal) {
351
395
  const waitSignal = signal === undefined
352
396
  ? this.applicationJobStop.signal
353
397
  : AbortSignal.any([this.applicationJobStop.signal, signal]);
354
- const permit = await this.applicationJobQueue.acquire(waitSignal);
398
+ const permit = await this.applicationJobQueue.acquire(waitSignal, 'local');
355
399
  return application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, { close() { } });
356
400
  }
357
401
  async sendService(targetNodeRoutingId, parts) {
358
- return this.send(targetNodeRoutingId, parts);
402
+ try {
403
+ await this.requireStarted().send(targetNodeRoutingId, parts);
404
+ return true;
405
+ }
406
+ catch (error) {
407
+ return this.sendFailure(error);
408
+ }
359
409
  }
360
- requestService(targetNodeRoutingId, parts, timeoutMs) {
361
- return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs);
410
+ requestService(targetNodeRoutingId, parts, timeoutMs, onAdmitted) {
411
+ const admission = this.topology.admittedPeer(targetNodeRoutingId)?.liveness;
412
+ return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, admission?.recordReceived, onAdmitted);
362
413
  }
363
414
  replyService(record, parts) {
364
415
  if (record.requestSequence === undefined) {
@@ -383,6 +434,22 @@ class RawServiceMeshRuntime {
383
434
  ]);
384
435
  }
385
436
  async pumpOne(nowMs = performance.now(), observe) {
437
+ const result = await this.receiveOne(nowMs, observe);
438
+ const acquisition = this.receiveAcquisition;
439
+ if (acquisition === undefined)
440
+ return result;
441
+ // A single receive operation may await its FIFO grant. Infrastructure
442
+ // rounds use receiveOne directly and end while that grant is pending.
443
+ try {
444
+ await acquisition;
445
+ }
446
+ catch (error) {
447
+ if (this.closed)
448
+ return 'noData';
449
+ throw error;
450
+ }
451
+ if (this.closed)
452
+ return 'noData';
386
453
  return this.receiveOne(nowMs, observe);
387
454
  }
388
455
  setReadableHandler(handler) {
@@ -390,6 +457,7 @@ class RawServiceMeshRuntime {
390
457
  }
391
458
  /** Returns whether a receive budget ended before no-data; idle ticks only maintain peers. */
392
459
  async pumpBatch(receiveReady = true, routeReady = false) {
460
+ this.observeInfrastructureFailure();
393
461
  if (routeReady)
394
462
  await this.observeSelectedRoutes();
395
463
  const startedAtMs = performance.now();
@@ -398,38 +466,72 @@ class RawServiceMeshRuntime {
398
466
  const observe = (_source, byteCount) => {
399
467
  bytes += byteCount;
400
468
  };
401
- while (receiveReady && messages < RAW_MESH_RECEIVE_RECORD_BUDGET && !this.closed) {
402
- const result = await this.receiveOne(performance.now(), observe);
403
- if (result === 'noData') {
404
- receiveReady = false;
405
- break;
469
+ const rotation = (this.receiveRotation ??= this.applicationJobQueue.createReceiveRotation(RAW_MESH_RECEIVE_RECORD_BUDGET, 'remote'));
470
+ if (receiveReady)
471
+ rotation.reserve();
472
+ try {
473
+ while (receiveReady && messages < RAW_MESH_RECEIVE_RECORD_BUDGET && !this.closed) {
474
+ const received = this.receiveOne(performance.now(), observe, rotation);
475
+ const result = received instanceof Promise ? await received : received;
476
+ if (result === 'noData') {
477
+ receiveReady = false;
478
+ break;
479
+ }
480
+ messages += 1;
481
+ // Core owns the per-peer fair-queue cursor. The Framework limit bounds
482
+ // the entire round, so changing peers does not renew its byte/count budget.
483
+ if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
484
+ performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
485
+ break;
406
486
  }
407
- messages += 1;
408
- // Core owns the per-peer fair-queue cursor. The Framework limit bounds
409
- // the entire round, so changing peers does not renew its byte/count budget.
410
- if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
411
- performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
412
- break;
487
+ }
488
+ finally {
489
+ rotation.releaseUnused();
413
490
  }
414
491
  if (!this.closed) {
415
- await this.announceExpectedPeers();
416
- await this.tickLiveness();
492
+ this.tickLiveness();
417
493
  }
418
494
  return receiveReady && messages > 0;
419
495
  }
420
- async receiveOne(nowMs, observe) {
496
+ receiveOne(nowMs, observe, rotation) {
421
497
  const router = this.requireStarted();
422
- let permit;
423
- try {
424
- permit = await this.applicationJobQueue.acquire(this.applicationJobStop.signal);
425
- }
426
- catch (error) {
427
- if (this.closed || this.applicationJobStop.signal.aborted)
428
- return 'noData';
429
- throw error;
498
+ this.observeInfrastructureFailure();
499
+ let permit = this.receivePermit;
500
+ this.receivePermit = undefined;
501
+ permit ??= rotation?.take();
502
+ if (permit === undefined && this.receiveAcquisition === undefined) {
503
+ let resolveAcquisition;
504
+ let rejectAcquisition;
505
+ permit = this.applicationJobQueue.acquireOrResume((permit) => {
506
+ this.receiveAcquisition = undefined;
507
+ if (this.closed) {
508
+ permit.releaseAfterInternalProcessing();
509
+ permit.releaseStorage?.();
510
+ }
511
+ else {
512
+ this.receivePermit = permit;
513
+ this.onReceiveReady?.();
514
+ }
515
+ resolveAcquisition?.(permit);
516
+ }, (error) => rejectAcquisition?.(error), this.applicationJobStop.signal, 'remote');
517
+ if (permit === undefined) {
518
+ const acquisition = new Promise((resolve, reject) => {
519
+ resolveAcquisition = resolve;
520
+ rejectAcquisition = reject;
521
+ });
522
+ this.receiveAcquisition = acquisition;
523
+ acquisition.catch((error) => {
524
+ this.receiveAcquisition = undefined;
525
+ if (!this.applicationJobStop.signal.aborted)
526
+ this.reportInfrastructureFailure(error);
527
+ });
528
+ }
430
529
  }
530
+ if (permit === undefined)
531
+ return 'noData';
431
532
  if (this.closed) {
432
533
  permit.releaseAfterInternalProcessing();
534
+ permit.releaseStorage?.();
433
535
  return 'noData';
434
536
  }
435
537
  let received;
@@ -438,23 +540,44 @@ class RawServiceMeshRuntime {
438
540
  }
439
541
  catch (error) {
440
542
  permit.releaseAfterInternalProcessing();
543
+ permit.releaseStorage?.();
441
544
  throw error;
442
545
  }
443
546
  if (received === undefined) {
444
547
  permit.releaseAfterInternalProcessing();
548
+ permit.releaseStorage?.();
445
549
  return 'noData';
446
550
  }
447
551
  const applicationJobOwner = application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, received);
552
+ let result;
553
+ try {
554
+ result = this.processReceived(received, nowMs, applicationJobOwner);
555
+ }
556
+ catch (error) {
557
+ applicationJobOwner.close();
558
+ throw error;
559
+ }
560
+ return result instanceof Promise
561
+ ? result.then((value) => this.finishReceive(received, applicationJobOwner, observe, value), (error) => {
562
+ applicationJobOwner.close();
563
+ throw error;
564
+ })
565
+ : this.finishReceive(received, applicationJobOwner, observe, result);
566
+ }
567
+ finishReceive(received, owner, observe, result) {
448
568
  try {
449
- const result = await this.processReceived(received, nowMs, applicationJobOwner);
450
- if (result === 'protocolError') {
569
+ if (result === 'protocolError')
451
570
  this.reportProtocolError(received);
571
+ if (observe !== undefined) {
572
+ let bytes = 0;
573
+ for (const part of received.parts)
574
+ bytes += part.byteLength;
575
+ observe(received.sourceRid, bytes);
452
576
  }
453
- observe?.(received.sourceRid, received.parts.reduce((sum, part) => sum + part.byteLength, 0));
454
577
  return result;
455
578
  }
456
579
  finally {
457
- applicationJobOwner.close();
580
+ owner.close();
458
581
  }
459
582
  }
460
583
  reportProtocolError(received) {
@@ -493,61 +616,19 @@ class RawServiceMeshRuntime {
493
616
  throw error;
494
617
  }
495
618
  }
496
- async processReceived(received, nowMs, applicationJobOwner) {
497
- if (received.parts.length === 0 ||
498
- (received.parts.length === 1 && received.parts[0].byteLength === 0)) {
499
- if (this.peerAdmissionSealed?.() === true)
500
- return 'dropped';
501
- return (await this.send(received.sourceRid, [
502
- (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
503
- ]))
504
- ? 'infrastructure'
505
- : 'dropped';
506
- }
619
+ processReceived(received, nowMs, applicationJobOwner) {
620
+ const peer = this.topology.admittedPeer(received.sourceRid);
621
+ const currentSource = peer?.liveness !== undefined && peer.liveness.connectionId === received.routeGeneration;
622
+ if (received.parts.length === 0)
623
+ return currentSource ? 'protocolError' : 'dropped';
507
624
  try {
508
625
  const header = (0, service_wire_m6a_codec_1.decodeHeader)(received.parts[0]);
509
626
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello && this.peerAdmissionSealed?.() === true) {
510
627
  return 'dropped';
511
628
  }
512
629
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello ||
513
- header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit ||
514
- header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.update) {
515
- if (received.parts.length !== 1)
516
- return 'protocolError';
517
- const descriptor = (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(received.parts[0], header.command, received.sourceRid);
518
- const expected = this.expectedPeers.get(received.sourceRid);
519
- if (expected !== undefined &&
520
- (expected.meshName !== descriptor.meshName ||
521
- expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
522
- await this.send(received.sourceRid, [
523
- (0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
524
- ]);
525
- return 'infrastructure';
526
- }
527
- const result = this.admitPeer(descriptor, routeConnectionId(received.routeGeneration), nowMs, expected);
528
- if (result !== 'admitted' && result !== 'notRequired') {
529
- const detail = result === 'invalidDescriptor'
530
- ? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
531
- : undefined;
532
- console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
533
- (detail === undefined ? '.' : ` (${detail}).`));
534
- await this.send(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
535
- return 'infrastructure';
536
- }
537
- if (result === 'admitted')
538
- this.selectBilateralConnection(descriptor);
539
- if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
540
- // Hello supplies only the sender's descriptor. Even NotRequired
541
- // peers must receive ours before the intent owner closes transport;
542
- // submitting a response does not guarantee delivery before close.
543
- await this.send(received.sourceRid, [
544
- (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, this.topology.localDescriptor())
545
- ]);
546
- }
547
- else if (result === 'notRequired') {
548
- this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
549
- }
550
- return 'infrastructure';
630
+ header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
631
+ return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
551
632
  }
552
633
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.reject) {
553
634
  if (received.parts.length !== 1)
@@ -555,45 +636,122 @@ class RawServiceMeshRuntime {
555
636
  (0, service_wire_m6a_codec_1.decodeReject)(received.parts[0]);
556
637
  return 'infrastructure';
557
638
  }
558
- const peer = this.topology.peer(received.sourceRid);
559
- if (peer === undefined)
560
- return 'protocolError';
639
+ if (!currentSource)
640
+ return 'dropped';
641
+ this.liveness.recordReceived(peer.liveness, nowMs);
642
+ if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.update) {
643
+ return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
644
+ }
561
645
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe ||
562
646
  header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck) {
563
- if (received.parts.length !== 1)
564
- return 'protocolError';
565
- const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
566
- if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
567
- const ack = this.liveness.acknowledgeProbe(received.sourceRid, peer.connectionId, record.probeId);
568
- if (ack === undefined)
569
- return 'protocolError';
570
- const sent = await this.send(received.sourceRid, [
571
- livenessCodec.encodeLivenessRecord({
572
- command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
573
- probeId: record.probeId
574
- })
575
- ]);
576
- if (!sent)
577
- return 'dropped';
578
- }
579
- else {
580
- this.liveness.acknowledge(received.sourceRid, peer.connectionId, record.probeId, nowMs);
581
- }
582
- return 'infrastructure';
647
+ return this.processLiveness(received, nowMs).catch((error) => this.receiveProtocolFailure(error));
583
648
  }
584
- const stateful = await this.serviceIngress?.({
585
- command: header.command,
586
- flags: header.flags,
587
- sourceRoutingId: received.sourceRid,
588
- sourceNodeGeneration: peer.descriptor.lifecycleGeneration,
589
- sourceRoute: received.sourceRoute,
590
- ...(received.reply === undefined ? {} : { reply: received.reply }),
591
- ...(received.requestSeq === undefined ? {} : { requestSequence: received.requestSeq }),
592
- parts: received.parts,
593
- applicationJobOwner
594
- });
649
+ const stateful = this.serviceIngress !== undefined && this.serviceIngressAccepts?.(header.command) !== false
650
+ ? this.serviceIngress({
651
+ command: header.command,
652
+ flags: header.flags,
653
+ sourceRoutingId: received.sourceRid,
654
+ sourceNodeGeneration: peer.descriptor.lifecycleGeneration,
655
+ sourceRoute: received.sourceRoute,
656
+ ...(received.reply === undefined ? {} : { reply: received.reply }),
657
+ ...(received.requestSeq === undefined
658
+ ? {}
659
+ : { requestSequence: received.requestSeq }),
660
+ parts: received.parts,
661
+ applicationJobOwner
662
+ })
663
+ : undefined;
664
+ if (stateful instanceof Promise)
665
+ return stateful.then((result) => result ?? this.processApplicationReceived(received, header, applicationJobOwner), (error) => this.receiveProtocolFailure(error));
595
666
  if (stateful !== undefined)
596
667
  return stateful;
668
+ return this.processApplicationReceived(received, header, applicationJobOwner);
669
+ }
670
+ catch (error) {
671
+ if (!currentSource && error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
672
+ return 'dropped';
673
+ return this.receiveProtocolFailure(error);
674
+ }
675
+ }
676
+ receiveProtocolFailure(error) {
677
+ if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
678
+ return 'protocolError';
679
+ throw error;
680
+ }
681
+ async processAdmission(received, header, nowMs) {
682
+ if (received.parts.length !== 1)
683
+ return 'protocolError';
684
+ const descriptor = (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(received.parts[0], header.command, received.sourceRid);
685
+ const expected = this.expectedPeers.get(received.sourceRid);
686
+ if (expected !== undefined &&
687
+ (expected.meshName !== descriptor.meshName ||
688
+ expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
689
+ await this.sendControl(received.sourceRid, [
690
+ (0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
691
+ ]);
692
+ return 'infrastructure';
693
+ }
694
+ const helloKey = controlSendKey(received.sourceRid, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
695
+ const exchange = this.controlSends.get(helloKey);
696
+ const result = this.admitPeer(descriptor, received.routeGeneration, nowMs, expected, header.command, received.parts[0].subarray(service_wire_binary_primitives_1.SERVICE_WIRE_PREFIX_SIZE));
697
+ if (result !== 'admitted' && result !== 'notRequired') {
698
+ const detail = result === 'invalidDescriptor'
699
+ ? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
700
+ : undefined;
701
+ console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
702
+ (detail === undefined ? '.' : ` (${detail}).`));
703
+ await this.sendControl(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
704
+ return 'infrastructure';
705
+ }
706
+ if (result === 'admitted')
707
+ this.selectBilateralConnection(descriptor);
708
+ if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
709
+ // Hello supplies only the sender's descriptor. Even NotRequired
710
+ // peers must receive ours before the intent owner closes transport;
711
+ // submitting a response does not guarantee delivery before close.
712
+ const local = exchange?.current?.() === true && exchange.hello !== undefined
713
+ ? (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(exchange.hello, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.descriptor.nodeRoutingId)
714
+ : this.topology.localDescriptor();
715
+ await this.sendControl(received.sourceRid, [
716
+ (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, local)
717
+ ]);
718
+ }
719
+ else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
720
+ this.controlSends.delete(helloKey);
721
+ if (result === 'notRequired') {
722
+ this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
723
+ }
724
+ else if (exchange?.hello !== undefined &&
725
+ (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(exchange.hello, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.descriptor.nodeRoutingId).descriptorRevision < this.descriptor.descriptorRevision) {
726
+ await this.publishLocalDescriptor([received.sourceRid]);
727
+ }
728
+ }
729
+ return 'infrastructure';
730
+ }
731
+ async processLiveness(received, nowMs) {
732
+ if (received.parts.length !== 1)
733
+ return 'protocolError';
734
+ const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
735
+ if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
736
+ const ack = this.liveness.acknowledgeProbe(received.sourceRid, received.routeGeneration, record.probeId);
737
+ if (ack === undefined)
738
+ return 'protocolError';
739
+ const sent = await this.sendControl(received.sourceRid, [
740
+ livenessCodec.encodeLivenessRecord({
741
+ command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
742
+ probeId: record.probeId
743
+ })
744
+ ]);
745
+ if (!sent)
746
+ return 'dropped';
747
+ }
748
+ else {
749
+ this.liveness.acknowledge(received.sourceRid, received.routeGeneration, record.probeId, nowMs);
750
+ }
751
+ return 'infrastructure';
752
+ }
753
+ processApplicationReceived(received, header, applicationJobOwner) {
754
+ try {
597
755
  if (header.flags === 0 &&
598
756
  // A bare infrastructure control is normally exactly one frame, but a
599
757
  // relocation Prepare now rides its bound-session journal as
@@ -609,7 +767,7 @@ class RawServiceMeshRuntime {
609
767
  received.parts.length >= 1 &&
610
768
  isBareInfrastructureControl(header.command)) {
611
769
  const accepted = this.mailbox.tryEnqueue({
612
- owner: `node:${this.descriptor.nodeRoutingId}`,
770
+ owner: this.nodeMailboxOwner,
613
771
  domain: 'infrastructure',
614
772
  parts: received.parts,
615
773
  sourceRoutingId: received.sourceRid,
@@ -632,51 +790,54 @@ class RawServiceMeshRuntime {
632
790
  let owner;
633
791
  let correlation;
634
792
  if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeSend) {
635
- owner = `node:${this.descriptor.nodeRoutingId}`;
793
+ owner = this.nodeMailboxOwner;
636
794
  }
637
795
  else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest) {
638
- owner = `node:${this.descriptor.nodeRoutingId}`;
639
- correlation = (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0]);
796
+ owner = this.nodeMailboxOwner;
797
+ correlation = (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0], header);
640
798
  }
641
799
  else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.channelSend) {
642
- owner = `channel:${(0, service_wire_m6a_codec_1.decodeChannelSendHeader)(received.parts[0])}`;
800
+ owner = `channel:${(0, service_wire_m6a_codec_1.decodeChannelSendHeader)(received.parts[0], header)}`;
643
801
  }
644
802
  else {
645
- const channel = (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0]);
803
+ const channel = (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0], header);
646
804
  owner = `channel:${channel.channelName}`;
647
805
  correlation = channel.correlation;
648
806
  }
649
- const applicationJob = await applicationJobOwner.acquire('application');
650
- const accepted = this.mailbox.tryEnqueue({
651
- owner,
652
- domain: 'application',
653
- parts: received.parts,
807
+ const job = applicationJobOwner.acquire('application');
808
+ return job instanceof Promise
809
+ ? job.then((permit) => this.enqueueOrdinaryRecord(received, owner, correlation, permit))
810
+ : this.enqueueOrdinaryRecord(received, owner, correlation, job);
811
+ }
812
+ catch (error) {
813
+ return this.receiveProtocolFailure(error);
814
+ }
815
+ }
816
+ enqueueOrdinaryRecord(received, owner, correlation, applicationJob) {
817
+ const accepted = this.mailbox.tryEnqueue({
818
+ owner,
819
+ domain: 'application',
820
+ parts: received.parts,
821
+ sourceRoutingId: received.sourceRid,
822
+ sourceRoute: received.sourceRoute,
823
+ ...(received.reply === undefined ? {} : { reply: received.reply }),
824
+ requestSequence: received.requestSeq,
825
+ ...(correlation === undefined ? {} : { correlation }),
826
+ applicationJob
827
+ });
828
+ if (accepted)
829
+ return 'application';
830
+ applicationJob.close();
831
+ if (correlation !== undefined && received.requestSeq !== undefined) {
832
+ this.replyService({
654
833
  sourceRoutingId: received.sourceRid,
655
834
  sourceRoute: received.sourceRoute,
656
- ...(received.reply === undefined ? {} : { reply: received.reply }),
657
835
  requestSequence: received.requestSeq,
658
- ...(correlation === undefined ? {} : { correlation }),
659
- applicationJob
660
- });
661
- if (accepted)
662
- return 'application';
663
- applicationJob.close();
664
- if (correlation !== undefined && received.requestSeq !== undefined) {
665
- this.replyService({
666
- sourceRoutingId: received.sourceRid,
667
- sourceRoute: received.sourceRoute,
668
- requestSequence: received.requestSeq,
669
- ...(received.reply === undefined ? {} : { reply: received.reply })
670
- }, [(0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.NotConnected, 0)]);
671
- return 'infrastructure';
672
- }
673
- return 'dropped';
674
- }
675
- catch (error) {
676
- if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
677
- return 'protocolError';
678
- throw error;
836
+ ...(received.reply === undefined ? {} : { reply: received.reply })
837
+ }, [(0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.NotConnected, 0)]);
838
+ return 'infrastructure';
679
839
  }
840
+ return 'dropped';
680
841
  }
681
842
  expireOperations(nowMs, turnDeadlineMs) {
682
843
  return this.operations.expire(nowMs, turnDeadlineMs);
@@ -684,22 +845,25 @@ class RawServiceMeshRuntime {
684
845
  get pendingOperationCount() {
685
846
  return this.operations.size;
686
847
  }
687
- async tickLiveness(nowMs = performance.now()) {
848
+ tickLiveness(nowMs = performance.now()) {
688
849
  const result = this.liveness.tick(nowMs);
689
850
  this.requireStarted();
851
+ for (const nodeRoutingId of this.selectedRoutes.keys())
852
+ void this.announcePeer(nodeRoutingId);
690
853
  for (const probe of result.probes) {
691
- await this.send(probe.nodeRoutingId, [
854
+ const parts = [
692
855
  livenessCodec.encodeLivenessRecord({
693
856
  command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe,
694
857
  probeId: probe.probeId
695
858
  })
696
- ]);
859
+ ];
860
+ this.startControlSend(probe.nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe, () => this.submitControl(probe.nodeRoutingId, parts));
697
861
  }
698
862
  for (const nodeRoutingId of result.timedOutNodes) {
699
863
  const peer = this.topology.peer(nodeRoutingId);
700
864
  if (peer === undefined)
701
865
  continue;
702
- // Liveness timeout is a semantic peer removal of the admitted route.
866
+ this.requireStarted().disconnectRid(nodeRoutingId);
703
867
  this.removePeer(peer);
704
868
  }
705
869
  return result;
@@ -722,12 +886,10 @@ class RawServiceMeshRuntime {
722
886
  for (const [nodeRoutingId, generation] of this.selectedRoutes) {
723
887
  if (observed.get(nodeRoutingId) === generation)
724
888
  continue;
889
+ this.controlSends.delete(controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello));
725
890
  changes++;
726
- const expected = this.expectedPeers.get(nodeRoutingId);
727
- if (expected !== undefined)
728
- delete expected.helloSubmittedGeneration;
729
891
  const peer = this.topology.peer(nodeRoutingId);
730
- if (peer !== undefined && peer.connectionId === routeConnectionId(generation)) {
892
+ if (peer?.liveness?.connectionId === generation) {
731
893
  this.removePeer(peer);
732
894
  }
733
895
  }
@@ -740,6 +902,8 @@ class RawServiceMeshRuntime {
740
902
  selected.push(nodeRoutingId);
741
903
  }
742
904
  this.selectedRoutes = observed;
905
+ for (const nodeRoutingId of selected)
906
+ this.notifyPeerRouteChanged(nodeRoutingId);
743
907
  // A new selected route admits only through a new handshake.
744
908
  for (const nodeRoutingId of selected)
745
909
  await this.announcePeer(nodeRoutingId);
@@ -748,7 +912,14 @@ class RawServiceMeshRuntime {
748
912
  close() {
749
913
  if (this.closed)
750
914
  return;
915
+ this.closed = true;
751
916
  this.applicationJobStop.abort(new Error('Raw service runtime application job admission stopped.'));
917
+ this.receivePermit?.releaseAfterInternalProcessing();
918
+ this.receivePermit?.releaseStorage?.();
919
+ this.receivePermit = undefined;
920
+ for (const send of this.controlSends.values())
921
+ delete send.next;
922
+ this.controlSends.clear();
752
923
  this.mailbox.close();
753
924
  this.operations.close('Raw service runtime closed.');
754
925
  this.serviceIngress = undefined;
@@ -761,9 +932,8 @@ class RawServiceMeshRuntime {
761
932
  host.close();
762
933
  this.router = undefined;
763
934
  this.host = undefined;
764
- this.closed = true;
765
935
  }
766
- requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName) {
936
+ requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted) {
767
937
  const correlation = this.nextCorrelation++;
768
938
  const header = channelName === undefined
769
939
  ? (0, service_wire_m6a_codec_1.encodeNodeRequestHeader)(correlation)
@@ -829,6 +999,9 @@ class RawServiceMeshRuntime {
829
999
  failureCode: 0
830
1000
  });
831
1001
  }
1002
+ else {
1003
+ onAdmitted?.();
1004
+ }
832
1005
  }
833
1006
  finally {
834
1007
  applicationJobOwner.close();
@@ -836,7 +1009,8 @@ class RawServiceMeshRuntime {
836
1009
  })().catch((error) => this.operations.fail(pending.id, error));
837
1010
  return pending;
838
1011
  }
839
- if (this.topology.peer(selectedTargetNodeRoutingId) === undefined) {
1012
+ const selectedPeer = this.topology.admittedPeer(selectedTargetNodeRoutingId);
1013
+ if (selectedPeer === undefined) {
840
1014
  // Logical target selection is the requester's decision: an RID that is
841
1015
  // not an admitted peer is not a target. Whether an admitted target's
842
1016
  // route can carry the request is Core's REQUEST result.
@@ -847,11 +1021,9 @@ class RawServiceMeshRuntime {
847
1021
  return pending;
848
1022
  }
849
1023
  const parts = [header, encodedPayload];
850
- let router;
851
1024
  let request;
852
1025
  try {
853
- router = this.requireStarted();
854
- request = router.request(selectedTargetNodeRoutingId, parts, timeoutMs);
1026
+ request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived, onAdmitted);
855
1027
  }
856
1028
  catch (error) {
857
1029
  this.operations.fail(pending.id, error);
@@ -900,23 +1072,22 @@ class RawServiceMeshRuntime {
900
1072
  applicationPayload(payload) {
901
1073
  return Buffer.isBuffer(payload) ? (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payload) : payload;
902
1074
  }
903
- admitPeer(descriptor, connectionId, nowMs, expected) {
1075
+ admitPeer(descriptor, connectionId, nowMs, expected, command = service_wire_m6a_codec_1.M6aServiceWireCommand.hello, descriptorBytes) {
904
1076
  const previous = this.topology.peer(descriptor.nodeRoutingId);
905
- if (previous !== undefined &&
906
- previous.descriptor.lifecycleGeneration === descriptor.lifecycleGeneration &&
907
- (descriptor.descriptorRevision < previous.descriptor.descriptorRevision ||
908
- (descriptor.descriptorRevision === previous.descriptor.descriptorRevision &&
909
- !(0, service_topology_registry_1.sameServiceNodeDescriptor)(previous.descriptor, descriptor)))) {
1077
+ const topologyConnectionId = typeof connectionId === 'bigint' ? routeConnectionId(connectionId) : connectionId;
1078
+ const result = this.topology.admit(descriptor, topologyConnectionId, expected, () => {
1079
+ const admission = this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
1080
+ this.liveness.recordReceived(admission, nowMs);
1081
+ return admission;
1082
+ }, command, descriptorBytes);
1083
+ if (result === 'staleDescriptor') {
910
1084
  throw new service_wire_m6a_codec_1.ServiceWireProtocolError(`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`);
911
1085
  }
912
- const result = this.topology.admit(descriptor, connectionId, expected);
913
- if (result === 'admitted') {
914
- this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
915
- this.liveness.requestProbe(descriptor.nodeRoutingId, connectionId, nowMs);
916
- }
917
- else if (result === 'notRequired' && previous !== undefined) {
918
- this.liveness.disconnect(descriptor.nodeRoutingId, previous.connectionId);
1086
+ if (result === 'notRequired' && previous !== undefined) {
1087
+ this.liveness.disconnect(descriptor.nodeRoutingId, previous.liveness?.connectionId ?? previous.connectionId);
919
1088
  }
1089
+ if (result === 'admitted')
1090
+ this.notifyPeerRouteChanged(descriptor.nodeRoutingId);
920
1091
  return result;
921
1092
  }
922
1093
  retireNotRequiredExpectedPeer(nodeRoutingId, advertisedEndpoint) {
@@ -950,7 +1121,7 @@ class RawServiceMeshRuntime {
950
1121
  }
951
1122
  removePeer(peer) {
952
1123
  this.topology.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
953
- this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
1124
+ this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.liveness?.connectionId ?? peer.connectionId);
954
1125
  this.onPeerDisconnected?.(peer.descriptor.nodeRoutingId, peer.descriptor.advertisedEndpoint, peer.descriptor.lifecycleGeneration);
955
1126
  }
956
1127
  requireStarted() {
@@ -958,22 +1129,111 @@ class RawServiceMeshRuntime {
958
1129
  throw new Error('Raw service runtime is not started.');
959
1130
  return this.router;
960
1131
  }
961
- async send(targetNodeRoutingId, parts) {
1132
+ async sendControl(targetNodeRoutingId, parts) {
1133
+ return this.startControlSend(targetNodeRoutingId, (0, service_wire_m6a_codec_1.decodeHeader)(parts[0]).command, () => this.submitControl(targetNodeRoutingId, parts));
1134
+ }
1135
+ submitControl(target, parts) {
1136
+ let submission;
962
1137
  try {
963
- await this.requireStarted().send(targetNodeRoutingId, parts);
964
- return true;
1138
+ submission = this.requireStarted().submitSend(target, parts);
965
1139
  }
966
1140
  catch (error) {
967
- if ((0, runtime_values_1.isZLinkBackendResultError)(error) && error.operation === 'submit') {
968
- const terminal = (0, submission_result_1.submitToRequestResult)(error.result, error.phase);
969
- if (terminal === runtime_values_1.RequestResult.NotConnected || terminal === runtime_values_1.RequestResult.NotFound)
970
- return false;
1141
+ return this.sendFailure(error);
1142
+ }
1143
+ if (submission.result === runtime_values_1.SubmitResult.Ok)
1144
+ return true;
1145
+ return submission.admitted.then(() => true, (error) => this.sendFailure(error));
1146
+ }
1147
+ startControlSend(target, command, attempt, current, hello) {
1148
+ const key = controlSendKey(target, command);
1149
+ const existing = this.controlSends.get(key);
1150
+ if (existing !== undefined &&
1151
+ existing.task !== undefined &&
1152
+ (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello || existing.current?.() === true)) {
1153
+ if (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
1154
+ existing.next = attempt;
1155
+ existing.current = current;
971
1156
  }
972
- throw error;
1157
+ return true;
1158
+ }
1159
+ const first = attempt();
1160
+ if (typeof first === 'boolean') {
1161
+ if (hello !== undefined)
1162
+ this.controlSends.set(key, { current, hello });
1163
+ return first;
1164
+ }
1165
+ const owner = this;
1166
+ const state = { current, hello };
1167
+ const completeSend = () => {
1168
+ if (owner.controlSends.get(key) !== state)
1169
+ return;
1170
+ if (hello !== undefined && current?.() === true)
1171
+ delete state.task;
1172
+ else
1173
+ owner.controlSends.delete(key);
1174
+ };
1175
+ const task = first.then(function drain(accepted) {
1176
+ if (!owner.closed && state.next !== undefined) {
1177
+ const next = state.next;
1178
+ delete state.next;
1179
+ return Promise.resolve(next()).then(drain);
1180
+ }
1181
+ completeSend();
1182
+ return accepted;
1183
+ });
1184
+ state.task = task;
1185
+ this.controlSends.set(key, state);
1186
+ task.then(() => { }, (error) => {
1187
+ completeSend();
1188
+ if (this.infrastructureTaskRunner === undefined)
1189
+ this.reportInfrastructureFailure(error);
1190
+ });
1191
+ this.infrastructureTaskRunner?.runDetached('RouteMesh control SEND', async () => {
1192
+ await task;
1193
+ });
1194
+ return true;
1195
+ }
1196
+ reportInfrastructureFailure(error) {
1197
+ this.infrastructureFailure = {
1198
+ error: this.infrastructureFailure === undefined
1199
+ ? error
1200
+ : new AggregateError([this.infrastructureFailure.error, error], 'RouteMesh infrastructure failed.')
1201
+ };
1202
+ this.onReceiveReady?.();
1203
+ }
1204
+ observeInfrastructureFailure() {
1205
+ const failure = this.infrastructureFailure;
1206
+ this.infrastructureFailure = undefined;
1207
+ if (failure !== undefined)
1208
+ throw failure.error;
1209
+ }
1210
+ send(targetNodeRoutingId, parts) {
1211
+ try {
1212
+ const submission = this.requireStarted().submitSend(targetNodeRoutingId, parts);
1213
+ if (submission.result === runtime_values_1.SubmitResult.Ok)
1214
+ return true;
1215
+ return submission.admitted.then(() => true, (error) => this.sendFailure(error));
973
1216
  }
1217
+ catch (error) {
1218
+ return this.sendFailure(error);
1219
+ }
1220
+ }
1221
+ sendFailure(error) {
1222
+ if ((0, runtime_values_1.isZLinkBackendResultError)(error) && error.operation === 'submit') {
1223
+ const terminal = (0, submission_result_1.submitToRequestResult)(error.result, error.phase);
1224
+ if (terminal === runtime_values_1.RequestResult.NotConnected || terminal === runtime_values_1.RequestResult.NotFound)
1225
+ return false;
1226
+ }
1227
+ throw error;
974
1228
  }
975
1229
  }
976
1230
  exports.RawServiceMeshRuntime = RawServiceMeshRuntime;
1231
+ function controlSendKey(target, command) {
1232
+ return JSON.stringify([target, command]);
1233
+ }
1234
+ function routeConnectionId(generation) {
1235
+ return `route:${generation}`;
1236
+ }
977
1237
  /**
978
1238
  * Relocation and bound-Session controls are service-wire records themselves,
979
1239
  * not application NodeSend(16) envelopes. Keep this list closed: a bare
@@ -1010,13 +1270,6 @@ function isAlreadyDisconnectedError(error) {
1010
1270
  }
1011
1271
  return error.nativeErrno === nativeErrnoValues.ENOENT;
1012
1272
  }
1013
- /**
1014
- * An admission belongs to one Core selected route. Its connection identity is
1015
- * that route's generation, an opaque token compared only for equality.
1016
- */
1017
- function routeConnectionId(routeGeneration) {
1018
- return `route:${routeGeneration.toString()}`;
1019
- }
1020
1273
  function describeInvalidAdmissionDescriptor(descriptor, expected, current) {
1021
1274
  try {
1022
1275
  (0, service_topology_registry_1.validateDescriptor)(descriptor);