@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
@@ -118,40 +118,22 @@ export class ZLinkLocationLifecycle {
118
118
  );
119
119
  }
120
120
 
121
- async notifyActorJoinedSpot(
121
+ async commitActorMembership(
122
122
  actorType: string,
123
- actorId: string,
124
- spotMeshName: string,
123
+ actorRef: ActorRef,
124
+ authorityOwnerGeneration: bigint,
125
125
  spotId: RoutingId,
126
126
  spotGeneration: bigint,
127
- membershipEpoch: bigint,
127
+ spotKind: ZLinkSpotKind.Entry | ZLinkSpotKind.User,
128
128
  ownerNodeGeneration: bigint
129
129
  ): Promise<void> {
130
- await this.actorClaims.notifyJoinedSpot(
130
+ await this.actorClaims.commitMembership(
131
131
  actorType,
132
- actorId,
133
- spotMeshName,
132
+ actorRef,
133
+ authorityOwnerGeneration,
134
134
  spotId,
135
135
  spotGeneration,
136
- membershipEpoch,
137
- ownerNodeGeneration
138
- );
139
- }
140
-
141
- async notifyActorLeftSpot(
142
- actorType: string,
143
- actorId: string,
144
- entrySpotId: RoutingId,
145
- entrySpotGeneration: bigint,
146
- membershipEpoch: bigint,
147
- ownerNodeGeneration: bigint
148
- ): Promise<void> {
149
- await this.actorClaims.notifyLeftSpot(
150
- actorType,
151
- actorId,
152
- entrySpotId,
153
- entrySpotGeneration,
154
- membershipEpoch,
136
+ spotKind,
155
137
  ownerNodeGeneration
156
138
  );
157
139
  }
@@ -1,4 +1,10 @@
1
- import { ServiceRelocationAuthorityPayloadCodec } from '../foundation/service-relocation-runtime';
1
+ import {
2
+ ServiceRelocationAuthorityPayloadCodec,
3
+ serviceRelocationAuthorityApplicationPayload
4
+ } from '../foundation/service-relocation-runtime';
5
+ import { decodeServiceReadySpotAuthority } from '../foundation/service-authority-payload-codec';
6
+ import { decodeActorAuthorityPayload } from '../actors/actor-authority-payload-codec';
7
+ import { ZLinkSpotKind } from '../../contracts';
2
8
  import { UINT64_MAX } from '@zlink-systems/stream-wire';
3
9
  import { createHash, randomUUID } from 'node:crypto';
4
10
  import { zlinkRuntimeDefaultLocationOptions } from '../../contracts/Locations/Options';
@@ -76,6 +82,7 @@ import {
76
82
  type ZLinkObjectCommitResult,
77
83
  type ZLinkObjectCreationCompleteRequest,
78
84
  type ZLinkObjectCreationCompleteResult,
85
+ type ZLinkEndedOwnerReleaseIntent,
79
86
  type ZLinkObjectReserveRequest,
80
87
  type ZLinkObjectReserveResult,
81
88
  type ZLinkOwnerLeaseClaimResult,
@@ -429,10 +436,39 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
429
436
  payload: Buffer.from(mutation.payload)
430
437
  }
431
438
  };
439
+ const actor =
440
+ mutation.kind !== 'delete' && record.snapshot.allocation.objectKind === 'actor'
441
+ ? decodeActorAuthorityPayload(
442
+ serviceRelocationAuthorityApplicationPayload(mutation.payload)
443
+ )
444
+ : undefined;
445
+ const previousActor =
446
+ actor === undefined
447
+ ? undefined
448
+ : decodeActorAuthorityPayload(
449
+ serviceRelocationAuthorityApplicationPayload(record.snapshot.payload)
450
+ );
451
+ const membershipConditions =
452
+ actor?.currentSpotKind === ZLinkSpotKind.User &&
453
+ (previousActor?.currentSpotKind !== ZLinkSpotKind.User ||
454
+ previousActor.currentSpotId !== actor.currentSpotId ||
455
+ previousActor.currentSpotGeneration !== actor.currentSpotGeneration)
456
+ ? await this.userSpotMembershipConditions(
457
+ actor.currentSpotId,
458
+ actor.currentSpotGeneration,
459
+ signal,
460
+ {
461
+ ownerId: record.snapshot.ownerId,
462
+ leaseGeneration: record.snapshot.ownerLeaseGeneration
463
+ }
464
+ )
465
+ : [];
466
+ if (membershipConditions === undefined) return { kind: 'conflict', current: snapshot };
432
467
  const result = await this.provider.write(
433
468
  {
434
469
  conditions: [
435
470
  { kind: 'version', key: rowKey, expected: current.value.version },
471
+ ...membershipConditions,
436
472
  ...(mutation.kind === 'restore'
437
473
  ? []
438
474
  : [
@@ -945,7 +981,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
945
981
  ) {
946
982
  throw new Error('Aggregate participant staging checksum does not match inventory.');
947
983
  }
948
- authorityRows.push({ key: rowKeyForParticipant, current, record, entry });
984
+ authorityRows.push({ key: rowKeyForParticipant, current, record, entry, payload });
949
985
  }
950
986
 
951
987
  const targetDescriptorKey = meshKey(
@@ -1024,12 +1060,52 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1024
1060
  bytes: encodeJson(capacity)
1025
1061
  });
1026
1062
  }
1063
+ const membershipConditions: ZLinkStoreCondition[] = [];
1064
+ for (const row of authorityRows) {
1065
+ if (row.record.snapshot.allocation.objectKind !== 'actor') continue;
1066
+ const actor = decodeActorAuthorityPayload(
1067
+ serviceRelocationAuthorityApplicationPayload(row.payload)
1068
+ );
1069
+ if (actor?.currentSpotKind !== ZLinkSpotKind.User) continue;
1070
+ const spotKey = encodeAuthorityKey('user_spot', actor.currentSpotId);
1071
+ const participantSpot = authorityRows.find(
1072
+ (candidate) => candidate.entry.authorityKey === spotKey.value
1073
+ );
1074
+ if (participantSpot !== undefined) {
1075
+ if (
1076
+ participantSpot.record.snapshot.allocation.objectKind !== 'user_spot' ||
1077
+ participantSpot.record.snapshot.objectGeneration !== actor.currentSpotGeneration
1078
+ )
1079
+ return { kind: 'stale' };
1080
+ continue;
1081
+ }
1082
+ if (
1083
+ membershipConditions.some(
1084
+ (condition) => condition.key.value === authorityKey(spotKey.value).value
1085
+ )
1086
+ )
1087
+ continue;
1088
+ const conditions = await this.userSpotMembershipConditions(
1089
+ actor.currentSpotId,
1090
+ actor.currentSpotGeneration,
1091
+ signal,
1092
+ aggregate.targetOwner
1093
+ );
1094
+ if (conditions === undefined) return { kind: 'stale' };
1095
+ membershipConditions.push(
1096
+ ...conditions.filter(
1097
+ (condition) =>
1098
+ !membershipConditions.some((existing) => existing.key.value === condition.key.value)
1099
+ )
1100
+ );
1101
+ }
1027
1102
  const published = await this.provider.write(
1028
1103
  {
1029
1104
  conditions: [
1030
1105
  { kind: 'version', key: rowKey, expected: aggregateRead.value.version },
1031
1106
  versionCondition(targetDescriptorKey, descriptorRead),
1032
1107
  leaseValueCondition(targetLeaseKey, aggregate.targetOwner),
1108
+ ...membershipConditions,
1033
1109
  ...[...capacityReads.entries()].map(([value, read]) => ({
1034
1110
  kind: 'version' as const,
1035
1111
  key: capacityKeys.get(value)!,
@@ -1128,10 +1204,12 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1128
1204
  override async releaseEndedReservation(
1129
1205
  key: ZLinkAuthorityKey,
1130
1206
  expectedStoreVersion: string,
1131
- signal?: AbortSignal
1207
+ signal?: AbortSignal,
1208
+ request?: ZLinkEndedOwnerReleaseIntent
1132
1209
  ): Promise<boolean> {
1133
1210
  return (
1134
- (await this.tryReleaseEndedReservation(key, expectedStoreVersion, signal)) === 'reclaimed'
1211
+ (await this.tryReleaseEndedReservation(key, expectedStoreVersion, signal, request)) ===
1212
+ 'reclaimed'
1135
1213
  );
1136
1214
  }
1137
1215
 
@@ -1139,7 +1217,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1139
1217
  key: ZLinkAuthorityKey,
1140
1218
  expectedStoreVersion: string,
1141
1219
  signal?: AbortSignal,
1142
- request?: ZLinkObjectReserveRequest
1220
+ request?: ZLinkEndedOwnerReleaseIntent
1143
1221
  ): Promise<'notReclaimable' | 'conflict' | 'reclaimed'> {
1144
1222
  const rowKey = authorityKey(key.value);
1145
1223
  const current = await this.provider.read(rowKey, signal);
@@ -1148,11 +1226,9 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1148
1226
  const record = decodeAuthorityRecord(current.value.bytes);
1149
1227
  const snapshot = record.snapshot;
1150
1228
  if (
1151
- (snapshot.allocation.state === 'active'
1152
- ? request?.key.kind !== 'actor'
1153
- : snapshot.pendingCreation === undefined) ||
1154
- record.aggregate !== undefined ||
1155
- hasRelocationAuthority(snapshot.payload)
1229
+ snapshot.allocation.state === 'active'
1230
+ ? request === undefined
1231
+ : snapshot.pendingCreation === undefined
1156
1232
  )
1157
1233
  return 'notReclaimable';
1158
1234
  const leaseKey = ownerKey(snapshot.ownerId);
@@ -1174,10 +1250,60 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1174
1250
  const ownerLive = sameLiveOwner(lease, snapshot);
1175
1251
  if (snapshot.allocation.state === 'active') {
1176
1252
  if (ownerLive) return 'notReclaimable';
1177
- if (request?.actorRelocationPolicy !== 'disabled')
1253
+ let unavailable = record.aggregate !== undefined || hasRelocationAuthority(snapshot.payload);
1254
+ if (snapshot.allocation.objectKind !== 'actor') {
1255
+ const spot = decodeServiceReadySpotAuthority(snapshot.payload);
1256
+ unavailable ||=
1257
+ spot === undefined ||
1258
+ spot.kind !== request?.key.kind ||
1259
+ spot.stableType !== request.intent.stableType ||
1260
+ spot.spotId !== request.key.globalId ||
1261
+ spot.activationRecovery !== undefined;
1262
+ if (spot?.kind === 'user_spot') {
1263
+ // The snapshot starts only after the old owner's lease was found invalid.
1264
+ for (const prefix of [`${PREFIX}actor:`, `${AUTHORITY_PREIMAGE_PREFIX}actor\0`]) {
1265
+ membershipSnapshot: for (;;) {
1266
+ let snapshotHasMember = false;
1267
+ let cursor: ZLinkStoreScanCursor | undefined;
1268
+ do {
1269
+ const page = await this.provider.scan(
1270
+ { prefix, cursor, limit: ZLINK_PROVIDER_MAX_PAGE_SIZE },
1271
+ signal
1272
+ );
1273
+ if (page.kind === 'expired') continue membershipSnapshot;
1274
+ for (const item of page.value.items) {
1275
+ if (prefix === `${PREFIX}actor:`) {
1276
+ const actor = normalizeActor(
1277
+ decodeJson<DescriptorRecord<ZLinkActorLocation>>(item.value.bytes).descriptor
1278
+ );
1279
+ snapshotHasMember ||=
1280
+ actor.spotKind === ZLinkSpotKind.User &&
1281
+ String(actor.spotId) === spot.spotId &&
1282
+ actor.spotGeneration === snapshot.objectGeneration;
1283
+ } else {
1284
+ const authority = decodeAuthorityRecord(item.value.bytes).snapshot;
1285
+ if (authority.allocation.objectKind !== 'actor') continue;
1286
+ const actor = decodeActorAuthorityPayload(
1287
+ serviceRelocationAuthorityApplicationPayload(authority.payload)
1288
+ );
1289
+ snapshotHasMember ||=
1290
+ actor?.currentSpotKind === ZLinkSpotKind.User &&
1291
+ actor.currentSpotId === spot.spotId &&
1292
+ actor.currentSpotGeneration === snapshot.objectGeneration;
1293
+ }
1294
+ }
1295
+ cursor = page.value.nextCursor;
1296
+ } while (cursor !== undefined);
1297
+ unavailable ||= snapshotHasMember;
1298
+ break;
1299
+ }
1300
+ }
1301
+ }
1302
+ }
1303
+ if (unavailable || request?.actorRelocationPolicy !== 'disabled')
1178
1304
  throw new ZLinkFrameworkException(
1179
1305
  ZLinkFrameworkErrorKind.Unavailable,
1180
- 'Actor owner lease is unavailable.'
1306
+ 'Object owner lease is unavailable.'
1181
1307
  );
1182
1308
  } else if (
1183
1309
  ownerLive &&
@@ -1187,6 +1313,11 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1187
1313
  ).lifecycleGeneration === snapshot.allocation.descriptorLifecycleGeneration
1188
1314
  )
1189
1315
  return 'notReclaimable';
1316
+ if (
1317
+ snapshot.allocation.state !== 'active' &&
1318
+ (record.aggregate !== undefined || hasRelocationAuthority(snapshot.payload))
1319
+ )
1320
+ return 'notReclaimable';
1190
1321
  const mutations: ZLinkStoreWriteRequest['mutations'][number][] = [
1191
1322
  { kind: 'delete', key: rowKey }
1192
1323
  ];
@@ -1601,6 +1732,22 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1601
1732
  'Creation terminal expiry must be the live operation deadline plus five minutes.'
1602
1733
  );
1603
1734
  }
1735
+ const actor =
1736
+ request.completion.kind === 'created'
1737
+ ? decodeActorAuthorityPayload(
1738
+ serviceRelocationAuthorityApplicationPayload(request.completion.readyPayload)
1739
+ )
1740
+ : undefined;
1741
+ const membershipConditions =
1742
+ actor?.currentSpotKind === ZLinkSpotKind.User
1743
+ ? await this.userSpotMembershipConditions(
1744
+ actor.currentSpotId,
1745
+ actor.currentSpotGeneration,
1746
+ signal,
1747
+ request.target.owner
1748
+ )
1749
+ : [];
1750
+ if (membershipConditions === undefined) return { kind: 'stale' };
1604
1751
  const mutations =
1605
1752
  request.completion.kind === 'created'
1606
1753
  ? [
@@ -1642,6 +1789,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
1642
1789
  conditions: [
1643
1790
  { kind: 'version', key: rowKey, expected: current.value.version },
1644
1791
  { kind: 'missing', key: terminalRowKey },
1792
+ ...membershipConditions,
1645
1793
  versionCondition(descriptorKey, descriptorRead),
1646
1794
  leaseValueCondition(leaseKey, request.target.owner),
1647
1795
  conditionFor(capacityRowKey, capacityRead)
@@ -2073,7 +2221,8 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
2073
2221
  actorKey(location.meshName, location.actorId),
2074
2222
  normalizeActor(location),
2075
2223
  intent,
2076
- signal
2224
+ signal,
2225
+ location
2077
2226
  );
2078
2227
  }
2079
2228
 
@@ -2615,11 +2764,48 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
2615
2764
  };
2616
2765
  }
2617
2766
 
2767
+ private async userSpotMembershipConditions(
2768
+ spotId: string,
2769
+ objectGeneration: bigint,
2770
+ signal?: AbortSignal,
2771
+ conditionedOwner?: ZLinkLocationOwnerToken
2772
+ ): Promise<ZLinkStoreCondition[] | undefined> {
2773
+ const key = authorityKey(encodeAuthorityKey('user_spot', spotId).value);
2774
+ const read = await this.provider.read(key, signal);
2775
+ if (read.kind === 'missing') return undefined;
2776
+ const record = decodeAuthorityRecord(read.value.bytes);
2777
+ const snapshot = record.snapshot;
2778
+ if (
2779
+ record.aggregate !== undefined ||
2780
+ snapshot.allocation.objectKind !== 'user_spot' ||
2781
+ snapshot.allocation.state !== 'active' ||
2782
+ snapshot.objectGeneration !== objectGeneration ||
2783
+ decodeServiceReadySpotAuthority(snapshot.payload)?.kind !== 'user_spot'
2784
+ )
2785
+ return undefined;
2786
+ const leaseKey = ownerKey(snapshot.ownerId);
2787
+ const lease = await this.provider.read(leaseKey, signal);
2788
+ if (!sameLiveOwner(lease, snapshot)) return undefined;
2789
+ return [
2790
+ { kind: 'version', key, expected: read.value.version },
2791
+ ...(conditionedOwner?.ownerId === snapshot.ownerId &&
2792
+ conditionedOwner.leaseGeneration === snapshot.ownerLeaseGeneration
2793
+ ? []
2794
+ : [
2795
+ leaseValueCondition(leaseKey, {
2796
+ ownerId: snapshot.ownerId,
2797
+ leaseGeneration: snapshot.ownerLeaseGeneration
2798
+ })
2799
+ ])
2800
+ ];
2801
+ }
2802
+
2618
2803
  private async updateOwnedLocation<T extends LeaseOwnedLocation>(
2619
2804
  rowKey: ZLinkStoreKey,
2620
2805
  location: T,
2621
2806
  intent: ZLinkLocationWriteIntent,
2622
- signal?: AbortSignal
2807
+ signal?: AbortSignal,
2808
+ membership?: Pick<ZLinkActorLocation, 'spotKind' | 'spotId' | 'spotGeneration'>
2623
2809
  ): Promise<ZLinkLocationWriteResult> {
2624
2810
  const leaseKey = ownerKey(location.ownerId);
2625
2811
  const [lease, current] = await Promise.all([
@@ -2673,6 +2859,24 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
2673
2859
  return rejected(lease.value.storeNow);
2674
2860
  }
2675
2861
 
2862
+ const previousMembership =
2863
+ current.kind === 'found' && membership !== undefined
2864
+ ? decodeJson<DescriptorRecord<ZLinkActorLocation>>(current.value.bytes).descriptor
2865
+ : undefined;
2866
+ const membershipConditions =
2867
+ membership?.spotKind === ZLinkSpotKind.User &&
2868
+ (previousMembership?.spotKind !== ZLinkSpotKind.User ||
2869
+ String(previousMembership.spotId) !== String(membership.spotId) ||
2870
+ BigInt(previousMembership.spotGeneration) !== membership.spotGeneration)
2871
+ ? await this.userSpotMembershipConditions(
2872
+ String(membership.spotId),
2873
+ membership.spotGeneration,
2874
+ signal,
2875
+ { ownerId: location.ownerId, leaseGeneration: locationOwnerGeneration(location) }
2876
+ )
2877
+ : [];
2878
+ if (membershipConditions === undefined) return rejected(lease.value.storeNow);
2879
+
2676
2880
  const result = await this.provider.write(
2677
2881
  {
2678
2882
  conditions: [
@@ -2680,7 +2884,8 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
2680
2884
  ownerId: location.ownerId,
2681
2885
  leaseGeneration: locationOwnerGeneration(location)
2682
2886
  }),
2683
- rowCondition
2887
+ rowCondition,
2888
+ ...membershipConditions
2684
2889
  ],
2685
2890
  mutations: [
2686
2891
  {
@@ -26,7 +26,11 @@ import {
26
26
  type ResolvedSpotHandle
27
27
  } from '../spots/spot-handle';
28
28
 
29
- import type { ZLinkSpotRouteResolver, ZLinkSpotRouteTarget } from '../spots/spot-routing-internal';
29
+ import type {
30
+ ZLinkSpotRouteResolver,
31
+ ZLinkSpotRouteTarget,
32
+ ZLinkInstanceReactivationRoute
33
+ } from '../spots/spot-routing-internal';
30
34
  import { encodeAuthorityKey } from './authority-key-codec';
31
35
  import { isKnownZLinkLocationAutoConnectType, isKnownZLinkLocationRole } from './canonical-codec';
32
36
  import {
@@ -951,7 +955,17 @@ export class ZLinkAuthoritySpotRouteResolver implements ZLinkSpotRouteResolver {
951
955
  ) => Promise<ZLinkFrameworkRuntimeState | undefined>
952
956
  ) {}
953
957
 
954
- async resolve(spotId: RoutingId, signal?: AbortSignal): Promise<ZLinkSpotRouteTarget> {
958
+ resolve(
959
+ spotId: RoutingId,
960
+ signal: AbortSignal | undefined,
961
+ instanceIntent: true
962
+ ): Promise<ZLinkSpotRouteTarget | ZLinkInstanceReactivationRoute>;
963
+ resolve(spotId: RoutingId, signal?: AbortSignal): Promise<ZLinkSpotRouteTarget>;
964
+ async resolve(
965
+ spotId: RoutingId,
966
+ signal?: AbortSignal,
967
+ instanceIntent?: true
968
+ ): Promise<ZLinkSpotRouteTarget | ZLinkInstanceReactivationRoute> {
955
969
  const key = String(spotId);
956
970
  const prepared = await this.lane.run(() => this.beginResolutionCore(key));
957
971
  try {
@@ -980,6 +994,15 @@ export class ZLinkAuthoritySpotRouteResolver implements ZLinkSpotRouteResolver {
980
994
  signal
981
995
  );
982
996
  if (remainingLeaseMs !== undefined && remainingLeaseMs <= 0) {
997
+ if (instanceIntent === true && ready?.kind === 'instance_spot') {
998
+ return {
999
+ kind: 'coldActivation',
1000
+ spotId,
1001
+ spotKind: ZLinkSpotKind.Instance,
1002
+ meshName: ready.ownerMeshName,
1003
+ stableType: ready.stableType
1004
+ };
1005
+ }
983
1006
  throw new ZLinkFrameworkException(
984
1007
  ZLinkFrameworkErrorKind.Unavailable,
985
1008
  `SPOT '${spotId}' Ready authority owner lease is unavailable.`
@@ -162,7 +162,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
162
162
  readonly name: string;
163
163
  }[];
164
164
  private readonly rewriteAuthorityPayloadForOwner?: ZLinkLocationRuntimeOptions['rewriteAuthorityPayloadForOwner'];
165
- private nextLeaseRenewAtMs?: number;
165
+ private leaseOperationStartedAtMs = 0;
166
166
  private ownerToken?: ZLinkLocationOwnerToken;
167
167
  private lastOwnerToken?: ZLinkLocationOwnerToken;
168
168
  private ownerLeaseDeadlineMs?: number;
@@ -342,12 +342,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
342
342
  const claim = this.renewOwnerLeaseOnce(signal, shutdownSignal);
343
343
  this.heartbeatRenewal = claim;
344
344
  try {
345
- const claimed = await claim;
346
- if (claimed) {
347
- this.scheduleHeartbeat();
348
- return;
349
- }
350
- this.nextLeaseRenewAtMs = this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
345
+ await claim;
351
346
  this.scheduleHeartbeat();
352
347
  } catch (error) {
353
348
  this.started = false;
@@ -362,7 +357,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
362
357
  this.clearTimer(this.heartbeatTimer);
363
358
  this.heartbeatTimer = undefined;
364
359
  }
365
- this.nextLeaseRenewAtMs = undefined;
360
+ this.leaseOperationStartedAtMs = 0;
366
361
  this.ownerLeaseDeadlineMs = undefined;
367
362
  await this.cleanupOwner(signal);
368
363
  }
@@ -422,6 +417,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
422
417
  const wasOwnerLeaseUsable = this.ownerLeaseUsable;
423
418
  try {
424
419
  const renewStartedAtMs = this.monotonicNowMs();
420
+ this.leaseOperationStartedAtMs = renewStartedAtMs;
425
421
  const result = await withTimeout(
426
422
  (renewSignal) =>
427
423
  this.stores.ownerLeaseStore.renewOwnerLease(
@@ -475,10 +471,15 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
475
471
  shutdownSignal?: () => AbortSignal
476
472
  ): Promise<boolean> {
477
473
  const claimStartedAtMs = this.monotonicNowMs();
478
- const timeoutDeadline = performance.now() + this.options.ownerLeaseRenewTimeoutMs;
474
+ this.leaseOperationStartedAtMs = claimStartedAtMs;
475
+ const timeoutStartedAtMs = performance.now();
479
476
  let claim: Awaited<ReturnType<ZLinkOwnerLeaseStore['claimOwnerLease']>>;
480
477
  try {
481
- claim = await this.claimOwnerLeaseWithConfirmation(timeoutDeadline, signal, shutdownSignal);
478
+ claim = await this.claimOwnerLeaseWithConfirmation(
479
+ timeoutStartedAtMs,
480
+ signal,
481
+ shutdownSignal
482
+ );
482
483
  } catch (error) {
483
484
  if (signal?.aborted === true) throw error;
484
485
  if (error instanceof ZLinkOwnerLeaseClaimError) throw error;
@@ -508,7 +509,6 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
508
509
  claim.storeNow
509
510
  );
510
511
  this.lastError = undefined;
511
- this.nextLeaseRenewAtMs = this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
512
512
  for (const handler of this.ownerLeaseRenewedHandlers) {
513
513
  handler({
514
514
  kind: 'renewed',
@@ -525,7 +525,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
525
525
  }
526
526
 
527
527
  private async claimOwnerLeaseWithConfirmation(
528
- timeoutDeadline: number,
528
+ timeoutStartedAtMs: number,
529
529
  signal?: AbortSignal,
530
530
  shutdownSignal?: () => AbortSignal
531
531
  ): Promise<Awaited<ReturnType<ZLinkOwnerLeaseStore['claimOwnerLease']>>> {
@@ -540,7 +540,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
540
540
  this.options.ownerLeaseTtlMs,
541
541
  claimSignal
542
542
  )),
543
- remainingTimeoutMs(timeoutDeadline),
543
+ remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs),
544
544
  signal
545
545
  );
546
546
  } catch (error) {
@@ -550,7 +550,9 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
550
550
  try {
551
551
  await withTimeout(
552
552
  () => request!,
553
- cleanupSignal === undefined ? remainingTimeoutMs(timeoutDeadline) : undefined,
553
+ cleanupSignal === undefined
554
+ ? remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs)
555
+ : undefined,
554
556
  cleanupSignal
555
557
  );
556
558
  } catch (completionError) {
@@ -567,7 +569,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
567
569
  }
568
570
  const confirmed = await this.confirmOwnerLease(
569
571
  error,
570
- timeoutDeadline,
572
+ timeoutStartedAtMs,
571
573
  signal,
572
574
  shutdownSignal
573
575
  );
@@ -577,13 +579,13 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
577
579
  if (claim.kind !== 'conflict') return claim;
578
580
  const conflict = new ZLinkOwnerLeaseClaimError(claim.kind);
579
581
  return (
580
- (await this.confirmOwnerLease(conflict, timeoutDeadline, signal, shutdownSignal)) ?? claim
582
+ (await this.confirmOwnerLease(conflict, timeoutStartedAtMs, signal, shutdownSignal)) ?? claim
581
583
  );
582
584
  }
583
585
 
584
586
  private async confirmOwnerLease(
585
587
  originalError: unknown,
586
- timeoutDeadline: number,
588
+ timeoutStartedAtMs: number,
587
589
  signal?: AbortSignal,
588
590
  shutdownSignal?: () => AbortSignal
589
591
  ): Promise<
@@ -593,7 +595,9 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
593
595
  const cancelled = signal?.aborted === true;
594
596
  const cleanupSignal = cancelled ? shutdownSignal?.() : undefined;
595
597
  const confirmationTimeoutMs =
596
- cleanupSignal === undefined ? remainingTimeoutMs(timeoutDeadline) : undefined;
598
+ cleanupSignal === undefined
599
+ ? remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs)
600
+ : undefined;
597
601
  if (confirmationTimeoutMs !== undefined && confirmationTimeoutMs <= 0) throw originalError;
598
602
  let confirmed: Awaited<ReturnType<ZLinkOwnerLeaseStore['readOwnerLease']>>;
599
603
  try {
@@ -615,7 +619,9 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
615
619
  await withTimeout(
616
620
  (releaseSignal) =>
617
621
  this.stores.ownerLeaseStore.releaseOwnerLease(confirmed.token, releaseSignal),
618
- cleanupSignal === undefined ? remainingTimeoutMs(timeoutDeadline) : undefined,
622
+ cleanupSignal === undefined
623
+ ? remainingTimeoutMs(timeoutStartedAtMs, this.options.ownerLeaseRenewTimeoutMs)
624
+ : undefined,
619
625
  cleanupSignal
620
626
  );
621
627
  } catch (releaseError) {
@@ -1250,8 +1256,7 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
1250
1256
  if (!this.started) {
1251
1257
  return;
1252
1258
  }
1253
- const scheduledAt =
1254
- this.nextLeaseRenewAtMs ?? this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
1259
+ const scheduledAt = this.leaseOperationStartedAtMs + this.options.ownerLeaseRenewIntervalMs;
1255
1260
  const delayMs = Math.max(0, scheduledAt - this.monotonicNowMs());
1256
1261
  this.heartbeatTimer = this.setTimer(() => {
1257
1262
  this.heartbeatTimer = undefined;
@@ -1259,7 +1264,6 @@ export class ZLinkLocationRuntime implements ZLinkLocationRuntimeQuery {
1259
1264
  for (const scope of this.leaseScopes) {
1260
1265
  this.metrics?.recordOwnerLeaseRenewLateness(lateness, scope.kind, scope.name);
1261
1266
  }
1262
- this.nextLeaseRenewAtMs = this.monotonicNowMs() + this.options.ownerLeaseRenewIntervalMs;
1263
1267
  if (
1264
1268
  this.ownerLeaseDeadlineMs !== undefined &&
1265
1269
  this.monotonicNowMs() >= this.ownerLeaseDeadlineMs
@@ -1413,8 +1417,8 @@ class OwnerLeaseRenewTimeoutError extends Error {
1413
1417
  }
1414
1418
  }
1415
1419
 
1416
- function remainingTimeoutMs(timeoutDeadline: number): number {
1417
- return Math.max(0, timeoutDeadline - performance.now());
1420
+ function remainingTimeoutMs(timeoutStartedAtMs: number, timeoutMs: number): number {
1421
+ return Math.max(0, timeoutMs - (performance.now() - timeoutStartedAtMs));
1418
1422
  }
1419
1423
 
1420
1424
  function errorMessage(error: unknown): string {