@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
@@ -1,5 +1,4 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { ZLinkConfigurationException } from '../configuration';
3
2
  import { isAbortError } from '../abort';
4
3
  import {
5
4
  ZLinkFrameworkInternalErrorKind,
@@ -53,6 +52,7 @@ export class ZLinkSpotSerialTurn {
53
52
  private suspendedResolve: (() => void) | undefined;
54
53
  private suspendedPromise: Promise<void> | undefined;
55
54
  private suspendSignaled = false;
55
+ private yieldUsed = false;
56
56
  private owner: Promise<unknown> | undefined;
57
57
  private frameworkOperationsBlocked = false;
58
58
 
@@ -115,26 +115,41 @@ export class ZLinkSpotSerialTurn {
115
115
  }
116
116
 
117
117
  resetSuspension(): void {
118
+ this.yieldUsed = false;
118
119
  this.suspendSignaled = false;
119
120
  this.suspendedResolve = undefined;
120
121
  this.suspendedPromise = undefined;
121
122
  }
122
123
 
123
- async yieldPromise<T>(pending: Promise<T>): Promise<T> {
124
- if (!this.yieldAllowed) {
125
- throw new ZLinkConfigurationException(
126
- 'yield requires a SpotWide User Spot or Instance Spot application handler.'
124
+ admitYield(): void {
125
+ const current = spotSerialTurnStorage.getStore();
126
+ if (
127
+ current?.turn !== this ||
128
+ !this.yieldAllowed ||
129
+ !current.executor.isActiveTurn(this, current.turnId) ||
130
+ this.yieldUsed
131
+ ) {
132
+ throw createInternalFrameworkException(
133
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
134
+ 'Yield requires the current SpotWide application turn and may be used only once per turn.'
127
135
  );
128
136
  }
137
+ this.yieldUsed = true;
138
+ }
139
+
140
+ async yieldPromise<T>(pending: Promise<T>): Promise<T> {
141
+ this.admitYield();
129
142
  return await this.yieldFrameworkPromise(pending);
130
143
  }
131
144
 
132
145
  /** Suspends a turn only for a Framework-owned lifecycle boundary. */
133
146
  async yieldFrameworkPromise<T>(pending: Promise<T>): Promise<T> {
134
147
  this.signalSuspended();
135
- const result = await pending;
136
- await this.awaitResumePermit();
137
- return result;
148
+ try {
149
+ return await pending;
150
+ } finally {
151
+ await this.awaitResumePermit();
152
+ }
138
153
  }
139
154
 
140
155
  async resumeOwnerUntilNextYield(): Promise<void> {
@@ -204,16 +219,18 @@ export function currentZLinkSpotSerialSourceId(): unknown {
204
219
 
205
220
  export function requireZLinkYieldTurn(capturedTurn?: ZLinkSpotSerialTurn): ZLinkSpotSerialTurn {
206
221
  const turn = capturedTurn ?? captureZLinkSpotSerialTurn();
207
- if (turn === undefined || !turn.yieldAllowed) {
208
- throw new ZLinkConfigurationException(
209
- 'yield requires a SpotWide User Spot or Instance Spot application handler.'
222
+ if (turn === undefined) {
223
+ throw createInternalFrameworkException(
224
+ ZLinkFrameworkInternalErrorKind.InvalidOperation,
225
+ 'Yield requires a current SpotWide application turn.'
210
226
  );
211
227
  }
228
+ turn.admitYield();
212
229
  return turn;
213
230
  }
214
231
 
215
232
  export interface ZLinkCapturedExecutionTurn {
216
- yieldPromise<T>(pending: Promise<T>): Promise<T>;
233
+ yieldPromise<T>(operation: () => Promise<T>): Promise<T>;
217
234
  post(callback: () => void): void;
218
235
  }
219
236
 
@@ -223,7 +240,16 @@ export function captureZLinkExecutionTurn(): ZLinkCapturedExecutionTurn | undefi
223
240
  return undefined;
224
241
  }
225
242
  return {
226
- yieldPromise: <T>(pending: Promise<T>) => current.turn.yieldPromise(pending),
243
+ yieldPromise: <T>(operation: () => Promise<T>) => {
244
+ const turn = requireZLinkYieldTurn(current.turn);
245
+ let pending: Promise<T>;
246
+ try {
247
+ pending = operation();
248
+ } catch (error) {
249
+ pending = Promise.reject(error);
250
+ }
251
+ return turn.yieldFrameworkPromise(pending);
252
+ },
227
253
  post: (callback: () => void) => {
228
254
  void current.executor.post(callback);
229
255
  }
@@ -241,7 +267,7 @@ export function isCurrentZLinkSpotSerialTurn(executor: ZLinkSpotSerialTurnExecut
241
267
 
242
268
  export interface ZLinkExecutionBarrierSeal {
243
269
  readonly generation: bigint;
244
- readonly kind: 'close' | 'relocation';
270
+ readonly kind: 'close' | 'relocation' | 'activation';
245
271
  }
246
272
 
247
273
  export interface ZLinkExecutionBarrierClaim {
@@ -1,6 +1,7 @@
1
1
  import { macrotaskBoundary } from '../abort';
2
2
  import {
3
3
  diagnosticWorkName,
4
+ startOutsideStateLane,
4
5
  guardStateLaneCompletion,
5
6
  isStructuralGuardEnabled,
6
7
  trackDiagnosticCompletion
@@ -9,6 +10,9 @@ import {
9
10
  export type ZLinkSerialWorkLane = 'application' | 'lifecycle';
10
11
 
11
12
  export interface ZLinkSerialWorkOptions {
13
+ readonly onAdmitted?: () => void;
14
+ /** Transfers an unstarted durable record out of this FIFO in the owner turn. */
15
+ readonly onWithdrawable?: (withdraw: () => boolean) => void;
12
16
  readonly lane?: ZLinkSerialWorkLane;
13
17
  readonly payloadBytes?: number;
14
18
  readonly metadataBytes?: number;
@@ -166,12 +170,22 @@ export class ZLinkSerialExecutionQueue {
166
170
  return this.admit(operation, { lane: 'lifecycle' }, context, undefined, true);
167
171
  }
168
172
 
173
+ get retainsApplicationForLifecycle(): boolean {
174
+ return this.activeLifecycle?.context !== undefined;
175
+ }
176
+
169
177
  visitPendingApplication(visitor: (record: ZLinkSerialWorkRecord<unknown>) => void): void {
170
178
  for (const record of this.application.records) {
171
179
  if (record.mailbox === undefined) visitor(record);
172
180
  }
173
181
  }
174
182
 
183
+ get hasPendingDurableApplication(): boolean {
184
+ // Every application record accepted behind durable work inherits durable
185
+ // ownership, so the tail answers this without scanning the FIFO.
186
+ return this.application.records.at(-1)?.preparation !== undefined;
187
+ }
188
+
175
189
  get hasPendingWork(): boolean {
176
190
  return (
177
191
  this.consumer?.running === true ||
@@ -269,6 +283,19 @@ export class ZLinkSerialExecutionQueue {
269
283
  release();
270
284
  throw error;
271
285
  }
286
+ options.onAdmitted?.();
287
+ options.onWithdrawable?.(() => {
288
+ const index = target.records.indexOf(record as SerialWorkRecord<unknown>);
289
+ if (index < 0) return false;
290
+ target.records.splice(index, 1);
291
+ record.preparationController?.abort(
292
+ new Error('Durable record transferred to another handoff.')
293
+ );
294
+ record.preparation?.cancel();
295
+ resolve(undefined as T);
296
+ release();
297
+ return true;
298
+ });
272
299
  this.scheduleDrain();
273
300
  return result;
274
301
  }
@@ -284,10 +311,12 @@ export class ZLinkSerialExecutionQueue {
284
311
  const consumer = this.consumer!;
285
312
  if (consumer.scheduled || consumer.running) return;
286
313
  consumer.scheduled = true;
287
- queueMicrotask(() => {
288
- consumer.scheduled = false;
289
- void this.drain();
290
- });
314
+ startOutsideStateLane(() =>
315
+ queueMicrotask(() => {
316
+ consumer.scheduled = false;
317
+ void this.drain();
318
+ })
319
+ );
291
320
  }
292
321
 
293
322
  /** Notifications carry no payload, admission sequence, result Promise, or host permit. */
@@ -12,6 +12,13 @@ export function isStructuralGuardEnabled(): boolean {
12
12
  return process.env.ZLINK_NODE_STRUCTURAL_GUARD === '1' || process.env.NODE_ENV === 'test';
13
13
  }
14
14
 
15
+ /** Detaches lane ownership while preserving the caller's other execution contexts. */
16
+ export function startOutsideStateLane<T>(work: () => T): T {
17
+ return currentLaneStorage.exit(() =>
18
+ diagnosticTurnStorage === undefined ? work() : diagnosticTurnStorage.exit(work)
19
+ );
20
+ }
21
+
15
22
  const currentLaneStorage = new AsyncLocalStorage<ZLinkStateLane>();
16
23
  const diagnosticPending = isStructuralGuardEnabled() ? new Map<number, string>() : undefined;
17
24
  let nextDiagnosticWork = 0;
@@ -131,7 +131,7 @@ export function encodeCanonicalActorJoinRecoverySavedWork(
131
131
  const replyContentType =
132
132
  operationId === undefined
133
133
  ? null
134
- : requireText(input.replyContentType, 'Actor Join reply content type');
134
+ : (nullableText(input.replyContentType ?? null, 'Actor Join reply content type') ?? null);
135
135
  const metadata = encodeMetadataJson({
136
136
  Request: {
137
137
  ActorId: requireText(input.actorId, 'Actor id'),
@@ -288,7 +288,7 @@ export function decodeCanonicalActorJoinRecoverySavedWork(
288
288
  const operationLow = integer(metadata.OperationIdLow, 'OperationIdLow');
289
289
  const hasOperation = operationHigh !== 0n || operationLow !== 0n;
290
290
  const replyContentType = nullableText(metadata.ReplyContentType, 'ReplyContentType');
291
- if (hasOperation !== (replyContentType !== undefined)) {
291
+ if (!hasOperation && replyContentType !== undefined) {
292
292
  throw new TypeError('Canonical Actor Join recovery reply identity is invalid.');
293
293
  }
294
294
  const targetNodeRid = base64(metadata.TargetNodeRid, 'TargetNodeRid');
@@ -0,0 +1,137 @@
1
+ import { awaitWithAbort } from '../abort';
2
+ import { RequestResult, SubmitResult, isZLinkBackendResultError } from '../backend/runtime-values';
3
+ import {
4
+ ZLinkFrameworkInternalErrorKind,
5
+ createInternalFrameworkException
6
+ } from '../framework-errors-internal';
7
+
8
+ export interface PeerRouteObservation {
9
+ readonly generation?: bigint;
10
+ readonly ready: boolean;
11
+ }
12
+
13
+ export interface DurableServiceRequestPort {
14
+ readonly requestStopSignal?: AbortSignal;
15
+ observePeerRoute(target: string): PeerRouteObservation;
16
+ observePeerRouteChanged(listener: (target: string) => void): () => void;
17
+ observePeerConnectionIntentRemoved(listener: (target: string) => void): () => void;
18
+ requestService(
19
+ target: string,
20
+ parts: readonly Uint8Array[],
21
+ timeoutMs: number,
22
+ onAdmitted?: () => void
23
+ ): Promise<readonly Buffer[]>;
24
+ }
25
+
26
+ /** Actor model §8.1: a ready edge or a typed transport failure owns replay. */
27
+ export async function requestDurableService(
28
+ port: DurableServiceRequestPort,
29
+ target: string,
30
+ parts: readonly Uint8Array[],
31
+ deadlineMs: number,
32
+ operationKind: string,
33
+ signal?: AbortSignal,
34
+ onSubmitted?: (signal: AbortSignal) => Promise<void>
35
+ ): Promise<readonly Buffer[]> {
36
+ let wasAdmitted = false;
37
+ const stop = new AbortController();
38
+ const exhausted = (cause?: unknown) =>
39
+ createInternalFrameworkException(
40
+ wasAdmitted
41
+ ? ZLinkFrameworkInternalErrorKind.DeadlineExceeded
42
+ : ZLinkFrameworkInternalErrorKind.RouteNotConnected,
43
+ `${operationKind} exhausted its end-to-end deadline.`,
44
+ true,
45
+ cause
46
+ );
47
+ const timer = setTimeout(
48
+ () => stop.abort(exhausted()),
49
+ Math.max(0, Math.ceil(deadlineMs - performance.now()))
50
+ );
51
+ const unobserveIntent = port.observePeerConnectionIntentRemoved((rid) => {
52
+ if (rid === target)
53
+ stop.abort(
54
+ createInternalFrameworkException(
55
+ ZLinkFrameworkInternalErrorKind.RouteNotConnected,
56
+ `${operationKind} target node lifecycle ended.`,
57
+ true
58
+ )
59
+ );
60
+ });
61
+ const cancellation = AbortSignal.any([
62
+ stop.signal,
63
+ ...(signal === undefined ? [] : [signal]),
64
+ ...(port.requestStopSignal === undefined ? [] : [port.requestStopSignal])
65
+ ]);
66
+ try {
67
+ for (;;) {
68
+ cancellation.throwIfAborted();
69
+ const remainingMs = Math.ceil(deadlineMs - performance.now());
70
+ if (remainingMs <= 0) throw exhausted();
71
+ let changed!: () => void;
72
+ const transition = new Promise<void>((resolve) => {
73
+ changed = resolve;
74
+ });
75
+ let submittedGeneration: bigint | undefined;
76
+ const attemptStop = new AbortController();
77
+ const attemptSignal = AbortSignal.any([cancellation, attemptStop.signal]);
78
+ const unobserveRoute = port.observePeerRouteChanged((rid) => {
79
+ if (rid !== target) return;
80
+ const route = port.observePeerRoute(target);
81
+ if (
82
+ submittedGeneration === undefined
83
+ ? route.ready
84
+ : route.generation !== undefined && route.generation !== submittedGeneration
85
+ ) {
86
+ changed();
87
+ attemptStop.abort();
88
+ }
89
+ });
90
+ try {
91
+ const route = port.observePeerRoute(target);
92
+ if (!route.ready) {
93
+ await awaitWithAbort(transition, cancellation);
94
+ continue;
95
+ }
96
+ submittedGeneration = route.generation;
97
+ const reply = port.requestService(target, parts, remainingMs, () => {
98
+ wasAdmitted = true;
99
+ });
100
+ const request =
101
+ onSubmitted === undefined
102
+ ? reply
103
+ : Promise.race([
104
+ reply,
105
+ Promise.resolve()
106
+ .then(() => onSubmitted(attemptSignal))
107
+ .then(() => reply)
108
+ ]);
109
+ const result = await awaitWithAbort(
110
+ Promise.race([request.then((parts) => ({ parts })), transition.then(() => undefined)]),
111
+ cancellation
112
+ );
113
+ if (result !== undefined) return result.parts;
114
+ } catch (error) {
115
+ cancellation.throwIfAborted();
116
+ if (!durableRequestCanReplay(error)) throw error;
117
+ if (isZLinkBackendResultError(error) && error.operation === 'request') wasAdmitted = true;
118
+ } finally {
119
+ attemptStop.abort();
120
+ unobserveRoute();
121
+ }
122
+ }
123
+ } finally {
124
+ clearTimeout(timer);
125
+ unobserveIntent();
126
+ }
127
+ }
128
+
129
+ export function durableRequestCanReplay(error: unknown): boolean {
130
+ if (!isZLinkBackendResultError(error)) return false;
131
+ return error.operation === 'request'
132
+ ? error.result === RequestResult.NotConnected || error.result === RequestResult.TimedOut
133
+ : error.result === SubmitResult.NotConnected ||
134
+ error.result === SubmitResult.NotFound ||
135
+ error.result === SubmitResult.NotAdmitted ||
136
+ error.result === SubmitResult.Backpressured;
137
+ }
@@ -19,12 +19,16 @@ export type ZLinkOperationIdentityKey = string & {
19
19
  export function operationIdentityKey(
20
20
  operationId: ZLinkOperationIdentity128
21
21
  ): ZLinkOperationIdentityKey {
22
+ validateOperationIdentity(operationId);
23
+ return `${operationId.high.toString(16)}:${operationId.low.toString(16)}` as ZLinkOperationIdentityKey;
24
+ }
25
+
26
+ export function validateOperationIdentity(operationId: ZLinkOperationIdentity128): void {
22
27
  requireUnsigned64(operationId.high, 'operationId.high');
23
28
  requireUnsigned64(operationId.low, 'operationId.low');
24
29
  if (operationId.high === 0n && operationId.low === 0n) {
25
30
  throw new RangeError('Operation identity must not be all zero.');
26
31
  }
27
- return `${operationId.high.toString(16)}:${operationId.low.toString(16)}` as ZLinkOperationIdentityKey;
28
32
  }
29
33
 
30
34
  export function createRandomOperationIdentity(
@@ -24,11 +24,22 @@ export interface PendingOperation<T> {
24
24
  readonly promise: Promise<T>;
25
25
  }
26
26
 
27
+ /**
28
+ * Receives an operation's terminal at the place it is taken from the
29
+ * registry. One long-lived observer serves every observed operation, so an
30
+ * observed registration creates no Promise or per-operation callback.
31
+ */
32
+ export interface OperationObserver<T, Context> {
33
+ operationCompleted(id: bigint, value: T, context: Context | undefined): void;
34
+ operationFailed(id: bigint, reason: unknown, context: Context | undefined): void;
35
+ }
36
+
27
37
  interface Entry<T, Context> {
28
38
  readonly context: Context | undefined;
29
- readonly deadlineMs?: number;
30
- readonly resolve: (value: T | PromiseLike<T>) => void;
31
- readonly reject: (reason: unknown) => void;
39
+ deadlineMs?: number;
40
+ resolve?: (value: T | PromiseLike<T>) => void;
41
+ reject?: (reason: unknown) => void;
42
+ observer?: OperationObserver<T, Context>;
32
43
  }
33
44
 
34
45
  const systemClock: OperationClock = {
@@ -40,7 +51,14 @@ export class OperationRegistry<T, Context = unknown> {
40
51
  private readonly entries = new Map<bigint, Entry<T, Context>>();
41
52
  private nextId = 1n;
42
53
  private deadlineCursor?: MapIterator<[bigint, Entry<T, Context>]>;
54
+ /**
55
+ * A lower bound of the earliest pending deadline. Completed entries only
56
+ * leave it early; a full expiry pass replaces it with the exact value.
57
+ */
58
+ private earliestDeadlineMs = Number.POSITIVE_INFINITY;
59
+ private scanEarliestDeadlineMs = Number.POSITIVE_INFINITY;
43
60
  private closed = false;
61
+ private pendingCount = 0;
44
62
 
45
63
  constructor(
46
64
  private readonly clock: OperationClock = systemClock,
@@ -63,28 +81,56 @@ export class OperationRegistry<T, Context = unknown> {
63
81
  resolve = onResolve;
64
82
  reject = onReject;
65
83
  });
66
- const entry: Entry<T, Context> = {
67
- context,
68
- deadlineMs: timeoutOwner === 'registry' ? this.clock.now() + timeoutMs : undefined,
69
- resolve,
70
- reject
71
- };
84
+ const deadlineMs = timeoutOwner === 'registry' ? this.clock.now() + timeoutMs : undefined;
85
+ const entry: Entry<T, Context> = { context, deadlineMs, resolve, reject };
72
86
  this.entries.set(id, entry);
73
- if (this.entries.size === 1) this.onPendingChanged?.();
87
+ this.notePending(deadlineMs);
74
88
  return { id, promise };
75
89
  }
76
90
 
77
- complete(id: bigint, value: T): boolean {
91
+ /** Registers an operation whose terminal goes to `observer` instead of a Promise. */
92
+ registerObserved(
93
+ timeoutMs: number,
94
+ observer: OperationObserver<T, Context>,
95
+ context?: Context
96
+ ): bigint {
97
+ if (this.closed) throw new Error('Operation registry is closed.');
98
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
99
+ throw new RangeError('timeoutMs must be a non-negative finite number.');
100
+ }
101
+ const id = this.nextId++;
102
+ const deadlineMs = this.clock.now() + timeoutMs;
103
+ this.entries.set(id, { context, deadlineMs, observer });
104
+ this.notePending(deadlineMs);
105
+ return id;
106
+ }
107
+
108
+ /** The time the next expiry pass has work, as a lower bound (spec 08 §4.2). */
109
+ nextDeadlineMs(): number {
110
+ return this.earliestDeadlineMs;
111
+ }
112
+
113
+ private notePending(deadlineMs: number | undefined): void {
114
+ this.pendingCount++;
115
+ const earlier = deadlineMs !== undefined && deadlineMs < this.earliestDeadlineMs;
116
+ if (earlier) this.earliestDeadlineMs = deadlineMs;
117
+ if (earlier || this.pendingCount === 1) this.onPendingChanged?.();
118
+ }
119
+
120
+ complete(id: bigint, value: T, terminalContextRetentionMs = 0): boolean {
78
121
  const entry = this.take(id);
79
122
  if (entry === undefined) return false;
80
- entry.resolve(value);
123
+ if (entry.observer !== undefined) entry.observer.operationCompleted(id, value, entry.context);
124
+ else entry.resolve!(value);
125
+ this.retainTerminal(id, entry, terminalContextRetentionMs);
81
126
  return true;
82
127
  }
83
128
 
84
129
  fail(id: bigint, reason: unknown): boolean {
85
130
  const entry = this.take(id);
86
131
  if (entry === undefined) return false;
87
- entry.reject(reason);
132
+ if (entry.observer !== undefined) entry.observer.operationFailed(id, reason, entry.context);
133
+ else entry.reject!(reason);
88
134
  return true;
89
135
  }
90
136
 
@@ -93,7 +139,7 @@ export class OperationRegistry<T, Context = unknown> {
93
139
  }
94
140
 
95
141
  isPending(id: bigint): boolean {
96
- return this.entries.has(id);
142
+ return this.pendingEntry(id) !== undefined;
97
143
  }
98
144
 
99
145
  context(id: bigint): Context | undefined {
@@ -104,35 +150,67 @@ export class OperationRegistry<T, Context = unknown> {
104
150
  if (this.closed) return;
105
151
  this.closed = true;
106
152
  for (const id of this.entries.keys()) this.cancel(id, reason);
153
+ this.entries.clear();
107
154
  this.deadlineCursor = undefined;
108
155
  }
109
156
 
157
+ failAll(reason: unknown): void {
158
+ for (const id of this.entries.keys()) this.fail(id, reason);
159
+ }
160
+
110
161
  get size(): number {
111
- return this.entries.size;
162
+ return this.pendingCount;
112
163
  }
113
164
 
114
165
  expire(nowMs: number, turnDeadlineMs: number): number {
115
166
  let expired = 0;
116
167
  while (this.clock.now() < turnDeadlineMs) {
117
- this.deadlineCursor ??= this.entries.entries();
168
+ if (this.deadlineCursor === undefined) {
169
+ this.deadlineCursor = this.entries.entries();
170
+ this.scanEarliestDeadlineMs = Number.POSITIVE_INFINITY;
171
+ }
118
172
  const current = this.deadlineCursor.next();
119
173
  if (current.done === true) {
120
174
  this.deadlineCursor = undefined;
175
+ // Entries registered during the pass are appended and were scanned.
176
+ this.earliestDeadlineMs = this.scanEarliestDeadlineMs;
121
177
  break;
122
178
  }
123
179
  const [id, entry] = current.value;
124
- if (entry.deadlineMs !== undefined && entry.deadlineMs <= nowMs) {
125
- if (this.fail(id, new OperationTimeoutError(id))) expired++;
180
+ if (entry.deadlineMs === undefined) continue;
181
+ if (entry.deadlineMs <= nowMs) {
182
+ if (!this.isPending(id)) this.entries.delete(id);
183
+ else if (this.fail(id, new OperationTimeoutError(id))) expired++;
184
+ } else if (entry.deadlineMs < this.scanEarliestDeadlineMs) {
185
+ this.scanEarliestDeadlineMs = entry.deadlineMs;
126
186
  }
127
187
  }
128
188
  return expired;
129
189
  }
130
190
 
131
191
  private take(id: bigint): Entry<T, Context> | undefined {
132
- const entry = this.entries.get(id);
192
+ const entry = this.pendingEntry(id);
133
193
  if (entry === undefined) return undefined;
134
194
  this.entries.delete(id);
135
- if (this.entries.size === 0) this.onPendingChanged?.();
195
+ this.pendingCount--;
196
+ if (this.pendingCount === 0) this.onPendingChanged?.();
136
197
  return entry;
137
198
  }
199
+
200
+ private pendingEntry(id: bigint): Entry<T, Context> | undefined {
201
+ const entry = this.entries.get(id);
202
+ return entry !== undefined && (entry.resolve !== undefined || entry.observer !== undefined)
203
+ ? entry
204
+ : undefined;
205
+ }
206
+
207
+ private retainTerminal(id: bigint, entry: Entry<T, Context>, retentionMs: number): void {
208
+ if (this.closed || entry.context === undefined || retentionMs === 0) return;
209
+ entry.resolve = undefined;
210
+ entry.reject = undefined;
211
+ entry.observer = undefined;
212
+ entry.deadlineMs = this.clock.now() + retentionMs;
213
+ this.entries.set(id, entry);
214
+ this.earliestDeadlineMs = Math.min(this.earliestDeadlineMs, entry.deadlineMs);
215
+ }
138
216
  }