@zlink-systems/framework 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1121) hide show
  1. package/LICENSE +105 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/contracts/Actors/ZLinkActor.d.ts +7 -0
  4. package/dist/contracts/Actors/ZLinkActor.js +2 -0
  5. package/dist/contracts/Actors/ZLinkActorClient.d.ts +15 -0
  6. package/dist/contracts/Actors/ZLinkActorClient.js +2 -0
  7. package/dist/contracts/Actors/ZLinkActorContext.d.ts +14 -0
  8. package/dist/contracts/Actors/ZLinkActorContext.js +2 -0
  9. package/dist/contracts/Actors/ZLinkActorFactory.d.ts +34 -0
  10. package/dist/contracts/Actors/ZLinkActorFactory.js +2 -0
  11. package/dist/contracts/Actors/ZLinkActorManager.d.ts +34 -0
  12. package/dist/contracts/Actors/ZLinkActorManager.js +2 -0
  13. package/dist/contracts/Actors/index.d.ts +5 -0
  14. package/dist/contracts/Actors/index.js +21 -0
  15. package/dist/contracts/Channels/Calls.d.ts +28 -0
  16. package/dist/contracts/Channels/Calls.js +2 -0
  17. package/dist/contracts/Channels/IZLinkChannelClient.d.ts +5 -0
  18. package/dist/contracts/Channels/IZLinkChannelClient.js +2 -0
  19. package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +11 -0
  20. package/dist/contracts/Channels/IZLinkFanoutClient.js +2 -0
  21. package/dist/contracts/Channels/RouteCalls.d.ts +11 -0
  22. package/dist/contracts/Channels/RouteCalls.js +2 -0
  23. package/dist/contracts/Channels/index.d.ts +4 -0
  24. package/dist/contracts/Channels/index.js +20 -0
  25. package/dist/contracts/Codecs/IZLinkCodecRegistryBuilder.d.ts +14 -0
  26. package/dist/contracts/Codecs/IZLinkCodecRegistryBuilder.js +2 -0
  27. package/dist/contracts/Codecs/ZLinkMessageSerializer.d.ts +5 -0
  28. package/dist/contracts/Codecs/ZLinkMessageSerializer.js +2 -0
  29. package/dist/contracts/Codecs/index.d.ts +2 -0
  30. package/dist/contracts/Codecs/index.js +18 -0
  31. package/dist/contracts/Common/ActorRef.d.ts +7 -0
  32. package/dist/contracts/Common/ActorRef.js +2 -0
  33. package/dist/contracts/Common/CoreTypes.d.ts +6 -0
  34. package/dist/contracts/Common/CoreTypes.js +2 -0
  35. package/dist/contracts/Common/Message.d.ts +9 -0
  36. package/dist/contracts/Common/Message.js +2 -0
  37. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +12 -0
  38. package/dist/contracts/Common/ZLinkEncodedPayload.js +41 -0
  39. package/dist/contracts/Common/ZLinkMessage.d.ts +25 -0
  40. package/dist/contracts/Common/ZLinkMessage.js +127 -0
  41. package/dist/contracts/Common/ZLinkMessageMetadata.d.ts +10 -0
  42. package/dist/contracts/Common/ZLinkMessageMetadata.js +49 -0
  43. package/dist/contracts/Common/ZLinkProviderResolver.d.ts +5 -0
  44. package/dist/contracts/Common/ZLinkProviderResolver.js +2 -0
  45. package/dist/contracts/Common/encoded-payload-storage.d.ts +3 -0
  46. package/dist/contracts/Common/encoded-payload-storage.js +18 -0
  47. package/dist/contracts/Common/index.d.ts +5 -0
  48. package/dist/contracts/Common/index.js +24 -0
  49. package/dist/contracts/Configuration/Builders.d.ts +153 -0
  50. package/dist/contracts/Configuration/Builders.js +2 -0
  51. package/dist/contracts/Configuration/CodecContentType.d.ts +2 -0
  52. package/dist/contracts/Configuration/CodecContentType.js +68 -0
  53. package/dist/contracts/Configuration/CodecSerializerSelection.d.ts +9 -0
  54. package/dist/contracts/Configuration/CodecSerializerSelection.js +15 -0
  55. package/dist/contracts/Configuration/Configs.d.ts +23 -0
  56. package/dist/contracts/Configuration/Configs.js +2 -0
  57. package/dist/contracts/Configuration/ConfigurationException.d.ts +3 -0
  58. package/dist/contracts/Configuration/ConfigurationException.js +10 -0
  59. package/dist/contracts/Configuration/Connections.d.ts +5 -0
  60. package/dist/contracts/Configuration/Connections.js +2 -0
  61. package/dist/contracts/Configuration/DiagnosticsValidation.d.ts +3 -0
  62. package/dist/contracts/Configuration/DiagnosticsValidation.js +23 -0
  63. package/dist/contracts/Configuration/EndpointNotation.d.ts +77 -0
  64. package/dist/contracts/Configuration/EndpointNotation.js +218 -0
  65. package/dist/contracts/Configuration/InternalDefaults.d.ts +7 -0
  66. package/dist/contracts/Configuration/InternalDefaults.js +47 -0
  67. package/dist/contracts/Configuration/ObjectRoles.d.ts +38 -0
  68. package/dist/contracts/Configuration/ObjectRoles.js +13 -0
  69. package/dist/contracts/Configuration/Registration.d.ts +11 -0
  70. package/dist/contracts/Configuration/Registration.js +162 -0
  71. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +14 -0
  72. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +61 -0
  73. package/dist/contracts/Configuration/RegistrationBuilders.d.ts +61 -0
  74. package/dist/contracts/Configuration/RegistrationBuilders.js +1181 -0
  75. package/dist/contracts/Configuration/RegistrationCodecRegistry.d.ts +19 -0
  76. package/dist/contracts/Configuration/RegistrationCodecRegistry.js +79 -0
  77. package/dist/contracts/Configuration/RegistrationNormalizers.d.ts +23 -0
  78. package/dist/contracts/Configuration/RegistrationNormalizers.js +319 -0
  79. package/dist/contracts/Configuration/RegistrationTypes.d.ts +414 -0
  80. package/dist/contracts/Configuration/RegistrationTypes.js +2 -0
  81. package/dist/contracts/Configuration/RegistrationValidators.d.ts +2 -0
  82. package/dist/contracts/Configuration/RegistrationValidators.js +461 -0
  83. package/dist/contracts/Configuration/RouteChannelInternalState.d.ts +10 -0
  84. package/dist/contracts/Configuration/RouteChannelInternalState.js +39 -0
  85. package/dist/contracts/Configuration/RuntimeEndpointConnections.d.ts +9 -0
  86. package/dist/contracts/Configuration/RuntimeEndpointConnections.js +80 -0
  87. package/dist/contracts/Configuration/SendTimeoutValidation.d.ts +2 -0
  88. package/dist/contracts/Configuration/SendTimeoutValidation.js +16 -0
  89. package/dist/contracts/Configuration/TimerRegistrationValidator.d.ts +2 -0
  90. package/dist/contracts/Configuration/TimerRegistrationValidator.js +24 -0
  91. package/dist/contracts/Configuration/index.d.ts +5 -0
  92. package/dist/contracts/Configuration/index.js +18 -0
  93. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +181 -0
  94. package/dist/contracts/Dispatch/ZLinkDispatchOptions.js +89 -0
  95. package/dist/contracts/Dispatch/ZLinkFlowOrigin.d.ts +1 -0
  96. package/dist/contracts/Dispatch/ZLinkFlowOrigin.js +2 -0
  97. package/dist/contracts/Dispatch/index.d.ts +2 -0
  98. package/dist/contracts/Dispatch/index.js +18 -0
  99. package/dist/contracts/Errors/ZLinkFrameworkException.d.ts +20 -0
  100. package/dist/contracts/Errors/ZLinkFrameworkException.js +29 -0
  101. package/dist/contracts/Errors/index.d.ts +1 -0
  102. package/dist/contracts/Errors/index.js +6 -0
  103. package/dist/contracts/Eventing/Metrics.d.ts +29 -0
  104. package/dist/contracts/Eventing/Metrics.js +4 -0
  105. package/dist/contracts/Eventing/index.d.ts +1 -0
  106. package/dist/contracts/Eventing/index.js +17 -0
  107. package/dist/contracts/Handlers/Attributes.d.ts +24 -0
  108. package/dist/contracts/Handlers/Attributes.js +84 -0
  109. package/dist/contracts/Handlers/Contexts.d.ts +18 -0
  110. package/dist/contracts/Handlers/Contexts.js +2 -0
  111. package/dist/contracts/Handlers/IZLinkChannelHandlers.d.ts +43 -0
  112. package/dist/contracts/Handlers/IZLinkChannelHandlers.js +2 -0
  113. package/dist/contracts/Handlers/IZLinkHandlerFilter.d.ts +15 -0
  114. package/dist/contracts/Handlers/IZLinkHandlerFilter.js +11 -0
  115. package/dist/contracts/Handlers/JsonContract.d.ts +46 -0
  116. package/dist/contracts/Handlers/JsonContract.js +137 -0
  117. package/dist/contracts/Handlers/ZLinkHandlerFilterNext.d.ts +1 -0
  118. package/dist/contracts/Handlers/ZLinkHandlerFilterNext.js +2 -0
  119. package/dist/contracts/Handlers/index.d.ts +5 -0
  120. package/dist/contracts/Handlers/index.js +33 -0
  121. package/dist/contracts/Locations/ActorTransfer.d.ts +41 -0
  122. package/dist/contracts/Locations/ActorTransfer.js +2 -0
  123. package/dist/contracts/Locations/Authority.d.ts +296 -0
  124. package/dist/contracts/Locations/Authority.js +17 -0
  125. package/dist/contracts/Locations/Diagnostics.d.ts +42 -0
  126. package/dist/contracts/Locations/Diagnostics.js +12 -0
  127. package/dist/contracts/Locations/Keys.d.ts +86 -0
  128. package/dist/contracts/Locations/Keys.js +2 -0
  129. package/dist/contracts/Locations/Models.d.ts +7 -0
  130. package/dist/contracts/Locations/Models.js +23 -0
  131. package/dist/contracts/Locations/Options.d.ts +23 -0
  132. package/dist/contracts/Locations/Options.js +20 -0
  133. package/dist/contracts/Locations/Readiness.d.ts +5 -0
  134. package/dist/contracts/Locations/Readiness.js +2 -0
  135. package/dist/contracts/Locations/RelocationStore.d.ts +38 -0
  136. package/dist/contracts/Locations/RelocationStore.js +2 -0
  137. package/dist/contracts/Locations/Resolvers.d.ts +4 -0
  138. package/dist/contracts/Locations/Resolvers.js +2 -0
  139. package/dist/contracts/Locations/Rows.d.ts +152 -0
  140. package/dist/contracts/Locations/Rows.js +19 -0
  141. package/dist/contracts/Locations/RuntimeQuery.d.ts +25 -0
  142. package/dist/contracts/Locations/RuntimeQuery.js +2 -0
  143. package/dist/contracts/Locations/Stores.d.ts +88 -0
  144. package/dist/contracts/Locations/Stores.js +2 -0
  145. package/dist/contracts/Locations/Values.d.ts +27 -0
  146. package/dist/contracts/Locations/Values.js +36 -0
  147. package/dist/contracts/Locations/Watch.d.ts +14 -0
  148. package/dist/contracts/Locations/Watch.js +12 -0
  149. package/dist/contracts/Locations/Writes.d.ts +48 -0
  150. package/dist/contracts/Locations/Writes.js +15 -0
  151. package/dist/contracts/Locations/index.d.ts +12 -0
  152. package/dist/contracts/Locations/index.js +30 -0
  153. package/dist/contracts/RouteMesh/Contracts.d.ts +102 -0
  154. package/dist/contracts/RouteMesh/Contracts.js +39 -0
  155. package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +165 -0
  156. package/dist/contracts/RouteMesh/RuntimeTopology.js +38 -0
  157. package/dist/contracts/RouteMesh/index.d.ts +2 -0
  158. package/dist/contracts/RouteMesh/index.js +18 -0
  159. package/dist/contracts/Spots/Builders.d.ts +10 -0
  160. package/dist/contracts/Spots/Builders.js +2 -0
  161. package/dist/contracts/Spots/Contracts.d.ts +110 -0
  162. package/dist/contracts/Spots/Contracts.js +9 -0
  163. package/dist/contracts/Spots/SpotKind.d.ts +8 -0
  164. package/dist/contracts/Spots/SpotKind.js +28 -0
  165. package/dist/contracts/Spots/ZLinkSpot.d.ts +62 -0
  166. package/dist/contracts/Spots/ZLinkSpot.js +15 -0
  167. package/dist/contracts/Spots/index.d.ts +3 -0
  168. package/dist/contracts/Spots/index.js +19 -0
  169. package/dist/contracts/Streams/BoundSessionContracts.d.ts +8 -0
  170. package/dist/contracts/Streams/BoundSessionContracts.js +2 -0
  171. package/dist/contracts/Streams/IZLinkSession.d.ts +44 -0
  172. package/dist/contracts/Streams/IZLinkSession.js +2 -0
  173. package/dist/contracts/Streams/IZLinkSessionActor.d.ts +15 -0
  174. package/dist/contracts/Streams/IZLinkSessionActor.js +2 -0
  175. package/dist/contracts/Streams/IZLinkSessionPacketHandler.d.ts +9 -0
  176. package/dist/contracts/Streams/IZLinkSessionPacketHandler.js +2 -0
  177. package/dist/contracts/Streams/IZLinkStream.d.ts +9 -0
  178. package/dist/contracts/Streams/IZLinkStream.js +2 -0
  179. package/dist/contracts/Streams/ZLinkMessageMetadata.d.ts +1 -0
  180. package/dist/contracts/Streams/ZLinkMessageMetadata.js +2 -0
  181. package/dist/contracts/Streams/ZLinkStreamCompression.d.ts +8 -0
  182. package/dist/contracts/Streams/ZLinkStreamCompression.js +2 -0
  183. package/dist/contracts/Streams/ZLinkStreamError.d.ts +8 -0
  184. package/dist/contracts/Streams/ZLinkStreamError.js +8 -0
  185. package/dist/contracts/Streams/index.d.ts +8 -0
  186. package/dist/contracts/Streams/index.js +24 -0
  187. package/dist/contracts/Timers/IZLinkTimer.d.ts +5 -0
  188. package/dist/contracts/Timers/IZLinkTimer.js +2 -0
  189. package/dist/contracts/Timers/ZLinkTimerOptions.d.ts +10 -0
  190. package/dist/contracts/Timers/ZLinkTimerOptions.js +9 -0
  191. package/dist/contracts/Timers/ZLinkTimerTick.d.ts +12 -0
  192. package/dist/contracts/Timers/ZLinkTimerTick.js +2 -0
  193. package/dist/contracts/Timers/index.d.ts +3 -0
  194. package/dist/contracts/Timers/index.js +19 -0
  195. package/dist/contracts/index.d.ts +25 -0
  196. package/dist/contracts/index.js +45 -0
  197. package/dist/index.d.ts +1 -0
  198. package/dist/index.js +17 -0
  199. package/dist/internal.d.ts +26 -0
  200. package/dist/internal.js +48 -0
  201. package/dist/location-store-integration.d.ts +5 -0
  202. package/dist/location-store-integration.js +31 -0
  203. package/dist/nest-integration.d.ts +49 -0
  204. package/dist/nest-integration.js +143 -0
  205. package/dist/runtime/abort.d.ts +13 -0
  206. package/dist/runtime/abort.js +71 -0
  207. package/dist/runtime/actors/actor-authority-payload-codec.d.ts +33 -0
  208. package/dist/runtime/actors/actor-authority-payload-codec.js +366 -0
  209. package/dist/runtime/actors/actor-authority-publication.d.ts +28 -0
  210. package/dist/runtime/actors/actor-authority-publication.js +207 -0
  211. package/dist/runtime/actors/actor-client.d.ts +36 -0
  212. package/dist/runtime/actors/actor-client.js +612 -0
  213. package/dist/runtime/actors/actor-context.d.ts +26 -0
  214. package/dist/runtime/actors/actor-context.js +433 -0
  215. package/dist/runtime/actors/actor-creation.d.ts +19 -0
  216. package/dist/runtime/actors/actor-creation.js +158 -0
  217. package/dist/runtime/actors/actor-execution-context.d.ts +6 -0
  218. package/dist/runtime/actors/actor-execution-context.js +27 -0
  219. package/dist/runtime/actors/actor-handoff.d.ts +191 -0
  220. package/dist/runtime/actors/actor-handoff.js +1252 -0
  221. package/dist/runtime/actors/actor-join-deferred-scope.d.ts +11 -0
  222. package/dist/runtime/actors/actor-join-deferred-scope.js +144 -0
  223. package/dist/runtime/actors/actor-join-relocation.d.ts +38 -0
  224. package/dist/runtime/actors/actor-join-relocation.js +2 -0
  225. package/dist/runtime/actors/actor-lifecycle-snapshot.d.ts +21 -0
  226. package/dist/runtime/actors/actor-lifecycle-snapshot.js +58 -0
  227. package/dist/runtime/actors/actor-local-native-join.d.ts +27 -0
  228. package/dist/runtime/actors/actor-local-native-join.js +409 -0
  229. package/dist/runtime/actors/actor-mailbox.d.ts +10 -0
  230. package/dist/runtime/actors/actor-mailbox.js +53 -0
  231. package/dist/runtime/actors/actor-message-follow-context.d.ts +46 -0
  232. package/dist/runtime/actors/actor-message-follow-context.js +257 -0
  233. package/dist/runtime/actors/actor-native-lookup.d.ts +4 -0
  234. package/dist/runtime/actors/actor-native-lookup.js +30 -0
  235. package/dist/runtime/actors/actor-packet-relay-wire.d.ts +73 -0
  236. package/dist/runtime/actors/actor-packet-relay-wire.js +144 -0
  237. package/dist/runtime/actors/actor-remote-joiner.d.ts +37 -0
  238. package/dist/runtime/actors/actor-remote-joiner.js +122 -0
  239. package/dist/runtime/actors/actor-remote-wire.d.ts +73 -0
  240. package/dist/runtime/actors/actor-remote-wire.js +84 -0
  241. package/dist/runtime/actors/actor-retry-delay.d.ts +5 -0
  242. package/dist/runtime/actors/actor-retry-delay.js +40 -0
  243. package/dist/runtime/actors/actor-routed-join-transport.d.ts +33 -0
  244. package/dist/runtime/actors/actor-routed-join-transport.js +2 -0
  245. package/dist/runtime/actors/actor-routed-json-request.d.ts +11 -0
  246. package/dist/runtime/actors/actor-routed-json-request.js +39 -0
  247. package/dist/runtime/actors/actor-runtime-contracts.d.ts +63 -0
  248. package/dist/runtime/actors/actor-runtime-contracts.js +2 -0
  249. package/dist/runtime/actors/actor-runtime-state.d.ts +152 -0
  250. package/dist/runtime/actors/actor-runtime-state.js +545 -0
  251. package/dist/runtime/actors/actor-source-transfer.d.ts +27 -0
  252. package/dist/runtime/actors/actor-source-transfer.js +2 -0
  253. package/dist/runtime/actors/actor-transfer-registry.d.ts +18 -0
  254. package/dist/runtime/actors/actor-transfer-registry.js +71 -0
  255. package/dist/runtime/actors/actor-transport-delivery-gate.d.ts +6 -0
  256. package/dist/runtime/actors/actor-transport-delivery-gate.js +4 -0
  257. package/dist/runtime/actors/bound-session-wire.d.ts +81 -0
  258. package/dist/runtime/actors/bound-session-wire.js +184 -0
  259. package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +47 -0
  260. package/dist/runtime/actors/deferred-join-accepted-journal.js +962 -0
  261. package/dist/runtime/actors/index.d.ts +79 -0
  262. package/dist/runtime/actors/index.js +639 -0
  263. package/dist/runtime/actors/post-commit-actor-binder.d.ts +18 -0
  264. package/dist/runtime/actors/post-commit-actor-binder.js +68 -0
  265. package/dist/runtime/actors/post-commit-actor-location.d.ts +19 -0
  266. package/dist/runtime/actors/post-commit-actor-location.js +72 -0
  267. package/dist/runtime/actors/spot-actor-dispatch.d.ts +59 -0
  268. package/dist/runtime/actors/spot-actor-dispatch.js +179 -0
  269. package/dist/runtime/actors/transferred-actor-rollback.d.ts +16 -0
  270. package/dist/runtime/actors/transferred-actor-rollback.js +91 -0
  271. package/dist/runtime/admission.d.ts +20 -0
  272. package/dist/runtime/admission.js +166 -0
  273. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +57 -0
  274. package/dist/runtime/application-jobs/application-ingress-record-owner.js +185 -0
  275. package/dist/runtime/application-jobs/application-job-queue-handler-start-gate.d.ts +8 -0
  276. package/dist/runtime/application-jobs/application-job-queue-handler-start-gate.js +8 -0
  277. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +17 -0
  278. package/dist/runtime/application-jobs/application-job-queue-scope.js +57 -0
  279. package/dist/runtime/application-jobs/contracts.d.ts +19 -0
  280. package/dist/runtime/application-jobs/contracts.js +2 -0
  281. package/dist/runtime/application-jobs/receive-flow-controller.d.ts +32 -0
  282. package/dist/runtime/application-jobs/receive-flow-controller.js +165 -0
  283. package/dist/runtime/backend/contracts/index.d.ts +487 -0
  284. package/dist/runtime/backend/contracts/index.js +29 -0
  285. package/dist/runtime/backend/index.d.ts +9 -0
  286. package/dist/runtime/backend/index.js +25 -0
  287. package/dist/runtime/backend/mesh-actor-session-node-adapter.d.ts +3 -0
  288. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +51 -0
  289. package/dist/runtime/backend/mesh-completion-table.d.ts +34 -0
  290. package/dist/runtime/backend/mesh-completion-table.js +124 -0
  291. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +48 -0
  292. package/dist/runtime/backend/mesh-dispatch-pump.js +322 -0
  293. package/dist/runtime/backend/mesh-record-dispatcher.d.ts +19 -0
  294. package/dist/runtime/backend/mesh-record-dispatcher.js +53 -0
  295. package/dist/runtime/backend/node/index.d.ts +4 -0
  296. package/dist/runtime/backend/node/index.js +22 -0
  297. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +12 -0
  298. package/dist/runtime/backend/node/node-backend-adapter-factory.js +161 -0
  299. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +52 -0
  300. package/dist/runtime/backend/node/node-backend-adapter-support.js +203 -0
  301. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +13 -0
  302. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +52 -0
  303. package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +11 -0
  304. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +23 -0
  305. package/dist/runtime/backend/node/node-monitor-backend-adapter.d.ts +6 -0
  306. package/dist/runtime/backend/node/node-monitor-backend-adapter.js +38 -0
  307. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +8 -0
  308. package/dist/runtime/backend/node/node-raw-binding-port.js +411 -0
  309. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +266 -0
  310. package/dist/runtime/backend/node/node-raw-mesh-backend.js +1707 -0
  311. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +9 -0
  312. package/dist/runtime/backend/node/node-socket-backend-adapter.js +286 -0
  313. package/dist/runtime/backend/node-backend-adapter.d.ts +9 -0
  314. package/dist/runtime/backend/node-backend-adapter.js +12 -0
  315. package/dist/runtime/backend/raw-binding-port.d.ts +58 -0
  316. package/dist/runtime/backend/raw-binding-port.js +2 -0
  317. package/dist/runtime/backend/runtime-message.d.ts +14 -0
  318. package/dist/runtime/backend/runtime-message.js +44 -0
  319. package/dist/runtime/backend/runtime-values.d.ts +78 -0
  320. package/dist/runtime/backend/runtime-values.js +66 -0
  321. package/dist/runtime/channels/channel-autoconnect.d.ts +14 -0
  322. package/dist/runtime/channels/channel-autoconnect.js +23 -0
  323. package/dist/runtime/channels/channel-clients.d.ts +50 -0
  324. package/dist/runtime/channels/channel-clients.js +329 -0
  325. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +76 -0
  326. package/dist/runtime/channels/channel-dispatch-pipeline.js +237 -0
  327. package/dist/runtime/channels/channel-dispatch-services.d.ts +52 -0
  328. package/dist/runtime/channels/channel-dispatch-services.js +132 -0
  329. package/dist/runtime/channels/channel-dispatchers.d.ts +125 -0
  330. package/dist/runtime/channels/channel-dispatchers.js +575 -0
  331. package/dist/runtime/channels/channel-envelope-inspection.d.ts +25 -0
  332. package/dist/runtime/channels/channel-envelope-inspection.js +96 -0
  333. package/dist/runtime/channels/channel-envelope.d.ts +73 -0
  334. package/dist/runtime/channels/channel-envelope.js +546 -0
  335. package/dist/runtime/channels/channel-framework-packets.d.ts +2 -0
  336. package/dist/runtime/channels/channel-framework-packets.js +6 -0
  337. package/dist/runtime/channels/channel-multipart.d.ts +16 -0
  338. package/dist/runtime/channels/channel-multipart.js +31 -0
  339. package/dist/runtime/channels/channel-outbound-operations.d.ts +33 -0
  340. package/dist/runtime/channels/channel-outbound-operations.js +343 -0
  341. package/dist/runtime/channels/channel-receive-loops.d.ts +151 -0
  342. package/dist/runtime/channels/channel-receive-loops.js +728 -0
  343. package/dist/runtime/channels/channel-receive-task-tracker.d.ts +14 -0
  344. package/dist/runtime/channels/channel-receive-task-tracker.js +37 -0
  345. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +77 -0
  346. package/dist/runtime/channels/channel-runtime-lifecycle.js +630 -0
  347. package/dist/runtime/channels/channel-runtime-manager.d.ts +84 -0
  348. package/dist/runtime/channels/channel-runtime-manager.js +193 -0
  349. package/dist/runtime/channels/channel-socket-options.d.ts +18 -0
  350. package/dist/runtime/channels/channel-socket-options.js +119 -0
  351. package/dist/runtime/channels/channel-socket-registry.d.ts +157 -0
  352. package/dist/runtime/channels/channel-socket-registry.js +1428 -0
  353. package/dist/runtime/channels/channel-transports.d.ts +126 -0
  354. package/dist/runtime/channels/channel-transports.js +448 -0
  355. package/dist/runtime/channels/client-server-location-runtime.d.ts +41 -0
  356. package/dist/runtime/channels/client-server-location-runtime.js +465 -0
  357. package/dist/runtime/channels/client-server-service-wire.d.ts +48 -0
  358. package/dist/runtime/channels/client-server-service-wire.js +306 -0
  359. package/dist/runtime/channels/dispatch-error-reporter.d.ts +22 -0
  360. package/dist/runtime/channels/dispatch-error-reporter.js +133 -0
  361. package/dist/runtime/channels/fanout-location-runtime.d.ts +38 -0
  362. package/dist/runtime/channels/fanout-location-runtime.js +356 -0
  363. package/dist/runtime/channels/fanout-service-wire.d.ts +12 -0
  364. package/dist/runtime/channels/fanout-service-wire.js +29 -0
  365. package/dist/runtime/channels/handler-filter-scope.d.ts +8 -0
  366. package/dist/runtime/channels/handler-filter-scope.js +11 -0
  367. package/dist/runtime/channels/index.d.ts +9 -0
  368. package/dist/runtime/channels/index.js +30 -0
  369. package/dist/runtime/channels/local-spot-route-transport.d.ts +9 -0
  370. package/dist/runtime/channels/local-spot-route-transport.js +40 -0
  371. package/dist/runtime/channels/route-disconnected-error.d.ts +3 -0
  372. package/dist/runtime/channels/route-disconnected-error.js +10 -0
  373. package/dist/runtime/channels/route-member-snapshot.d.ts +10 -0
  374. package/dist/runtime/channels/route-member-snapshot.js +55 -0
  375. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +12 -0
  376. package/dist/runtime/channels/router-socket-spot-route-transport.js +43 -0
  377. package/dist/runtime/channels/source-spot-router.d.ts +10 -0
  378. package/dist/runtime/channels/source-spot-router.js +46 -0
  379. package/dist/runtime/channels/spot-direct-envelope.d.ts +5 -0
  380. package/dist/runtime/channels/spot-direct-envelope.js +29 -0
  381. package/dist/runtime/channels/spot-node-route-transport.d.ts +13 -0
  382. package/dist/runtime/channels/spot-node-route-transport.js +60 -0
  383. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +14 -0
  384. package/dist/runtime/channels/spot-route-bridge-transport.js +58 -0
  385. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +50 -0
  386. package/dist/runtime/channels/spot-route-dispatch-strategy.js +128 -0
  387. package/dist/runtime/channels/spot-route-target-resolver.d.ts +16 -0
  388. package/dist/runtime/channels/spot-route-target-resolver.js +92 -0
  389. package/dist/runtime/codecs/index.d.ts +14 -0
  390. package/dist/runtime/codecs/index.js +44 -0
  391. package/dist/runtime/configuration/index.d.ts +1 -0
  392. package/dist/runtime/configuration/index.js +17 -0
  393. package/dist/runtime/diagnostics/dispatch-error-port.d.ts +8 -0
  394. package/dist/runtime/diagnostics/dispatch-error-port.js +2 -0
  395. package/dist/runtime/diagnostics/flow-context.d.ts +21 -0
  396. package/dist/runtime/diagnostics/flow-context.js +68 -0
  397. package/dist/runtime/diagnostics/index.d.ts +82 -0
  398. package/dist/runtime/diagnostics/index.js +335 -0
  399. package/dist/runtime/diagnostics/internal-event-contracts.d.ts +139 -0
  400. package/dist/runtime/diagnostics/internal-event-contracts.js +68 -0
  401. package/dist/runtime/diagnostics/message-flow.d.ts +55 -0
  402. package/dist/runtime/diagnostics/message-flow.js +420 -0
  403. package/dist/runtime/diagnostics/runtime-metrics.d.ts +123 -0
  404. package/dist/runtime/diagnostics/runtime-metrics.js +454 -0
  405. package/dist/runtime/diagnostics/runtime-observation-queue.d.ts +58 -0
  406. package/dist/runtime/diagnostics/runtime-observation-queue.js +324 -0
  407. package/dist/runtime/diagnostics/topology-runtime-projections.d.ts +33 -0
  408. package/dist/runtime/diagnostics/topology-runtime-projections.js +255 -0
  409. package/dist/runtime/execution/index.d.ts +114 -0
  410. package/dist/runtime/execution/index.js +363 -0
  411. package/dist/runtime/execution/serial-execution-queue.d.ts +94 -0
  412. package/dist/runtime/execution/serial-execution-queue.js +411 -0
  413. package/dist/runtime/execution/serial-work-size.d.ts +4 -0
  414. package/dist/runtime/execution/serial-work-size.js +28 -0
  415. package/dist/runtime/execution/state-lane.d.ts +28 -0
  416. package/dist/runtime/execution/state-lane.js +105 -0
  417. package/dist/runtime/foundation/actor-join-recovery-codec.d.ts +72 -0
  418. package/dist/runtime/foundation/actor-join-recovery-codec.js +333 -0
  419. package/dist/runtime/foundation/event-loop-resources.d.ts +37 -0
  420. package/dist/runtime/foundation/event-loop-resources.js +163 -0
  421. package/dist/runtime/foundation/index.d.ts +18 -0
  422. package/dist/runtime/foundation/index.js +34 -0
  423. package/dist/runtime/foundation/message-follow-suppression-registry.d.ts +38 -0
  424. package/dist/runtime/foundation/message-follow-suppression-registry.js +89 -0
  425. package/dist/runtime/foundation/operation-identity.d.ts +12 -0
  426. package/dist/runtime/foundation/operation-identity.js +33 -0
  427. package/dist/runtime/foundation/operation-registry.d.ts +42 -0
  428. package/dist/runtime/foundation/operation-registry.js +146 -0
  429. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +143 -0
  430. package/dist/runtime/foundation/raw-service-mesh-runtime.js +1349 -0
  431. package/dist/runtime/foundation/route-mesh-connection-policy.d.ts +3 -0
  432. package/dist/runtime/foundation/route-mesh-connection-policy.js +13 -0
  433. package/dist/runtime/foundation/runtime-state-projections.d.ts +13 -0
  434. package/dist/runtime/foundation/runtime-state-projections.js +44 -0
  435. package/dist/runtime/foundation/service-authority-payload-codec.d.ts +56 -0
  436. package/dist/runtime/foundation/service-authority-payload-codec.js +411 -0
  437. package/dist/runtime/foundation/service-discovery-registry.d.ts +42 -0
  438. package/dist/runtime/foundation/service-discovery-registry.js +175 -0
  439. package/dist/runtime/foundation/service-instance-activation-recovery-codec.d.ts +19 -0
  440. package/dist/runtime/foundation/service-instance-activation-recovery-codec.js +287 -0
  441. package/dist/runtime/foundation/service-liveness-registry.d.ts +28 -0
  442. package/dist/runtime/foundation/service-liveness-registry.js +109 -0
  443. package/dist/runtime/foundation/service-mailbox.d.ts +60 -0
  444. package/dist/runtime/foundation/service-mailbox.js +283 -0
  445. package/dist/runtime/foundation/service-maintenance-runtime.d.ts +45 -0
  446. package/dist/runtime/foundation/service-maintenance-runtime.js +198 -0
  447. package/dist/runtime/foundation/service-metadata-codec.d.ts +2 -0
  448. package/dist/runtime/foundation/service-metadata-codec.js +69 -0
  449. package/dist/runtime/foundation/service-relocation-aggregate-committer.d.ts +35 -0
  450. package/dist/runtime/foundation/service-relocation-aggregate-committer.js +139 -0
  451. package/dist/runtime/foundation/service-relocation-coordinator.d.ts +19 -0
  452. package/dist/runtime/foundation/service-relocation-coordinator.js +16 -0
  453. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +71 -0
  454. package/dist/runtime/foundation/service-relocation-object-owner.js +242 -0
  455. package/dist/runtime/foundation/service-relocation-runtime.d.ts +143 -0
  456. package/dist/runtime/foundation/service-relocation-runtime.js +1080 -0
  457. package/dist/runtime/foundation/service-runtime-contracts.d.ts +332 -0
  458. package/dist/runtime/foundation/service-runtime-contracts.js +66 -0
  459. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +23 -0
  460. package/dist/runtime/foundation/service-session-binding-ingress-port.js +11 -0
  461. package/dist/runtime/foundation/service-stateful-registry.d.ts +142 -0
  462. package/dist/runtime/foundation/service-stateful-registry.js +465 -0
  463. package/dist/runtime/foundation/service-stateful-runtime.d.ts +393 -0
  464. package/dist/runtime/foundation/service-stateful-runtime.js +3898 -0
  465. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +597 -0
  466. package/dist/runtime/foundation/service-stateful-wire-codec.js +2006 -0
  467. package/dist/runtime/foundation/service-topology-registry.d.ts +68 -0
  468. package/dist/runtime/foundation/service-topology-registry.js +393 -0
  469. package/dist/runtime/foundation/service-weighted-selection.d.ts +14 -0
  470. package/dist/runtime/foundation/service-weighted-selection.js +128 -0
  471. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +10 -0
  472. package/dist/runtime/foundation/service-wire-binary-primitives.js +53 -0
  473. package/dist/runtime/foundation/service-wire-codec.d.ts +22 -0
  474. package/dist/runtime/foundation/service-wire-codec.js +67 -0
  475. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +110 -0
  476. package/dist/runtime/foundation/service-wire-constants.generated.js +132 -0
  477. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +102 -0
  478. package/dist/runtime/foundation/service-wire-m6a-codec.js +568 -0
  479. package/dist/runtime/framework-errors-internal.d.ts +95 -0
  480. package/dist/runtime/framework-errors-internal.js +301 -0
  481. package/dist/runtime/handlers/handler-instance-scope.d.ts +11 -0
  482. package/dist/runtime/handlers/handler-instance-scope.js +284 -0
  483. package/dist/runtime/handlers/index.d.ts +13 -0
  484. package/dist/runtime/handlers/index.js +57 -0
  485. package/dist/runtime/host/actor-packet-relay.d.ts +60 -0
  486. package/dist/runtime/host/actor-packet-relay.js +664 -0
  487. package/dist/runtime/host/actor-placement-coordinator.d.ts +32 -0
  488. package/dist/runtime/host/actor-placement-coordinator.js +386 -0
  489. package/dist/runtime/host/actor-runtime-options-factory.d.ts +65 -0
  490. package/dist/runtime/host/actor-runtime-options-factory.js +160 -0
  491. package/dist/runtime/host/actor-transfer-authority-runtime.d.ts +26 -0
  492. package/dist/runtime/host/actor-transfer-authority-runtime.js +138 -0
  493. package/dist/runtime/host/actor-transfer-runtime.d.ts +149 -0
  494. package/dist/runtime/host/actor-transfer-runtime.js +1245 -0
  495. package/dist/runtime/host/application-job-queue.d.ts +99 -0
  496. package/dist/runtime/host/application-job-queue.js +409 -0
  497. package/dist/runtime/host/bound-session-relay.d.ts +41 -0
  498. package/dist/runtime/host/bound-session-relay.js +52 -0
  499. package/dist/runtime/host/bounded-replay-map.d.ts +12 -0
  500. package/dist/runtime/host/bounded-replay-map.js +42 -0
  501. package/dist/runtime/host/channel-runtime-options-factory.d.ts +22 -0
  502. package/dist/runtime/host/channel-runtime-options-factory.js +76 -0
  503. package/dist/runtime/host/entry-actor-runtime.d.ts +30 -0
  504. package/dist/runtime/host/entry-actor-runtime.js +80 -0
  505. package/dist/runtime/host/host-capacity-status.d.ts +11 -0
  506. package/dist/runtime/host/host-capacity-status.js +85 -0
  507. package/dist/runtime/host/index.d.ts +188 -0
  508. package/dist/runtime/host/index.js +2552 -0
  509. package/dist/runtime/host/instance-activation-authority.d.ts +33 -0
  510. package/dist/runtime/host/instance-activation-authority.js +496 -0
  511. package/dist/runtime/host/location-runtime-owner.d.ts +48 -0
  512. package/dist/runtime/host/location-runtime-owner.js +227 -0
  513. package/dist/runtime/host/mesh-router-resolver.d.ts +16 -0
  514. package/dist/runtime/host/mesh-router-resolver.js +108 -0
  515. package/dist/runtime/host/relocation-direct-transfer.d.ts +81 -0
  516. package/dist/runtime/host/relocation-direct-transfer.js +240 -0
  517. package/dist/runtime/host/relocation-integrity-fault-gate.d.ts +6 -0
  518. package/dist/runtime/host/relocation-integrity-fault-gate.js +5 -0
  519. package/dist/runtime/host/relocation-state-adapter.d.ts +8 -0
  520. package/dist/runtime/host/relocation-state-adapter.js +13 -0
  521. package/dist/runtime/host/remote-actor-join-receiver.d.ts +47 -0
  522. package/dist/runtime/host/remote-actor-join-receiver.js +161 -0
  523. package/dist/runtime/host/remote-actor-packet-target-store.d.ts +29 -0
  524. package/dist/runtime/host/remote-actor-packet-target-store.js +185 -0
  525. package/dist/runtime/host/remote-bound-session-relay.d.ts +58 -0
  526. package/dist/runtime/host/remote-bound-session-relay.js +540 -0
  527. package/dist/runtime/host/route-mesh-runtime-options.d.ts +9 -0
  528. package/dist/runtime/host/route-mesh-runtime-options.js +41 -0
  529. package/dist/runtime/host/route-mesh-runtime.d.ts +76 -0
  530. package/dist/runtime/host/route-mesh-runtime.js +746 -0
  531. package/dist/runtime/host/runtime-shutdown.d.ts +33 -0
  532. package/dist/runtime/host/runtime-shutdown.js +68 -0
  533. package/dist/runtime/host/service-relocation-control.d.ts +7 -0
  534. package/dist/runtime/host/service-relocation-control.js +24 -0
  535. package/dist/runtime/host/service-relocation-host-runtime.d.ts +241 -0
  536. package/dist/runtime/host/service-relocation-host-runtime.js +4113 -0
  537. package/dist/runtime/host/spot-address-transport.d.ts +47 -0
  538. package/dist/runtime/host/spot-address-transport.js +601 -0
  539. package/dist/runtime/host/spot-node-runtime-options-factory.d.ts +38 -0
  540. package/dist/runtime/host/spot-node-runtime-options-factory.js +36 -0
  541. package/dist/runtime/host/spot-runtime-options-factory.d.ts +48 -0
  542. package/dist/runtime/host/spot-runtime-options-factory.js +169 -0
  543. package/dist/runtime/host/stateful-authority-route-runtime.d.ts +34 -0
  544. package/dist/runtime/host/stateful-authority-route-runtime.js +440 -0
  545. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +69 -0
  546. package/dist/runtime/host/user-spot-creation-coordinator.js +759 -0
  547. package/dist/runtime/locations/actor-location-claims.d.ts +43 -0
  548. package/dist/runtime/locations/actor-location-claims.js +319 -0
  549. package/dist/runtime/locations/actor-session-route-claims.d.ts +10 -0
  550. package/dist/runtime/locations/actor-session-route-claims.js +51 -0
  551. package/dist/runtime/locations/aggregate-inventory-store.d.ts +18 -0
  552. package/dist/runtime/locations/aggregate-inventory-store.js +399 -0
  553. package/dist/runtime/locations/authority-key-codec.d.ts +6 -0
  554. package/dist/runtime/locations/authority-key-codec.js +78 -0
  555. package/dist/runtime/locations/auto-connect-loop.d.ts +37 -0
  556. package/dist/runtime/locations/auto-connect-loop.js +112 -0
  557. package/dist/runtime/locations/auto-connect-planner.d.ts +9 -0
  558. package/dist/runtime/locations/auto-connect-planner.js +137 -0
  559. package/dist/runtime/locations/auto-connect-reconciler.d.ts +57 -0
  560. package/dist/runtime/locations/auto-connect-reconciler.js +358 -0
  561. package/dist/runtime/locations/auto-connect-types.d.ts +42 -0
  562. package/dist/runtime/locations/auto-connect-types.js +2 -0
  563. package/dist/runtime/locations/auto-connect.d.ts +4 -0
  564. package/dist/runtime/locations/auto-connect.js +20 -0
  565. package/dist/runtime/locations/canonical-codec.d.ts +7 -0
  566. package/dist/runtime/locations/canonical-codec.js +48 -0
  567. package/dist/runtime/locations/domain-store-contract.d.ts +34 -0
  568. package/dist/runtime/locations/domain-store-contract.js +2 -0
  569. package/dist/runtime/locations/in-memory-authority-store.d.ts +51 -0
  570. package/dist/runtime/locations/in-memory-authority-store.js +895 -0
  571. package/dist/runtime/locations/in-memory-location-store.d.ts +78 -0
  572. package/dist/runtime/locations/in-memory-location-store.js +1008 -0
  573. package/dist/runtime/locations/in-memory-provider-location-store.d.ts +19 -0
  574. package/dist/runtime/locations/in-memory-provider-location-store.js +183 -0
  575. package/dist/runtime/locations/index.d.ts +11 -0
  576. package/dist/runtime/locations/index.js +27 -0
  577. package/dist/runtime/locations/internal-location-contracts.d.ts +7 -0
  578. package/dist/runtime/locations/internal-location-contracts.js +21 -0
  579. package/dist/runtime/locations/internal-store-contracts.d.ts +35 -0
  580. package/dist/runtime/locations/internal-store-contracts.js +2 -0
  581. package/dist/runtime/locations/key-codec.d.ts +13 -0
  582. package/dist/runtime/locations/key-codec.js +41 -0
  583. package/dist/runtime/locations/lease-tracker.d.ts +36 -0
  584. package/dist/runtime/locations/lease-tracker.js +155 -0
  585. package/dist/runtime/locations/lifecycle-runtime.d.ts +19 -0
  586. package/dist/runtime/locations/lifecycle-runtime.js +2 -0
  587. package/dist/runtime/locations/lifecycle.d.ts +40 -0
  588. package/dist/runtime/locations/lifecycle.js +120 -0
  589. package/dist/runtime/locations/location-store-repository.d.ts +72 -0
  590. package/dist/runtime/locations/location-store-repository.js +3198 -0
  591. package/dist/runtime/locations/relocation-blob.d.ts +7 -0
  592. package/dist/runtime/locations/relocation-blob.js +24 -0
  593. package/dist/runtime/locations/resolvers.d.ts +145 -0
  594. package/dist/runtime/locations/resolvers.js +693 -0
  595. package/dist/runtime/locations/runtime.d.ts +144 -0
  596. package/dist/runtime/locations/runtime.js +792 -0
  597. package/dist/runtime/locations/spot-location-claims.d.ts +36 -0
  598. package/dist/runtime/locations/spot-location-claims.js +305 -0
  599. package/dist/runtime/messaging/creation-payload-codec.d.ts +4 -0
  600. package/dist/runtime/messaging/creation-payload-codec.js +40 -0
  601. package/dist/runtime/messaging/framework-json-v1.d.ts +7 -0
  602. package/dist/runtime/messaging/framework-json-v1.js +296 -0
  603. package/dist/runtime/messaging/index.d.ts +1 -0
  604. package/dist/runtime/messaging/index.js +2 -0
  605. package/dist/runtime/messaging/packet-name.d.ts +4 -0
  606. package/dist/runtime/messaging/packet-name.js +79 -0
  607. package/dist/runtime/messaging/payload-codec.d.ts +25 -0
  608. package/dist/runtime/messaging/payload-codec.js +255 -0
  609. package/dist/runtime/messaging/submission-result.d.ts +15 -0
  610. package/dist/runtime/messaging/submission-result.js +37 -0
  611. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +395 -0
  612. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +645 -0
  613. package/dist/runtime/routing-id.d.ts +8 -0
  614. package/dist/runtime/routing-id.js +112 -0
  615. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +124 -0
  616. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +269 -0
  617. package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +33 -0
  618. package/dist/runtime/spots/formal-remote-actor-transfer-registry.js +94 -0
  619. package/dist/runtime/spots/index.d.ts +247 -0
  620. package/dist/runtime/spots/index.js +2090 -0
  621. package/dist/runtime/spots/spot-activation-registry.d.ts +47 -0
  622. package/dist/runtime/spots/spot-activation-registry.js +272 -0
  623. package/dist/runtime/spots/spot-activation-state.d.ts +104 -0
  624. package/dist/runtime/spots/spot-activation-state.js +288 -0
  625. package/dist/runtime/spots/spot-activation.d.ts +89 -0
  626. package/dist/runtime/spots/spot-activation.js +601 -0
  627. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +20 -0
  628. package/dist/runtime/spots/spot-actor-admission-coordinator.js +194 -0
  629. package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +83 -0
  630. package/dist/runtime/spots/spot-actor-join-dispatch.js +185 -0
  631. package/dist/runtime/spots/spot-actor-lifecycle-drain.d.ts +22 -0
  632. package/dist/runtime/spots/spot-actor-lifecycle-drain.js +51 -0
  633. package/dist/runtime/spots/spot-actor-membership.d.ts +39 -0
  634. package/dist/runtime/spots/spot-actor-membership.js +179 -0
  635. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +91 -0
  636. package/dist/runtime/spots/spot-actor-packet-dispatch.js +315 -0
  637. package/dist/runtime/spots/spot-actor-packet-drain.d.ts +40 -0
  638. package/dist/runtime/spots/spot-actor-packet-drain.js +235 -0
  639. package/dist/runtime/spots/spot-actor-packet-relay-dispatch.d.ts +18 -0
  640. package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +110 -0
  641. package/dist/runtime/spots/spot-closing.d.ts +2 -0
  642. package/dist/runtime/spots/spot-closing.js +30 -0
  643. package/dist/runtime/spots/spot-context.d.ts +46 -0
  644. package/dist/runtime/spots/spot-context.js +113 -0
  645. package/dist/runtime/spots/spot-entry-activation.d.ts +107 -0
  646. package/dist/runtime/spots/spot-entry-activation.js +342 -0
  647. package/dist/runtime/spots/spot-handle.d.ts +28 -0
  648. package/dist/runtime/spots/spot-handle.js +38 -0
  649. package/dist/runtime/spots/spot-handler-registry.d.ts +52 -0
  650. package/dist/runtime/spots/spot-handler-registry.js +155 -0
  651. package/dist/runtime/spots/spot-lifecycle-metrics.d.ts +8 -0
  652. package/dist/runtime/spots/spot-lifecycle-metrics.js +16 -0
  653. package/dist/runtime/spots/spot-location-claim.d.ts +25 -0
  654. package/dist/runtime/spots/spot-location-claim.js +55 -0
  655. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +10 -0
  656. package/dist/runtime/spots/spot-manager-internal-contracts.js +2 -0
  657. package/dist/runtime/spots/spot-manager-public.d.ts +32 -0
  658. package/dist/runtime/spots/spot-manager-public.js +219 -0
  659. package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +26 -0
  660. package/dist/runtime/spots/spot-native-actor-join-admission.js +105 -0
  661. package/dist/runtime/spots/spot-native-flags.d.ts +2 -0
  662. package/dist/runtime/spots/spot-native-flags.js +5 -0
  663. package/dist/runtime/spots/spot-node-autoconnect.d.ts +23 -0
  664. package/dist/runtime/spots/spot-node-autoconnect.js +246 -0
  665. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +137 -0
  666. package/dist/runtime/spots/spot-node-runtime-manager.js +1111 -0
  667. package/dist/runtime/spots/spot-outbound.d.ts +78 -0
  668. package/dist/runtime/spots/spot-outbound.js +460 -0
  669. package/dist/runtime/spots/spot-provider.d.ts +4 -0
  670. package/dist/runtime/spots/spot-provider.js +28 -0
  671. package/dist/runtime/spots/spot-publisher-transport.d.ts +14 -0
  672. package/dist/runtime/spots/spot-publisher-transport.js +28 -0
  673. package/dist/runtime/spots/spot-remote-codec.d.ts +50 -0
  674. package/dist/runtime/spots/spot-remote-codec.js +190 -0
  675. package/dist/runtime/spots/spot-remote-route-codec.d.ts +47 -0
  676. package/dist/runtime/spots/spot-remote-route-codec.js +168 -0
  677. package/dist/runtime/spots/spot-route-packet-dispatch.d.ts +25 -0
  678. package/dist/runtime/spots/spot-route-packet-dispatch.js +238 -0
  679. package/dist/runtime/spots/spot-route-replies.d.ts +17 -0
  680. package/dist/runtime/spots/spot-route-replies.js +76 -0
  681. package/dist/runtime/spots/spot-route-reply-wire.d.ts +10 -0
  682. package/dist/runtime/spots/spot-route-reply-wire.js +6 -0
  683. package/dist/runtime/spots/spot-routed-actor-admission.d.ts +36 -0
  684. package/dist/runtime/spots/spot-routed-actor-admission.js +240 -0
  685. package/dist/runtime/spots/spot-routed-bound-session-dispatch.d.ts +19 -0
  686. package/dist/runtime/spots/spot-routed-bound-session-dispatch.js +46 -0
  687. package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +54 -0
  688. package/dist/runtime/spots/spot-routed-frame-dispatch.js +162 -0
  689. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +43 -0
  690. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +152 -0
  691. package/dist/runtime/spots/spot-routing-internal.d.ts +28 -0
  692. package/dist/runtime/spots/spot-routing-internal.js +2 -0
  693. package/dist/runtime/spots/spot-runtime-ports.d.ts +64 -0
  694. package/dist/runtime/spots/spot-runtime-ports.js +2 -0
  695. package/dist/runtime/spots/spot-serial-executor.d.ts +38 -0
  696. package/dist/runtime/spots/spot-serial-executor.js +133 -0
  697. package/dist/runtime/spots/spot-serial-turn-executor.d.ts +54 -0
  698. package/dist/runtime/spots/spot-serial-turn-executor.js +219 -0
  699. package/dist/runtime/spots/spot-subscription-dispatch.d.ts +32 -0
  700. package/dist/runtime/spots/spot-subscription-dispatch.js +194 -0
  701. package/dist/runtime/spots/spot-timer.d.ts +110 -0
  702. package/dist/runtime/spots/spot-timer.js +419 -0
  703. package/dist/runtime/streams/actor-session-binding-registry.d.ts +193 -0
  704. package/dist/runtime/streams/actor-session-binding-registry.js +1127 -0
  705. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +20 -0
  706. package/dist/runtime/streams/actor-session-binding-runtime-owner.js +19 -0
  707. package/dist/runtime/streams/actor-session-lifecycle-coordinator.d.ts +4 -0
  708. package/dist/runtime/streams/actor-session-lifecycle-coordinator.js +24 -0
  709. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +29 -0
  710. package/dist/runtime/streams/bound-actor-relay-sender.js +181 -0
  711. package/dist/runtime/streams/bound-session-response-target.d.ts +25 -0
  712. package/dist/runtime/streams/bound-session-response-target.js +54 -0
  713. package/dist/runtime/streams/bound-session-service.d.ts +48 -0
  714. package/dist/runtime/streams/bound-session-service.js +201 -0
  715. package/dist/runtime/streams/index.d.ts +152 -0
  716. package/dist/runtime/streams/index.js +338 -0
  717. package/dist/runtime/streams/managed-stream.d.ts +53 -0
  718. package/dist/runtime/streams/managed-stream.js +329 -0
  719. package/dist/runtime/streams/native-fallback-bound-session.d.ts +24 -0
  720. package/dist/runtime/streams/native-fallback-bound-session.js +201 -0
  721. package/dist/runtime/streams/protocol.d.ts +67 -0
  722. package/dist/runtime/streams/protocol.js +244 -0
  723. package/dist/runtime/streams/session-actor-coordinator.d.ts +56 -0
  724. package/dist/runtime/streams/session-actor-coordinator.js +371 -0
  725. package/dist/runtime/streams/session-calls.d.ts +59 -0
  726. package/dist/runtime/streams/session-calls.js +123 -0
  727. package/dist/runtime/streams/session-context.d.ts +108 -0
  728. package/dist/runtime/streams/session-context.js +377 -0
  729. package/dist/runtime/streams/session-local-actors.d.ts +10 -0
  730. package/dist/runtime/streams/session-local-actors.js +26 -0
  731. package/dist/runtime/streams/session-provider.d.ts +4 -0
  732. package/dist/runtime/streams/session-provider.js +30 -0
  733. package/dist/runtime/streams/session-requests.d.ts +25 -0
  734. package/dist/runtime/streams/session-requests.js +100 -0
  735. package/dist/runtime/streams/session-serial-executor.d.ts +12 -0
  736. package/dist/runtime/streams/session-serial-executor.js +58 -0
  737. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +62 -0
  738. package/dist/runtime/streams/stream-binding-runtime-ports.js +2 -0
  739. package/dist/runtime/streams/stream-frame-factory.d.ts +44 -0
  740. package/dist/runtime/streams/stream-frame-factory.js +149 -0
  741. package/dist/runtime/streams/stream-message-utils.d.ts +5 -0
  742. package/dist/runtime/streams/stream-message-utils.js +74 -0
  743. package/dist/runtime/streams/stream-session-runtime.d.ts +166 -0
  744. package/dist/runtime/streams/stream-session-runtime.js +1144 -0
  745. package/dist/runtime/workers/index.d.ts +38 -0
  746. package/dist/runtime/workers/index.js +474 -0
  747. package/package.json +19 -0
  748. package/src/contracts/Actors/ZLinkActor.ts +8 -0
  749. package/src/contracts/Actors/ZLinkActorClient.ts +18 -0
  750. package/src/contracts/Actors/ZLinkActorContext.ts +15 -0
  751. package/src/contracts/Actors/ZLinkActorFactory.ts +41 -0
  752. package/src/contracts/Actors/ZLinkActorManager.ts +31 -0
  753. package/src/contracts/Actors/index.ts +5 -0
  754. package/src/contracts/Channels/Calls.ts +33 -0
  755. package/src/contracts/Channels/IZLinkChannelClient.ts +6 -0
  756. package/src/contracts/Channels/IZLinkFanoutClient.ts +13 -0
  757. package/src/contracts/Channels/RouteCalls.ts +13 -0
  758. package/src/contracts/Channels/index.ts +4 -0
  759. package/src/contracts/Codecs/IZLinkCodecRegistryBuilder.ts +22 -0
  760. package/src/contracts/Codecs/ZLinkMessageSerializer.ts +6 -0
  761. package/src/contracts/Codecs/index.ts +2 -0
  762. package/src/contracts/Common/ActorRef.ts +8 -0
  763. package/src/contracts/Common/CoreTypes.ts +6 -0
  764. package/src/contracts/Common/Message.ts +9 -0
  765. package/src/contracts/Common/ZLinkEncodedPayload.ts +47 -0
  766. package/src/contracts/Common/ZLinkMessage.ts +135 -0
  767. package/src/contracts/Common/ZLinkMessageMetadata.ts +77 -0
  768. package/src/contracts/Common/ZLinkProviderResolver.ts +6 -0
  769. package/src/contracts/Common/encoded-payload-storage.ts +16 -0
  770. package/src/contracts/Common/index.ts +5 -0
  771. package/src/contracts/Configuration/Builders.ts +200 -0
  772. package/src/contracts/Configuration/CodecContentType.ts +68 -0
  773. package/src/contracts/Configuration/CodecSerializerSelection.ts +28 -0
  774. package/src/contracts/Configuration/Configs.ts +27 -0
  775. package/src/contracts/Configuration/ConfigurationException.ts +6 -0
  776. package/src/contracts/Configuration/Connections.ts +5 -0
  777. package/src/contracts/Configuration/DiagnosticsValidation.ts +25 -0
  778. package/src/contracts/Configuration/EndpointNotation.ts +232 -0
  779. package/src/contracts/Configuration/InternalDefaults.ts +13 -0
  780. package/src/contracts/Configuration/ObjectRoles.ts +47 -0
  781. package/src/contracts/Configuration/Registration.ts +191 -0
  782. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +76 -0
  783. package/src/contracts/Configuration/RegistrationBuilders.ts +1705 -0
  784. package/src/contracts/Configuration/RegistrationCodecRegistry.ts +118 -0
  785. package/src/contracts/Configuration/RegistrationNormalizers.ts +404 -0
  786. package/src/contracts/Configuration/RegistrationTypes.ts +499 -0
  787. package/src/contracts/Configuration/RegistrationValidators.ts +698 -0
  788. package/src/contracts/Configuration/RouteChannelInternalState.ts +50 -0
  789. package/src/contracts/Configuration/RuntimeEndpointConnections.ts +91 -0
  790. package/src/contracts/Configuration/SendTimeoutValidation.ts +15 -0
  791. package/src/contracts/Configuration/TimerRegistrationValidator.ts +37 -0
  792. package/src/contracts/Configuration/index.ts +35 -0
  793. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +222 -0
  794. package/src/contracts/Dispatch/ZLinkFlowOrigin.ts +1 -0
  795. package/src/contracts/Dispatch/index.ts +2 -0
  796. package/src/contracts/Errors/ZLinkFrameworkException.ts +27 -0
  797. package/src/contracts/Errors/index.ts +4 -0
  798. package/src/contracts/Eventing/Metrics.ts +27 -0
  799. package/src/contracts/Eventing/index.ts +1 -0
  800. package/src/contracts/Handlers/Attributes.ts +111 -0
  801. package/src/contracts/Handlers/Contexts.ts +21 -0
  802. package/src/contracts/Handlers/IZLinkChannelHandlers.ts +69 -0
  803. package/src/contracts/Handlers/IZLinkHandlerFilter.ts +22 -0
  804. package/src/contracts/Handlers/JsonContract.ts +172 -0
  805. package/src/contracts/Handlers/ZLinkHandlerFilterNext.ts +1 -0
  806. package/src/contracts/Handlers/index.ts +17 -0
  807. package/src/contracts/Locations/ActorTransfer.ts +84 -0
  808. package/src/contracts/Locations/Authority.ts +308 -0
  809. package/src/contracts/Locations/Diagnostics.ts +48 -0
  810. package/src/contracts/Locations/Keys.ts +93 -0
  811. package/src/contracts/Locations/Models.ts +7 -0
  812. package/src/contracts/Locations/Options.ts +42 -0
  813. package/src/contracts/Locations/Readiness.ts +11 -0
  814. package/src/contracts/Locations/RelocationStore.ts +51 -0
  815. package/src/contracts/Locations/Resolvers.ts +8 -0
  816. package/src/contracts/Locations/Rows.ts +164 -0
  817. package/src/contracts/Locations/RuntimeQuery.ts +56 -0
  818. package/src/contracts/Locations/Stores.ts +92 -0
  819. package/src/contracts/Locations/Values.ts +32 -0
  820. package/src/contracts/Locations/Watch.ts +16 -0
  821. package/src/contracts/Locations/Writes.ts +56 -0
  822. package/src/contracts/Locations/index.ts +48 -0
  823. package/src/contracts/RouteMesh/Contracts.ts +145 -0
  824. package/src/contracts/RouteMesh/RuntimeTopology.ts +201 -0
  825. package/src/contracts/RouteMesh/index.ts +2 -0
  826. package/src/contracts/Spots/Builders.ts +11 -0
  827. package/src/contracts/Spots/Contracts.ts +150 -0
  828. package/src/contracts/Spots/SpotKind.ts +24 -0
  829. package/src/contracts/Spots/ZLinkSpot.ts +88 -0
  830. package/src/contracts/Spots/index.ts +3 -0
  831. package/src/contracts/Streams/BoundSessionContracts.ts +9 -0
  832. package/src/contracts/Streams/IZLinkSession.ts +52 -0
  833. package/src/contracts/Streams/IZLinkSessionActor.ts +17 -0
  834. package/src/contracts/Streams/IZLinkSessionPacketHandler.ts +11 -0
  835. package/src/contracts/Streams/IZLinkStream.ts +10 -0
  836. package/src/contracts/Streams/ZLinkMessageMetadata.ts +1 -0
  837. package/src/contracts/Streams/ZLinkStreamCompression.ts +9 -0
  838. package/src/contracts/Streams/ZLinkStreamError.ts +9 -0
  839. package/src/contracts/Streams/index.ts +8 -0
  840. package/src/contracts/Timers/IZLinkTimer.ts +5 -0
  841. package/src/contracts/Timers/ZLinkTimerOptions.ts +11 -0
  842. package/src/contracts/Timers/ZLinkTimerTick.ts +12 -0
  843. package/src/contracts/Timers/index.ts +3 -0
  844. package/src/contracts/index.ts +71 -0
  845. package/src/index.ts +1 -0
  846. package/src/internal.ts +29 -0
  847. package/src/location-store-integration.ts +51 -0
  848. package/src/nest-integration.ts +251 -0
  849. package/src/runtime/abort.ts +70 -0
  850. package/src/runtime/actors/actor-authority-payload-codec.ts +454 -0
  851. package/src/runtime/actors/actor-authority-publication.ts +277 -0
  852. package/src/runtime/actors/actor-client.ts +1018 -0
  853. package/src/runtime/actors/actor-context.ts +583 -0
  854. package/src/runtime/actors/actor-creation.ts +254 -0
  855. package/src/runtime/actors/actor-execution-context.ts +38 -0
  856. package/src/runtime/actors/actor-handoff.ts +1911 -0
  857. package/src/runtime/actors/actor-join-deferred-scope.ts +183 -0
  858. package/src/runtime/actors/actor-join-relocation.ts +39 -0
  859. package/src/runtime/actors/actor-lifecycle-snapshot.ts +90 -0
  860. package/src/runtime/actors/actor-local-native-join.ts +725 -0
  861. package/src/runtime/actors/actor-mailbox.ts +92 -0
  862. package/src/runtime/actors/actor-message-follow-context.ts +347 -0
  863. package/src/runtime/actors/actor-native-lookup.ts +38 -0
  864. package/src/runtime/actors/actor-packet-relay-wire.ts +223 -0
  865. package/src/runtime/actors/actor-remote-joiner.ts +238 -0
  866. package/src/runtime/actors/actor-remote-wire.ts +169 -0
  867. package/src/runtime/actors/actor-retry-delay.ts +37 -0
  868. package/src/runtime/actors/actor-routed-join-transport.ts +58 -0
  869. package/src/runtime/actors/actor-routed-json-request.ts +44 -0
  870. package/src/runtime/actors/actor-runtime-contracts.ts +126 -0
  871. package/src/runtime/actors/actor-runtime-state.ts +805 -0
  872. package/src/runtime/actors/actor-source-transfer.ts +62 -0
  873. package/src/runtime/actors/actor-transfer-registry.ts +112 -0
  874. package/src/runtime/actors/actor-transport-delivery-gate.ts +17 -0
  875. package/src/runtime/actors/bound-session-wire.ts +257 -0
  876. package/src/runtime/actors/deferred-join-accepted-journal.ts +1319 -0
  877. package/src/runtime/actors/index.ts +972 -0
  878. package/src/runtime/actors/post-commit-actor-binder.ts +70 -0
  879. package/src/runtime/actors/post-commit-actor-location.ts +114 -0
  880. package/src/runtime/actors/spot-actor-dispatch.ts +362 -0
  881. package/src/runtime/actors/transferred-actor-rollback.ts +123 -0
  882. package/src/runtime/admission.ts +192 -0
  883. package/src/runtime/application-jobs/application-ingress-record-owner.ts +216 -0
  884. package/src/runtime/application-jobs/application-job-queue-handler-start-gate.ts +10 -0
  885. package/src/runtime/application-jobs/application-job-queue-scope.ts +64 -0
  886. package/src/runtime/application-jobs/contracts.ts +26 -0
  887. package/src/runtime/application-jobs/receive-flow-controller.ts +188 -0
  888. package/src/runtime/backend/contracts/index.ts +765 -0
  889. package/src/runtime/backend/index.ts +9 -0
  890. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +73 -0
  891. package/src/runtime/backend/mesh-completion-table.ts +165 -0
  892. package/src/runtime/backend/mesh-dispatch-pump.ts +363 -0
  893. package/src/runtime/backend/mesh-record-dispatcher.ts +65 -0
  894. package/src/runtime/backend/node/index.ts +4 -0
  895. package/src/runtime/backend/node/node-backend-adapter-factory.ts +204 -0
  896. package/src/runtime/backend/node/node-backend-adapter-support.ts +257 -0
  897. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +133 -0
  898. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +44 -0
  899. package/src/runtime/backend/node/node-monitor-backend-adapter.ts +39 -0
  900. package/src/runtime/backend/node/node-raw-binding-port.contract.ts +21 -0
  901. package/src/runtime/backend/node/node-raw-binding-port.ts +518 -0
  902. package/src/runtime/backend/node/node-raw-mesh-backend.ts +2669 -0
  903. package/src/runtime/backend/node/node-socket-backend-adapter.ts +372 -0
  904. package/src/runtime/backend/node-backend-adapter.ts +19 -0
  905. package/src/runtime/backend/raw-binding-port.ts +69 -0
  906. package/src/runtime/backend/runtime-message.ts +51 -0
  907. package/src/runtime/backend/runtime-values.ts +107 -0
  908. package/src/runtime/channels/channel-autoconnect.ts +46 -0
  909. package/src/runtime/channels/channel-clients.ts +527 -0
  910. package/src/runtime/channels/channel-dispatch-pipeline.ts +408 -0
  911. package/src/runtime/channels/channel-dispatch-services.ts +234 -0
  912. package/src/runtime/channels/channel-dispatchers.ts +790 -0
  913. package/src/runtime/channels/channel-envelope-inspection.ts +125 -0
  914. package/src/runtime/channels/channel-envelope.ts +743 -0
  915. package/src/runtime/channels/channel-framework-packets.ts +8 -0
  916. package/src/runtime/channels/channel-multipart.ts +61 -0
  917. package/src/runtime/channels/channel-outbound-operations.ts +584 -0
  918. package/src/runtime/channels/channel-receive-loops.ts +901 -0
  919. package/src/runtime/channels/channel-receive-task-tracker.ts +39 -0
  920. package/src/runtime/channels/channel-runtime-lifecycle.ts +969 -0
  921. package/src/runtime/channels/channel-runtime-manager.ts +444 -0
  922. package/src/runtime/channels/channel-socket-options.ts +153 -0
  923. package/src/runtime/channels/channel-socket-registry.ts +1837 -0
  924. package/src/runtime/channels/channel-transports.ts +1154 -0
  925. package/src/runtime/channels/client-server-location-runtime.ts +576 -0
  926. package/src/runtime/channels/client-server-service-wire.ts +390 -0
  927. package/src/runtime/channels/dispatch-error-reporter.ts +165 -0
  928. package/src/runtime/channels/fanout-location-runtime.ts +459 -0
  929. package/src/runtime/channels/fanout-service-wire.ts +43 -0
  930. package/src/runtime/channels/handler-filter-scope.ts +29 -0
  931. package/src/runtime/channels/index.ts +45 -0
  932. package/src/runtime/channels/local-spot-route-transport.ts +59 -0
  933. package/src/runtime/channels/route-disconnected-error.ts +6 -0
  934. package/src/runtime/channels/route-member-snapshot.ts +55 -0
  935. package/src/runtime/channels/router-socket-spot-route-transport.ts +77 -0
  936. package/src/runtime/channels/source-spot-router.ts +89 -0
  937. package/src/runtime/channels/spot-direct-envelope.ts +44 -0
  938. package/src/runtime/channels/spot-node-route-transport.ts +92 -0
  939. package/src/runtime/channels/spot-route-bridge-transport.ts +75 -0
  940. package/src/runtime/channels/spot-route-dispatch-strategy.ts +329 -0
  941. package/src/runtime/channels/spot-route-target-resolver.ts +101 -0
  942. package/src/runtime/codecs/index.ts +69 -0
  943. package/src/runtime/configuration/index.ts +1 -0
  944. package/src/runtime/diagnostics/dispatch-error-port.ts +8 -0
  945. package/src/runtime/diagnostics/flow-context.ts +84 -0
  946. package/src/runtime/diagnostics/index.ts +441 -0
  947. package/src/runtime/diagnostics/internal-event-contracts.ts +135 -0
  948. package/src/runtime/diagnostics/message-flow.ts +560 -0
  949. package/src/runtime/diagnostics/runtime-metrics.ts +601 -0
  950. package/src/runtime/diagnostics/runtime-observation-queue.ts +362 -0
  951. package/src/runtime/diagnostics/topology-runtime-projections.ts +298 -0
  952. package/src/runtime/execution/index.ts +466 -0
  953. package/src/runtime/execution/serial-execution-queue.ts +534 -0
  954. package/src/runtime/execution/serial-work-size.ts +31 -0
  955. package/src/runtime/execution/state-lane.ts +116 -0
  956. package/src/runtime/foundation/actor-join-recovery-codec.ts +465 -0
  957. package/src/runtime/foundation/event-loop-resources.ts +162 -0
  958. package/src/runtime/foundation/index.ts +18 -0
  959. package/src/runtime/foundation/message-follow-suppression-registry.ts +130 -0
  960. package/src/runtime/foundation/operation-identity.ts +49 -0
  961. package/src/runtime/foundation/operation-registry.ts +162 -0
  962. package/src/runtime/foundation/raw-service-mesh-runtime.ts +1771 -0
  963. package/src/runtime/foundation/route-mesh-connection-policy.ts +28 -0
  964. package/src/runtime/foundation/runtime-state-projections.ts +68 -0
  965. package/src/runtime/foundation/service-authority-payload-codec.ts +566 -0
  966. package/src/runtime/foundation/service-discovery-registry.ts +263 -0
  967. package/src/runtime/foundation/service-instance-activation-recovery-codec.ts +329 -0
  968. package/src/runtime/foundation/service-liveness-registry.ts +144 -0
  969. package/src/runtime/foundation/service-mailbox.ts +369 -0
  970. package/src/runtime/foundation/service-maintenance-runtime.ts +242 -0
  971. package/src/runtime/foundation/service-metadata-codec.ts +75 -0
  972. package/src/runtime/foundation/service-relocation-aggregate-committer.ts +218 -0
  973. package/src/runtime/foundation/service-relocation-coordinator.ts +37 -0
  974. package/src/runtime/foundation/service-relocation-object-owner.ts +428 -0
  975. package/src/runtime/foundation/service-relocation-runtime.ts +1407 -0
  976. package/src/runtime/foundation/service-runtime-contracts.ts +423 -0
  977. package/src/runtime/foundation/service-session-binding-ingress-port.ts +45 -0
  978. package/src/runtime/foundation/service-stateful-registry.ts +664 -0
  979. package/src/runtime/foundation/service-stateful-runtime.ts +5753 -0
  980. package/src/runtime/foundation/service-stateful-wire-codec.ts +3008 -0
  981. package/src/runtime/foundation/service-topology-registry.ts +599 -0
  982. package/src/runtime/foundation/service-weighted-selection.ts +166 -0
  983. package/src/runtime/foundation/service-wire-binary-primitives.ts +80 -0
  984. package/src/runtime/foundation/service-wire-codec.ts +91 -0
  985. package/src/runtime/foundation/service-wire-constants.generated.ts +131 -0
  986. package/src/runtime/foundation/service-wire-m6a-codec.ts +647 -0
  987. package/src/runtime/framework-errors-internal.ts +338 -0
  988. package/src/runtime/handlers/handler-instance-scope.ts +372 -0
  989. package/src/runtime/handlers/index.ts +93 -0
  990. package/src/runtime/host/actor-packet-relay.ts +1070 -0
  991. package/src/runtime/host/actor-placement-coordinator.ts +573 -0
  992. package/src/runtime/host/actor-runtime-options-factory.ts +282 -0
  993. package/src/runtime/host/actor-transfer-authority-runtime.ts +225 -0
  994. package/src/runtime/host/actor-transfer-runtime.ts +1958 -0
  995. package/src/runtime/host/application-job-queue.ts +518 -0
  996. package/src/runtime/host/bound-session-relay.ts +94 -0
  997. package/src/runtime/host/bounded-replay-map.ts +42 -0
  998. package/src/runtime/host/channel-runtime-options-factory.ts +104 -0
  999. package/src/runtime/host/entry-actor-runtime.ts +115 -0
  1000. package/src/runtime/host/host-capacity-status.ts +103 -0
  1001. package/src/runtime/host/index.ts +3492 -0
  1002. package/src/runtime/host/instance-activation-authority.ts +658 -0
  1003. package/src/runtime/host/location-runtime-owner.ts +313 -0
  1004. package/src/runtime/host/mesh-router-resolver.ts +114 -0
  1005. package/src/runtime/host/relocation-direct-transfer.ts +273 -0
  1006. package/src/runtime/host/relocation-integrity-fault-gate.ts +8 -0
  1007. package/src/runtime/host/relocation-state-adapter.ts +24 -0
  1008. package/src/runtime/host/remote-actor-join-receiver.ts +264 -0
  1009. package/src/runtime/host/remote-actor-packet-target-store.ts +244 -0
  1010. package/src/runtime/host/remote-bound-session-relay.ts +900 -0
  1011. package/src/runtime/host/route-mesh-runtime-options.ts +46 -0
  1012. package/src/runtime/host/route-mesh-runtime.ts +891 -0
  1013. package/src/runtime/host/runtime-shutdown.ts +101 -0
  1014. package/src/runtime/host/service-relocation-control.ts +28 -0
  1015. package/src/runtime/host/service-relocation-host-runtime.ts +5817 -0
  1016. package/src/runtime/host/spot-address-transport.ts +997 -0
  1017. package/src/runtime/host/spot-node-runtime-options-factory.ts +82 -0
  1018. package/src/runtime/host/spot-runtime-options-factory.ts +286 -0
  1019. package/src/runtime/host/stateful-authority-route-runtime.ts +662 -0
  1020. package/src/runtime/host/user-spot-creation-coordinator.ts +1176 -0
  1021. package/src/runtime/locations/actor-location-claims.ts +426 -0
  1022. package/src/runtime/locations/actor-session-route-claims.ts +64 -0
  1023. package/src/runtime/locations/aggregate-inventory-store.ts +581 -0
  1024. package/src/runtime/locations/authority-key-codec.ts +80 -0
  1025. package/src/runtime/locations/auto-connect-loop.ts +131 -0
  1026. package/src/runtime/locations/auto-connect-planner.ts +178 -0
  1027. package/src/runtime/locations/auto-connect-reconciler.ts +425 -0
  1028. package/src/runtime/locations/auto-connect-types.ts +62 -0
  1029. package/src/runtime/locations/auto-connect.ts +4 -0
  1030. package/src/runtime/locations/canonical-codec.ts +54 -0
  1031. package/src/runtime/locations/domain-store-contract.ts +149 -0
  1032. package/src/runtime/locations/in-memory-authority-store.ts +1172 -0
  1033. package/src/runtime/locations/in-memory-location-store.ts +1467 -0
  1034. package/src/runtime/locations/in-memory-provider-location-store.ts +213 -0
  1035. package/src/runtime/locations/index.ts +11 -0
  1036. package/src/runtime/locations/internal-location-contracts.ts +22 -0
  1037. package/src/runtime/locations/internal-store-contracts.ts +90 -0
  1038. package/src/runtime/locations/key-codec.ts +61 -0
  1039. package/src/runtime/locations/lease-tracker.ts +221 -0
  1040. package/src/runtime/locations/lifecycle-runtime.ts +44 -0
  1041. package/src/runtime/locations/lifecycle.ts +272 -0
  1042. package/src/runtime/locations/location-store-repository.ts +4211 -0
  1043. package/src/runtime/locations/relocation-blob.ts +36 -0
  1044. package/src/runtime/locations/resolvers.ts +1054 -0
  1045. package/src/runtime/locations/runtime.ts +1126 -0
  1046. package/src/runtime/locations/spot-location-claims.ts +435 -0
  1047. package/src/runtime/messaging/creation-payload-codec.ts +59 -0
  1048. package/src/runtime/messaging/framework-json-v1.ts +307 -0
  1049. package/src/runtime/messaging/index.ts +1 -0
  1050. package/src/runtime/messaging/packet-name.ts +94 -0
  1051. package/src/runtime/messaging/payload-codec.ts +418 -0
  1052. package/src/runtime/messaging/submission-result.ts +61 -0
  1053. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +189 -0
  1054. package/src/runtime/routing-id.ts +125 -0
  1055. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +418 -0
  1056. package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +147 -0
  1057. package/src/runtime/spots/index.ts +3303 -0
  1058. package/src/runtime/spots/spot-activation-registry.ts +335 -0
  1059. package/src/runtime/spots/spot-activation-state.ts +414 -0
  1060. package/src/runtime/spots/spot-activation.ts +1027 -0
  1061. package/src/runtime/spots/spot-actor-admission-coordinator.ts +354 -0
  1062. package/src/runtime/spots/spot-actor-join-dispatch.ts +303 -0
  1063. package/src/runtime/spots/spot-actor-lifecycle-drain.ts +79 -0
  1064. package/src/runtime/spots/spot-actor-membership.ts +266 -0
  1065. package/src/runtime/spots/spot-actor-packet-dispatch.ts +593 -0
  1066. package/src/runtime/spots/spot-actor-packet-drain.ts +328 -0
  1067. package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +162 -0
  1068. package/src/runtime/spots/spot-closing.ts +34 -0
  1069. package/src/runtime/spots/spot-context.ts +259 -0
  1070. package/src/runtime/spots/spot-entry-activation.ts +551 -0
  1071. package/src/runtime/spots/spot-handle.ts +101 -0
  1072. package/src/runtime/spots/spot-handler-registry.ts +273 -0
  1073. package/src/runtime/spots/spot-lifecycle-metrics.ts +15 -0
  1074. package/src/runtime/spots/spot-location-claim.ts +86 -0
  1075. package/src/runtime/spots/spot-manager-internal-contracts.ts +11 -0
  1076. package/src/runtime/spots/spot-manager-public.ts +361 -0
  1077. package/src/runtime/spots/spot-native-actor-join-admission.ts +151 -0
  1078. package/src/runtime/spots/spot-native-flags.ts +4 -0
  1079. package/src/runtime/spots/spot-node-autoconnect.ts +325 -0
  1080. package/src/runtime/spots/spot-node-runtime-manager.ts +1573 -0
  1081. package/src/runtime/spots/spot-outbound.ts +761 -0
  1082. package/src/runtime/spots/spot-provider.ts +36 -0
  1083. package/src/runtime/spots/spot-publisher-transport.ts +69 -0
  1084. package/src/runtime/spots/spot-remote-codec.ts +308 -0
  1085. package/src/runtime/spots/spot-remote-route-codec.ts +284 -0
  1086. package/src/runtime/spots/spot-route-packet-dispatch.ts +359 -0
  1087. package/src/runtime/spots/spot-route-replies.ts +126 -0
  1088. package/src/runtime/spots/spot-route-reply-wire.ts +15 -0
  1089. package/src/runtime/spots/spot-routed-actor-admission.ts +351 -0
  1090. package/src/runtime/spots/spot-routed-bound-session-dispatch.ts +132 -0
  1091. package/src/runtime/spots/spot-routed-frame-dispatch.ts +250 -0
  1092. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +254 -0
  1093. package/src/runtime/spots/spot-routing-internal.ts +33 -0
  1094. package/src/runtime/spots/spot-runtime-ports.ts +196 -0
  1095. package/src/runtime/spots/spot-serial-executor.ts +170 -0
  1096. package/src/runtime/spots/spot-serial-turn-executor.ts +319 -0
  1097. package/src/runtime/spots/spot-subscription-dispatch.ts +252 -0
  1098. package/src/runtime/spots/spot-timer.ts +609 -0
  1099. package/src/runtime/streams/actor-session-binding-registry.ts +1691 -0
  1100. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +78 -0
  1101. package/src/runtime/streams/actor-session-lifecycle-coordinator.ts +20 -0
  1102. package/src/runtime/streams/bound-actor-relay-sender.ts +275 -0
  1103. package/src/runtime/streams/bound-session-response-target.ts +91 -0
  1104. package/src/runtime/streams/bound-session-service.ts +500 -0
  1105. package/src/runtime/streams/index.ts +706 -0
  1106. package/src/runtime/streams/managed-stream.ts +509 -0
  1107. package/src/runtime/streams/native-fallback-bound-session.ts +321 -0
  1108. package/src/runtime/streams/protocol.ts +291 -0
  1109. package/src/runtime/streams/session-actor-coordinator.ts +605 -0
  1110. package/src/runtime/streams/session-calls.ts +221 -0
  1111. package/src/runtime/streams/session-context.ts +609 -0
  1112. package/src/runtime/streams/session-local-actors.ts +30 -0
  1113. package/src/runtime/streams/session-provider.ts +50 -0
  1114. package/src/runtime/streams/session-requests.ts +109 -0
  1115. package/src/runtime/streams/session-serial-executor.ts +97 -0
  1116. package/src/runtime/streams/stream-binding-runtime-ports.ts +106 -0
  1117. package/src/runtime/streams/stream-frame-factory.ts +255 -0
  1118. package/src/runtime/streams/stream-message-utils.ts +89 -0
  1119. package/src/runtime/streams/stream-session-runtime.ts +1420 -0
  1120. package/src/runtime/workers/index.ts +580 -0
  1121. package/tsconfig.json +17 -0
@@ -0,0 +1,4211 @@
1
+ import { createHash, randomUUID, timingSafeEqual } from 'node:crypto';
2
+ import type {
3
+ ZLinkLocationStore,
4
+ ZLinkLocationPage,
5
+ ZLinkClientServerServerDescriptor,
6
+ ZLinkClientServerServerDescriptorKey,
7
+ ZLinkFanoutPublisherDescriptor,
8
+ ZLinkFanoutPublisherDescriptorKey,
9
+ ZLinkMeshNodeDescriptor,
10
+ ZLinkMeshNodeDescriptorKey,
11
+ ZLinkPageRequest,
12
+ ZLinkStoreCondition,
13
+ ZLinkStoreKey,
14
+ ZLinkStoreReadResult,
15
+ ZLinkStoreScanCursor,
16
+ ZLinkStoreScanRequest,
17
+ ZLinkStoreScanResult,
18
+ ZLinkStoreWriteRequest,
19
+ ZLinkStoreWriteResult,
20
+ ZLinkStoreVersion
21
+ } from '../../contracts';
22
+ import type {
23
+ ZLinkAggregateAbortResult,
24
+ ZLinkAggregateCommitResult,
25
+ ZLinkAggregateFence,
26
+ ZLinkAggregateId,
27
+ ZLinkAggregatePrepareRequest,
28
+ ZLinkAggregatePrepareResult,
29
+ ZLinkAuthorityCompareExchangeResult,
30
+ ZLinkAuthorityKey,
31
+ ZLinkAuthorityMutation,
32
+ ZLinkAuthorityReadResult,
33
+ ZLinkAuthorityScanCursor,
34
+ ZLinkAuthorityScanResult,
35
+ ZLinkAuthoritySnapshot,
36
+ ZLinkAuthorityStoreVersion,
37
+ ZLinkCapacityVector,
38
+ ZLinkCreationOperationIdentity,
39
+ ZLinkCreationTerminalReadResult,
40
+ ZLinkCreationTerminalRecord,
41
+ ZLinkLocationOwnerToken,
42
+ ZLinkLocationWriteResult,
43
+ ZLinkLocationWriteStatus,
44
+ ZLinkObjectCommitRequest,
45
+ ZLinkObjectCommitResult,
46
+ ZLinkObjectAbortRequest,
47
+ ZLinkObjectAbortResult,
48
+ ZLinkObjectCreationCompleteRequest,
49
+ ZLinkObjectCreationCompleteResult,
50
+ ZLinkObjectReserveRequest,
51
+ ZLinkObjectReserveResult,
52
+ ZLinkOwnerLeaseClaimResult,
53
+ ZLinkOwnerLeaseReadResult,
54
+ ZLinkOwnerLeaseReleaseResult,
55
+ ZLinkOwnerLeaseRenewResult,
56
+ ZLinkPlacementAllocation
57
+ } from './internal-location-contracts';
58
+ import { ZLinkLocationWriteIntent } from './internal-location-contracts';
59
+ import type {
60
+ ZLinkActorLocation,
61
+ ZLinkActorLocationFilter,
62
+ ZLinkActorLocationKey,
63
+ ZLinkRouteLocation,
64
+ ZLinkRouteLocationFilter,
65
+ ZLinkRouteLocationKey,
66
+ ZLinkSpotLocation,
67
+ ZLinkSpotLocationFilter,
68
+ ZLinkSpotLocationKey
69
+ } from './internal-location-contracts';
70
+ import {
71
+ ZLinkFrameworkRuntimeState,
72
+ ZLinkObjectRole
73
+ } from '../../contracts';
74
+ import { ZLinkLocationWriteStatus as WriteStatus } from '../../contracts/Locations';
75
+ import { ZLinkInMemoryLocationStore } from './in-memory-location-store';
76
+ import { storeKey } from './in-memory-provider-location-store';
77
+ import { decodeAuthorityKey, encodeAuthorityKey } from './authority-key-codec';
78
+ import { ZLinkAggregateInventoryStore } from './aggregate-inventory-store';
79
+ import type { RoutingId } from '../../contracts/Common/CoreTypes';
80
+ import { decodeRoutingId, encodeRoutingIdStorageHex } from '../routing-id';
81
+
82
+ const PREFIX = 'zlink:v11:';
83
+ const OWNER_COUNTER_KEY = storeKey(`${PREFIX}owner-counter`);
84
+ // These counters are store-wide fences. They deliberately are not derived
85
+ // from an authority identity: deleting and recreating an authority must never
86
+ // reuse an incarnation or owner-transition generation.
87
+ const OBJECT_COUNTER_KEY = storeKey(`${PREFIX}object-counter`);
88
+ const AUTHORITY_OWNER_COUNTER_KEY = storeKey(`${PREFIX}authority-owner-counter`);
89
+ const MAX_GENERATION = 0x7fff_ffff_ffff_ffffn;
90
+ const MAX_U64 = 0xffff_ffff_ffff_ffffn;
91
+ const MAX_CREATION_TERMINAL_BYTES = 1024 * 1024;
92
+ const CREATION_TERMINAL_RETENTION_MS = 5 * 60 * 1000;
93
+ const AGGREGATE_COMMIT_RETRY_WINDOW_MS = 5_000;
94
+ const MAX_AGGREGATE_COMMIT_CONFLICT_RETRIES = 64;
95
+
96
+ type StoredAuthoritySnapshot = Omit<
97
+ ZLinkAuthoritySnapshot,
98
+ 'kind' | 'storeVersion' | 'storeNow'
99
+ >;
100
+
101
+ interface AuthorityRecord {
102
+ readonly snapshot: StoredAuthoritySnapshot;
103
+ readonly reservationId?: string;
104
+ readonly terminal?: 'committed' | 'rejected' | 'failed' | 'aborted';
105
+ readonly aggregate?: AggregateParticipantFenceRecord;
106
+ readonly visibleStoreVersion?: string;
107
+ }
108
+
109
+ interface CapacityRecord {
110
+ readonly active: CapacityUsage;
111
+ readonly pending: CapacityUsage;
112
+ }
113
+
114
+ interface CapacityUsage {
115
+ readonly actors: number;
116
+ readonly spots: number;
117
+ readonly spotTypes: Readonly<Record<string, number>>;
118
+ }
119
+
120
+ interface AggregateParticipantFenceRecord {
121
+ readonly aggregateId: string;
122
+ readonly aggregateGeneration: bigint;
123
+ readonly index: number;
124
+ readonly expectedStoreVersion: string;
125
+ readonly ownerTransition: 'preserve' | 'newOwner';
126
+ readonly targetAuthorityOwnerGeneration: bigint;
127
+ readonly authorityPayloadSha256: string;
128
+ readonly membershipMutationSha256: string;
129
+ }
130
+
131
+ interface AggregateRecord {
132
+ readonly state: 'staging' | 'prepared' | 'committed' | 'aborted';
133
+ readonly requestFingerprint: string;
134
+ readonly participantCount: number;
135
+ readonly inventoryDigest: Uint8Array;
136
+ readonly targetDescriptor: ZLinkMeshNodeDescriptorKey;
137
+ readonly targetDescriptorLifecycleGeneration: bigint;
138
+ readonly capacity: ZLinkCapacityVector;
139
+ readonly targetOwner: ZLinkLocationOwnerToken;
140
+ /** Store-wide authority-owner generations reserved for this aggregate. */
141
+ readonly ownerGenerationStart?: bigint;
142
+ readonly ownerGenerationEnd?: bigint;
143
+ }
144
+
145
+ interface OwnerRecord {
146
+ readonly recordVersion: 1;
147
+ readonly ownerId: string;
148
+ readonly leaseGeneration: string;
149
+ }
150
+
151
+ interface DescriptorRecord<T> {
152
+ readonly generation: string;
153
+ readonly descriptor: T;
154
+ }
155
+
156
+ interface CanonicalDescriptorRecord<T> {
157
+ readonly recordVersion: 1;
158
+ /** Legacy Node-private row generation. Canonical v1 records omit this. */
159
+ readonly generation?: string;
160
+ readonly ownerId: string;
161
+ readonly leaseGeneration: string;
162
+ readonly descriptorRevision: string;
163
+ readonly descriptor: T;
164
+ }
165
+
166
+ interface OwnerCleanupCandidate {
167
+ readonly key: ZLinkStoreKey;
168
+ readonly scanVersion: ZLinkStoreVersion;
169
+ }
170
+
171
+ interface OwnerCleanupRecord {
172
+ readonly descriptor: OwnedStoreRecord;
173
+ }
174
+
175
+ const MAX_OWNER_CLEANUP_BATCH_ROWS = 2_047;
176
+
177
+ /**
178
+ * Maps framework domain records to the minimal provider SPI.
179
+ *
180
+ * Owner lease and MeshNode descriptor publication are persisted through the
181
+ * provider. Remaining domain families still use the inherited framework-owned
182
+ * repository while their record codecs are migrated.
183
+ */
184
+ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
185
+ private readonly provider: ZLinkLocationStore;
186
+ private readonly aggregateInventory: ZLinkAggregateInventoryStore;
187
+
188
+ constructor(
189
+ provider: ZLinkLocationStore,
190
+ private readonly nowProvider: () => Date = () => new Date()
191
+ ) {
192
+ super(nowProvider);
193
+ this.provider = new AmbiguousWriteReconcilingLocationStore(provider);
194
+ this.aggregateInventory = new ZLinkAggregateInventoryStore(this.provider);
195
+ }
196
+
197
+ override async readAuthority(
198
+ key: ZLinkAuthorityKey,
199
+ signal?: AbortSignal
200
+ ): Promise<ZLinkAuthorityReadResult> {
201
+ const result = await this.provider.read(authorityKey(key.value), signal);
202
+ if (result.kind === 'missing') {
203
+ return { kind: 'missing', storeNow: result.storeNow };
204
+ }
205
+ return await this.projectAuthority(
206
+ decodeAuthorityRecord(result.value.bytes),
207
+ result.value.version,
208
+ result.value.storeNow,
209
+ signal
210
+ );
211
+ }
212
+
213
+ override async listAuthorities(
214
+ prefix: string,
215
+ cursor: ZLinkAuthorityScanCursor | undefined,
216
+ limit: number,
217
+ signal?: AbortSignal
218
+ ): Promise<ZLinkAuthorityScanResult> {
219
+ if (!Number.isInteger(limit) || limit < 1 || limit > 1_000) {
220
+ throw new RangeError('Authority scan limit must be in 1..1000.');
221
+ }
222
+ const scan = await this.provider.scan({
223
+ prefix: AUTHORITY_PREIMAGE_PREFIX,
224
+ cursor: cursor === undefined
225
+ ? undefined
226
+ : ({ value: cursor.encoded } as ZLinkStoreScanCursor),
227
+ limit
228
+ }, signal);
229
+ if (scan.kind === 'expired') return { kind: 'scanExpired' };
230
+ const items = [];
231
+ for (const item of scan.value.items) {
232
+ const encodedKey = authorityContractValueFromPreimage(item.key.value);
233
+ if (!encodedKey.startsWith(prefix)) continue;
234
+ const snapshot = await this.projectAuthority(
235
+ decodeAuthorityRecord(item.value.bytes),
236
+ item.value.version,
237
+ item.value.storeNow,
238
+ signal
239
+ );
240
+ items.push({ key: authorityContractKey(encodedKey), snapshot });
241
+ }
242
+ return {
243
+ kind: 'page',
244
+ items,
245
+ nextCursor: scan.value.nextCursor === undefined
246
+ ? undefined
247
+ : ({ encoded: scan.value.nextCursor.value } as ZLinkAuthorityScanCursor)
248
+ };
249
+ }
250
+
251
+ override async compareExchangeAuthority(
252
+ key: ZLinkAuthorityKey,
253
+ expectedStoreVersion: ZLinkAuthorityStoreVersion,
254
+ mutation: ZLinkAuthorityMutation,
255
+ signal?: AbortSignal
256
+ ): Promise<ZLinkAuthorityCompareExchangeResult> {
257
+ if (mutation.kind !== 'delete') {
258
+ validatePayloadSize(mutation.payload, 'Authority payload');
259
+ }
260
+ const rowKey = authorityKey(requireText(key.value, 'authority key'));
261
+ for (;;) {
262
+ signal?.throwIfAborted();
263
+ const current = await this.provider.read(rowKey, signal);
264
+ if (current.kind === 'missing') {
265
+ return { kind: 'conflict', current: { kind: 'missing', storeNow: current.storeNow } };
266
+ }
267
+ const record = decodeAuthorityRecord(current.value.bytes);
268
+ const snapshot = await this.projectAuthority(
269
+ record,
270
+ current.value.version,
271
+ current.value.storeNow,
272
+ signal
273
+ );
274
+ if (record.aggregate !== undefined) {
275
+ return { kind: 'conflict', current: snapshot };
276
+ }
277
+ if (
278
+ record.snapshot.allocation.state !== 'active'
279
+ || (record.visibleStoreVersion ?? current.value.version.value)
280
+ !== expectedStoreVersion.value
281
+ ) {
282
+ return { kind: 'conflict', current: snapshot };
283
+ }
284
+ if (mutation.kind === 'rebindOwnerLease') {
285
+ if (
286
+ mutation.expectedOwner.ownerId !== record.snapshot.ownerId
287
+ || mutation.expectedOwner.leaseGeneration !== record.snapshot.ownerLeaseGeneration
288
+ || mutation.targetOwner.ownerId !== record.snapshot.ownerId
289
+ || mutation.targetOwner.leaseGeneration === record.snapshot.ownerLeaseGeneration
290
+ ) {
291
+ return { kind: 'conflict', current: snapshot };
292
+ }
293
+ const descriptorKey = meshKey(
294
+ record.snapshot.allocation.descriptor.meshName,
295
+ record.snapshot.allocation.descriptor.rid
296
+ );
297
+ const [descriptorRead, targetLeaseRead] = await Promise.all([
298
+ this.provider.read(descriptorKey, signal),
299
+ this.provider.read(ownerKey(mutation.targetOwner.ownerId), signal)
300
+ ]);
301
+ if (liveTargetDescriptor(
302
+ descriptorRead,
303
+ targetLeaseRead,
304
+ {
305
+ meshName: record.snapshot.allocation.descriptor.meshName,
306
+ nodeRid: record.snapshot.allocation.descriptor.rid,
307
+ nodeLifecycleGeneration: record.snapshot.allocation.descriptorLifecycleGeneration,
308
+ owner: mutation.targetOwner
309
+ }
310
+ ) === undefined) {
311
+ return { kind: 'conflict', current: snapshot };
312
+ }
313
+ const nextRecord: AuthorityRecord = {
314
+ ...record,
315
+ visibleStoreVersion: undefined,
316
+ snapshot: {
317
+ ...record.snapshot,
318
+ ownerLeaseGeneration: mutation.targetOwner.leaseGeneration,
319
+ payload: Buffer.from(mutation.payload)
320
+ }
321
+ };
322
+ const result = await this.provider.write({
323
+ conditions: [
324
+ { kind: 'version', key: rowKey, expected: current.value.version },
325
+ versionCondition(descriptorKey, descriptorRead),
326
+ versionCondition(ownerKey(mutation.targetOwner.ownerId), targetLeaseRead)
327
+ ],
328
+ mutations: [{ kind: 'put', key: rowKey, bytes: encodeAuthorityRecord(nextRecord) }]
329
+ }, signal);
330
+ if (result.kind === 'conflict') continue;
331
+ const storeVersion = result.putVersions.find(entry =>
332
+ entry.key.value === rowKey.value)?.version;
333
+ if (storeVersion === undefined) {
334
+ throw new Error('Authority lease rebind did not return a row version.');
335
+ }
336
+ const stored = authoritySnapshot(nextRecord.snapshot, storeVersion, result.storeNow);
337
+ const { kind: _kind, ...withoutKind } = stored;
338
+ return { kind: 'stored', ...withoutKind };
339
+ }
340
+ if (
341
+ mutation.kind === 'restore'
342
+ && (
343
+ mutation.expectedOwner.ownerId !== record.snapshot.ownerId
344
+ || mutation.expectedOwner.leaseGeneration
345
+ !== record.snapshot.ownerLeaseGeneration
346
+ )
347
+ ) {
348
+ return { kind: 'conflict', current: snapshot };
349
+ }
350
+ const leaseKey = ownerKey(record.snapshot.ownerId);
351
+ const lease = await this.provider.read(leaseKey, signal);
352
+ if (
353
+ mutation.kind !== 'restore'
354
+ && !sameLiveOwner(lease, record.snapshot)
355
+ ) {
356
+ return { kind: 'conflict', current: snapshot };
357
+ }
358
+ const capacityRowKey = capacityKey(
359
+ record.snapshot.allocation.descriptor.meshName,
360
+ String(record.snapshot.allocation.descriptor.rid)
361
+ );
362
+ const capacityRead = mutation.kind === 'delete'
363
+ ? await this.provider.read(capacityRowKey, signal)
364
+ : undefined;
365
+ const nextRecord: AuthorityRecord | undefined = mutation.kind === 'delete'
366
+ ? undefined
367
+ : {
368
+ ...record,
369
+ visibleStoreVersion: undefined,
370
+ snapshot: {
371
+ ...record.snapshot,
372
+ payload: Buffer.from(mutation.payload)
373
+ }
374
+ };
375
+ const result = await this.provider.write({
376
+ conditions: [
377
+ { kind: 'version', key: rowKey, expected: current.value.version },
378
+ ...(mutation.kind === 'restore'
379
+ ? []
380
+ : [versionCondition(leaseKey, lease)]),
381
+ ...(capacityRead === undefined
382
+ ? []
383
+ : [conditionFor(capacityRowKey, capacityRead)])
384
+ ],
385
+ mutations: mutation.kind === 'delete'
386
+ ? [
387
+ { kind: 'delete', key: rowKey },
388
+ {
389
+ kind: 'put',
390
+ key: capacityRowKey,
391
+ bytes: encodeJson({
392
+ active: subtractCapacity(
393
+ capacityRead?.kind === 'found'
394
+ ? decodeJson<CapacityRecord>(capacityRead.value.bytes).active
395
+ : emptyCapacityRecord().active,
396
+ record.snapshot.allocation.capacity
397
+ ),
398
+ pending: capacityRead?.kind === 'found'
399
+ ? decodeJson<CapacityRecord>(capacityRead.value.bytes).pending
400
+ : emptyCapacityRecord().pending
401
+ } satisfies CapacityRecord)
402
+ }
403
+ ]
404
+ : [{ kind: 'put', key: rowKey, bytes: encodeAuthorityRecord(nextRecord!) }]
405
+ }, signal);
406
+ if (result.kind === 'conflict') continue;
407
+ const storeVersion = result.putVersions.find(entry =>
408
+ entry.key.value === rowKey.value)?.version;
409
+ if (mutation.kind === 'delete') {
410
+ return {
411
+ kind: 'deleted',
412
+ storeVersion: {
413
+ value: (storeVersion ?? current.value.version).value
414
+ } as ZLinkAuthorityStoreVersion,
415
+ storeNow: result.storeNow
416
+ };
417
+ }
418
+ if (storeVersion === undefined) {
419
+ throw new Error('Authority compare-exchange did not return a row version.');
420
+ }
421
+ const stored = authoritySnapshot(nextRecord!.snapshot, storeVersion, result.storeNow);
422
+ const { kind: _kind, ...withoutKind } = stored;
423
+ return { kind: 'stored', ...withoutKind };
424
+ }
425
+ }
426
+
427
+ override async prepareAggregate(
428
+ request: ZLinkAggregatePrepareRequest,
429
+ signal?: AbortSignal
430
+ ): Promise<ZLinkAggregatePrepareResult> {
431
+ validateProviderAggregateRequest(request);
432
+ const fence = aggregateFence(request.aggregateId, request.aggregateGeneration);
433
+ const rowKey = aggregateKey(fence);
434
+ const fingerprint = sha256Hex(encodeJson(request));
435
+ let aggregateRead = await this.provider.read(rowKey, signal);
436
+ if (aggregateRead.kind === 'found') {
437
+ const existing = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
438
+ const reconciled = reconcileAggregatePrepare(existing, fingerprint, fence);
439
+ if (reconciled !== undefined) {
440
+ if (reconciled.kind === 'alreadyPrepared') {
441
+ await this.aggregateInventory.read(fence, request.inventoryDigest, signal);
442
+ }
443
+ return reconciled;
444
+ }
445
+ } else {
446
+ const staging = aggregateRecord(request, fingerprint, 'staging');
447
+ const claimed = await this.provider.write({
448
+ conditions: [{ kind: 'missing', key: rowKey }],
449
+ mutations: [{ kind: 'put', key: rowKey, bytes: encodeJson(staging) }]
450
+ }, signal);
451
+ if (claimed.kind === 'conflict') {
452
+ aggregateRead = await this.provider.read(rowKey, signal);
453
+ if (aggregateRead.kind === 'missing') return { kind: 'conflict' };
454
+ const existing = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
455
+ const reconciled = reconcileAggregatePrepare(existing, fingerprint, fence);
456
+ if (reconciled !== undefined) return reconciled;
457
+ } else {
458
+ const version = claimed.putVersions.find(value =>
459
+ value.key.value === rowKey.value)?.version;
460
+ if (version === undefined) {
461
+ throw new Error('Aggregate staging did not return a Store version.');
462
+ }
463
+ aggregateRead = {
464
+ kind: 'found',
465
+ value: {
466
+ bytes: encodeJson(staging),
467
+ version,
468
+ storeNow: claimed.storeNow
469
+ }
470
+ };
471
+ }
472
+ }
473
+ const aggregate = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
474
+ if (
475
+ aggregate.state !== 'staging'
476
+ || aggregate.requestFingerprint !== fingerprint
477
+ ) {
478
+ return { kind: 'conflict' };
479
+ }
480
+ try {
481
+ await this.aggregateInventory.store(request, signal);
482
+ const entries = await this.aggregateInventory.read(
483
+ fence,
484
+ request.inventoryDigest,
485
+ signal
486
+ );
487
+ if (entries.length !== request.participants.length) {
488
+ throw new Error('Aggregate inventory count changed after staging.');
489
+ }
490
+ await parallelForEach(request.participants, 64, async (participant, index) => {
491
+ const entry = entries[index]!;
492
+ if (
493
+ entry.authorityKey !== participant.authorityKey.value
494
+ || entry.expectedStoreVersion !== participant.expectedStoreVersion.value
495
+ || entry.ownerTransition !== participant.ownerTransition
496
+ ) {
497
+ throw new Error('Aggregate inventory differs from its participant request.');
498
+ }
499
+ await this.putImmutable(
500
+ aggregateParticipantPayloadKey(fence, index),
501
+ participant.authorityPayload,
502
+ signal
503
+ );
504
+ await this.putImmutable(
505
+ aggregateParticipantMembershipKey(fence, index),
506
+ participant.membershipMutation,
507
+ signal
508
+ );
509
+ });
510
+
511
+ const targetDescriptorKey = meshKey(
512
+ request.targetDescriptor.meshName,
513
+ request.targetDescriptor.rid
514
+ );
515
+ const targetLeaseKey = ownerKey(request.targetOwner.ownerId);
516
+ const targetCapacityKey = capacityKey(
517
+ request.targetDescriptor.meshName,
518
+ request.targetDescriptor.rid
519
+ );
520
+ const [
521
+ descriptorRead,
522
+ leaseRead,
523
+ targetCapacityRead
524
+ ] = await Promise.all([
525
+ this.provider.read(targetDescriptorKey, signal),
526
+ this.provider.read(targetLeaseKey, signal),
527
+ this.provider.read(targetCapacityKey, signal)
528
+ ]);
529
+ const descriptor = liveTargetDescriptor(
530
+ descriptorRead,
531
+ leaseRead,
532
+ aggregateTarget(request)
533
+ );
534
+ const targetCapacity = targetCapacityRead.kind === 'missing'
535
+ ? emptyCapacityRecord()
536
+ : decodeJson<CapacityRecord>(targetCapacityRead.value.bytes);
537
+ if (
538
+ descriptor === undefined
539
+ || !capacityAvailable(descriptor, request.capacity, targetCapacity)
540
+ ) {
541
+ await this.abortAggregateStaging(fence, signal);
542
+ return { kind: 'conflict' };
543
+ }
544
+
545
+ let sourceCapacity: ZLinkCapacityVector = { actors: 0, spots: 0 };
546
+ let ownerGenerationStart = aggregate.ownerGenerationStart;
547
+ let ownerGenerationEnd = aggregate.ownerGenerationEnd;
548
+ let ownerGenerationCounterRead: ZLinkStoreReadResult | undefined;
549
+ if (ownerGenerationStart === undefined || ownerGenerationEnd === undefined) {
550
+ ownerGenerationCounterRead = await this.provider.read(AUTHORITY_OWNER_COUNTER_KEY, signal);
551
+ ownerGenerationStart = counterNextValue(ownerGenerationCounterRead);
552
+ ownerGenerationEnd = ownerGenerationStart + BigInt(request.participants.length) - 1n;
553
+ if (ownerGenerationEnd >= MAX_GENERATION) {
554
+ await this.abortAggregateStaging(fence, signal);
555
+ return { kind: 'generationExhausted' };
556
+ }
557
+ } else if (ownerGenerationEnd !== ownerGenerationStart + BigInt(request.participants.length) - 1n) {
558
+ await this.abortAggregateStaging(fence, signal);
559
+ return { kind: 'conflict' };
560
+ }
561
+ const installed: Array<{
562
+ readonly key: ZLinkStoreKey;
563
+ readonly expectedStoreVersion: string;
564
+ }> = [];
565
+ for (let index = 0; index < request.participants.length; index++) {
566
+ const participant = request.participants[index]!;
567
+ const entry = entries[index]!;
568
+ const authorityRowKey = authorityKey(participant.authorityKey.value);
569
+ const current = await this.provider.read(authorityRowKey, signal);
570
+ if (current.kind === 'missing') {
571
+ await this.abortAggregateStaging(fence, signal);
572
+ return { kind: 'conflict' };
573
+ }
574
+ const record = decodeAuthorityRecord(current.value.bytes);
575
+ if (sameAggregateMarker(record.aggregate, fence, index, participant)) {
576
+ if (ownerGenerationCounterRead !== undefined) {
577
+ const reservedAggregate = await this.provider.read(rowKey, signal);
578
+ if (reservedAggregate.kind === 'missing') return { kind: 'conflict' };
579
+ const reservedRecord = decodeJson<AggregateRecord>(reservedAggregate.value.bytes);
580
+ if (reservedRecord.ownerGenerationStart === undefined
581
+ || reservedRecord.ownerGenerationEnd === undefined) {
582
+ return { kind: 'conflict' };
583
+ }
584
+ ownerGenerationStart = reservedRecord.ownerGenerationStart;
585
+ ownerGenerationEnd = reservedRecord.ownerGenerationEnd;
586
+ ownerGenerationCounterRead = undefined;
587
+ aggregateRead = reservedAggregate;
588
+ }
589
+ installed.push({
590
+ key: authorityRowKey,
591
+ expectedStoreVersion: participant.expectedStoreVersion.value
592
+ });
593
+ if (participant.ownerTransition === 'newOwner') {
594
+ sourceCapacity = addCapacityVector(
595
+ sourceCapacity,
596
+ record.snapshot.allocation.capacity
597
+ );
598
+ }
599
+ continue;
600
+ }
601
+ if (
602
+ record.aggregate !== undefined
603
+ || record.snapshot.allocation.state !== 'active'
604
+ || (record.visibleStoreVersion ?? current.value.version.value)
605
+ !== participant.expectedStoreVersion.value
606
+ ) {
607
+ await this.clearAggregateMarkers(fence, installed, signal);
608
+ await this.abortAggregateStaging(fence, signal);
609
+ return { kind: 'conflict' };
610
+ }
611
+ if (participant.ownerTransition === 'preserve') {
612
+ const lease = await this.provider.read(ownerKey(record.snapshot.ownerId), signal);
613
+ if (!sameLiveOwner(lease, record.snapshot)) {
614
+ await this.clearAggregateMarkers(fence, installed, signal);
615
+ await this.abortAggregateStaging(fence, signal);
616
+ return { kind: 'conflict' };
617
+ }
618
+ } else {
619
+ sourceCapacity = addCapacityVector(
620
+ sourceCapacity,
621
+ record.snapshot.allocation.capacity
622
+ );
623
+ }
624
+ const targetAuthorityOwnerGeneration = participant.ownerTransition === 'newOwner'
625
+ ? ownerGenerationStart + BigInt(index)
626
+ : record.snapshot.authorityOwnerGeneration;
627
+ const marker: AggregateParticipantFenceRecord = {
628
+ aggregateId: fence.aggregateId.value,
629
+ aggregateGeneration: fence.aggregateGeneration,
630
+ index,
631
+ expectedStoreVersion: participant.expectedStoreVersion.value,
632
+ ownerTransition: participant.ownerTransition,
633
+ targetAuthorityOwnerGeneration,
634
+ authorityPayloadSha256: entry.authorityPayloadSha256,
635
+ membershipMutationSha256: entry.membershipMutationSha256
636
+ };
637
+ const reservingOwnerGenerationBlock = ownerGenerationCounterRead !== undefined;
638
+ const stored = await this.provider.write({
639
+ conditions: [
640
+ { kind: 'version', key: authorityRowKey, expected: current.value.version },
641
+ ...(reservingOwnerGenerationBlock
642
+ ? [conditionFor(AUTHORITY_OWNER_COUNTER_KEY, ownerGenerationCounterRead!)]
643
+ : []),
644
+ ...(reservingOwnerGenerationBlock
645
+ ? [{ kind: 'version' as const, key: rowKey, expected: aggregateRead.value.version }]
646
+ : [])
647
+ ],
648
+ mutations: [
649
+ {
650
+ kind: 'put', key: authorityRowKey, bytes: encodeAuthorityRecord({
651
+ ...record,
652
+ aggregate: marker,
653
+ visibleStoreVersion:
654
+ record.visibleStoreVersion ?? current.value.version.value
655
+ } satisfies AuthorityRecord)
656
+ },
657
+ ...(reservingOwnerGenerationBlock
658
+ ? [
659
+ {
660
+ kind: 'put' as const,
661
+ key: AUTHORITY_OWNER_COUNTER_KEY,
662
+ bytes: encodeText((ownerGenerationEnd! + 1n).toString())
663
+ },
664
+ {
665
+ kind: 'put' as const,
666
+ key: rowKey,
667
+ bytes: encodeJson({
668
+ ...aggregate,
669
+ ownerGenerationStart,
670
+ ownerGenerationEnd
671
+ } satisfies AggregateRecord)
672
+ }
673
+ ]
674
+ : [])
675
+ ]
676
+ }, signal);
677
+ if (stored.kind === 'conflict') {
678
+ const raced = await this.provider.read(authorityRowKey, signal);
679
+ if (raced.kind === 'found' && sameAggregateMarker(
680
+ decodeAuthorityRecord(raced.value.bytes).aggregate, fence, index, participant
681
+ )) {
682
+ if (reservingOwnerGenerationBlock) {
683
+ const reservedAggregate = await this.provider.read(rowKey, signal);
684
+ if (reservedAggregate.kind === 'missing') return { kind: 'conflict' };
685
+ const reservedRecord = decodeJson<AggregateRecord>(reservedAggregate.value.bytes);
686
+ if (reservedRecord.ownerGenerationStart === undefined
687
+ || reservedRecord.ownerGenerationEnd === undefined) {
688
+ return { kind: 'conflict' };
689
+ }
690
+ ownerGenerationStart = reservedRecord.ownerGenerationStart;
691
+ ownerGenerationEnd = reservedRecord.ownerGenerationEnd;
692
+ ownerGenerationCounterRead = undefined;
693
+ aggregateRead = reservedAggregate;
694
+ }
695
+ installed.push({ key: authorityRowKey, expectedStoreVersion: participant.expectedStoreVersion.value });
696
+ continue;
697
+ }
698
+ // A peer can be in the middle of publishing this same aggregate.
699
+ // Do not abort its shared staging row merely because this attempt
700
+ // lost a marker CAS; re-enter and adopt its terminal state.
701
+ const aggregateRaced = await this.provider.read(rowKey, signal);
702
+ if (aggregateRaced.kind === 'found') {
703
+ const aggregateRecord = decodeJson<AggregateRecord>(aggregateRaced.value.bytes);
704
+ if (aggregateRecord.requestFingerprint === fingerprint
705
+ && (aggregateRecord.state === 'staging' || aggregateRecord.state === 'prepared')) {
706
+ return await this.prepareAggregate(request, signal);
707
+ }
708
+ }
709
+ await this.clearAggregateMarkers(fence, installed, signal);
710
+ await this.abortAggregateStaging(fence, signal);
711
+ return { kind: 'conflict' };
712
+ }
713
+ if (reservingOwnerGenerationBlock) {
714
+ ownerGenerationCounterRead = undefined;
715
+ }
716
+ installed.push({
717
+ key: authorityRowKey,
718
+ expectedStoreVersion: participant.expectedStoreVersion.value
719
+ });
720
+ }
721
+ if (!sameCapacityVector(sourceCapacity, request.capacity)) {
722
+ await this.clearAggregateMarkers(fence, installed, signal);
723
+ await this.abortAggregateStaging(fence, signal);
724
+ return { kind: 'conflict' };
725
+ }
726
+
727
+ aggregateRead = await this.provider.read(rowKey, signal);
728
+ if (aggregateRead.kind === 'missing') return { kind: 'conflict' };
729
+ const latest = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
730
+ if (latest.state === 'prepared' && latest.requestFingerprint === fingerprint) {
731
+ return { kind: 'alreadyPrepared', fence };
732
+ }
733
+ if (latest.state !== 'staging' || latest.requestFingerprint !== fingerprint) {
734
+ return { kind: 'conflict' };
735
+ }
736
+ const reserved = await this.provider.write({
737
+ conditions: [
738
+ { kind: 'version', key: rowKey, expected: aggregateRead.value.version },
739
+ versionCondition(targetDescriptorKey, descriptorRead),
740
+ versionCondition(targetLeaseKey, leaseRead),
741
+ conditionFor(targetCapacityKey, targetCapacityRead)
742
+ ],
743
+ mutations: [
744
+ {
745
+ kind: 'put',
746
+ key: rowKey,
747
+ bytes: encodeJson({ ...latest, state: 'prepared' } satisfies AggregateRecord)
748
+ },
749
+ {
750
+ kind: 'put',
751
+ key: targetCapacityKey,
752
+ bytes: encodeJson({
753
+ active: targetCapacity.active,
754
+ pending: addCapacity(targetCapacity.pending, request.capacity)
755
+ } satisfies CapacityRecord)
756
+ }
757
+ ]
758
+ }, signal);
759
+ if (reserved.kind === 'conflict') {
760
+ const raced = await this.provider.read(rowKey, signal);
761
+ if (raced.kind === 'found') {
762
+ const record = decodeJson<AggregateRecord>(raced.value.bytes);
763
+ if (record.state === 'prepared' && record.requestFingerprint === fingerprint) {
764
+ return { kind: 'alreadyPrepared', fence };
765
+ }
766
+ }
767
+ await this.clearAggregateMarkers(fence, installed, signal);
768
+ return { kind: 'conflict' };
769
+ }
770
+ return { kind: 'prepared', fence };
771
+ } catch (error) {
772
+ await this.abortAggregateStaging(fence, signal);
773
+ throw error;
774
+ }
775
+ }
776
+
777
+ override async commitAggregate(
778
+ fence: ZLinkAggregateFence,
779
+ signal?: AbortSignal
780
+ ): Promise<ZLinkAggregateCommitResult> {
781
+ validateAggregateFence(fence);
782
+ return await this.commitAggregateCore(
783
+ fence,
784
+ 0,
785
+ performance.now() + AGGREGATE_COMMIT_RETRY_WINDOW_MS,
786
+ signal
787
+ );
788
+ }
789
+
790
+ private async commitAggregateCore(
791
+ fence: ZLinkAggregateFence,
792
+ retryAttempt: number,
793
+ retryDeadlineAtMs: number,
794
+ signal?: AbortSignal
795
+ ): Promise<ZLinkAggregateCommitResult> {
796
+ const rowKey = aggregateKey(fence);
797
+ let aggregateRead = await this.provider.read(rowKey, signal);
798
+ if (aggregateRead.kind === 'missing') return { kind: 'stale' };
799
+ let aggregate = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
800
+ if (aggregate.state === 'aborted' || aggregate.state === 'staging') {
801
+ return { kind: 'stale' };
802
+ }
803
+ if (aggregate.state === 'committed') {
804
+ await this.normalizeCommittedAggregate(fence, aggregate, signal);
805
+ return { kind: 'alreadyCommitted' };
806
+ }
807
+ const entries = await this.aggregateInventory.read(
808
+ fence,
809
+ Buffer.from(aggregate.inventoryDigest),
810
+ signal
811
+ );
812
+ if (entries.length !== aggregate.participantCount) {
813
+ throw new Error('Aggregate inventory count differs from its authority record.');
814
+ }
815
+ const authorityRows = [];
816
+ for (let index = 0; index < entries.length; index++) {
817
+ const entry = entries[index]!;
818
+ const rowKeyForParticipant = authorityKey(entry.authorityKey);
819
+ const current = await this.provider.read(rowKeyForParticipant, signal);
820
+ if (current.kind === 'missing') return { kind: 'stale' };
821
+ const record = decodeAuthorityRecord(current.value.bytes);
822
+ if (!sameAggregateMarkerEntry(record.aggregate, fence, index, entry)) {
823
+ // A competing committer may already have published the aggregate and
824
+ // normalized this participant before this reader reached it. The
825
+ // committed aggregate is the terminal outcome to adopt, not a stale
826
+ // failure caused by observing the post-normalization row.
827
+ const latest = await this.provider.read(rowKey, signal);
828
+ if (latest.kind === 'found') {
829
+ const latestAggregate = decodeJson<AggregateRecord>(latest.value.bytes);
830
+ if (latestAggregate.state === 'committed') {
831
+ await this.normalizeCommittedAggregate(fence, latestAggregate, signal);
832
+ return { kind: 'alreadyCommitted' };
833
+ }
834
+ }
835
+ return { kind: 'stale' };
836
+ }
837
+ const [payload, membership] = await Promise.all([
838
+ requireProviderBytes(
839
+ this.provider,
840
+ aggregateParticipantPayloadKey(fence, index),
841
+ signal
842
+ ),
843
+ requireProviderBytes(
844
+ this.provider,
845
+ aggregateParticipantMembershipKey(fence, index),
846
+ signal
847
+ )
848
+ ]);
849
+ if (
850
+ sha256Hex(payload) !== entry.authorityPayloadSha256
851
+ || sha256Hex(membership) !== entry.membershipMutationSha256
852
+ ) {
853
+ throw new Error('Aggregate participant staging checksum does not match inventory.');
854
+ }
855
+ authorityRows.push({ key: rowKeyForParticipant, current, record, entry });
856
+ }
857
+
858
+ const targetDescriptorKey = meshKey(
859
+ aggregate.targetDescriptor.meshName,
860
+ aggregate.targetDescriptor.rid
861
+ );
862
+ const targetLeaseKey = ownerKey(aggregate.targetOwner.ownerId);
863
+ const targetCapacityKey = capacityKey(
864
+ aggregate.targetDescriptor.meshName,
865
+ String(aggregate.targetDescriptor.rid)
866
+ );
867
+ const [descriptorRead, leaseRead] = await Promise.all([
868
+ this.provider.read(targetDescriptorKey, signal),
869
+ this.provider.read(targetLeaseKey, signal)
870
+ ]);
871
+ if (
872
+ liveTargetDescriptor(
873
+ descriptorRead,
874
+ leaseRead,
875
+ aggregateTargetFromRecord(aggregate)
876
+ ) === undefined
877
+ ) {
878
+ return { kind: 'stale' };
879
+ }
880
+
881
+ const capacityDeltas = new Map<string, ZLinkCapacityVector>();
882
+ for (const row of authorityRows) {
883
+ if (row.entry.ownerTransition !== 'newOwner') continue;
884
+ const key = capacityKey(
885
+ row.record.snapshot.allocation.descriptor.meshName,
886
+ String(row.record.snapshot.allocation.descriptor.rid)
887
+ ).value;
888
+ capacityDeltas.set(
889
+ key,
890
+ addCapacityVector(
891
+ capacityDeltas.get(key) ?? { actors: 0, spots: 0 },
892
+ row.record.snapshot.allocation.capacity
893
+ )
894
+ );
895
+ }
896
+ const capacityKeys = new Map<string, ZLinkStoreKey>();
897
+ capacityKeys.set(targetCapacityKey.value, targetCapacityKey);
898
+ for (const value of capacityDeltas.keys()) capacityKeys.set(value, storeKey(value));
899
+ const capacityReads = new Map<string, Extract<ZLinkStoreReadResult, { kind: 'found' }>>();
900
+ for (const [value, key] of capacityKeys) {
901
+ const read = await this.provider.read(key, signal);
902
+ if (read.kind === 'missing') {
903
+ // Capacity rows are provider-private. A foreign source legitimately
904
+ // has no row under this provider's key encoding; its source runtime
905
+ // releases that capacity after observing the committed authority.
906
+ // The target row remains mandatory because this provider reserved it
907
+ // during prepare and must consume it atomically with commit.
908
+ if (value === targetCapacityKey.value) return { kind: 'stale' };
909
+ capacityKeys.delete(value);
910
+ continue;
911
+ }
912
+ capacityReads.set(value, read);
913
+ }
914
+ const capacityMutations = [];
915
+ for (const [value, key] of capacityKeys) {
916
+ const read = capacityReads.get(value)!;
917
+ let capacity = decodeJson<CapacityRecord>(read.value.bytes);
918
+ const sourceDelta = capacityDeltas.get(value);
919
+ if (sourceDelta !== undefined) {
920
+ capacity = {
921
+ active: subtractCapacity(capacity.active, sourceDelta),
922
+ pending: capacity.pending
923
+ };
924
+ }
925
+ if (value === targetCapacityKey.value) {
926
+ capacity = {
927
+ active: addCapacity(capacity.active, aggregate.capacity),
928
+ pending: subtractCapacity(capacity.pending, aggregate.capacity)
929
+ };
930
+ }
931
+ capacityMutations.push({
932
+ kind: 'put' as const,
933
+ key,
934
+ bytes: encodeJson(capacity)
935
+ });
936
+ }
937
+ const published = await this.provider.write({
938
+ conditions: [
939
+ { kind: 'version', key: rowKey, expected: aggregateRead.value.version },
940
+ versionCondition(targetDescriptorKey, descriptorRead),
941
+ versionCondition(targetLeaseKey, leaseRead),
942
+ ...[...capacityReads.entries()].map(([value, read]) => ({
943
+ kind: 'version' as const,
944
+ key: capacityKeys.get(value)!,
945
+ expected: read.value.version
946
+ }))
947
+ ],
948
+ mutations: [
949
+ {
950
+ kind: 'put',
951
+ key: rowKey,
952
+ bytes: encodeJson({ ...aggregate, state: 'committed' } satisfies AggregateRecord)
953
+ },
954
+ ...capacityMutations
955
+ ]
956
+ }, signal);
957
+ if (published.kind === 'conflict') {
958
+ aggregateRead = await this.provider.read(rowKey, signal);
959
+ if (aggregateRead.kind === 'missing') return { kind: 'stale' };
960
+ aggregate = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
961
+ if (aggregate.state === 'prepared'
962
+ && retryAttempt < MAX_AGGREGATE_COMMIT_CONFLICT_RETRIES
963
+ && performance.now() < retryDeadlineAtMs) {
964
+ // The commit CAS also fences the target's live owner lease, descriptor,
965
+ // and capacity rows. Re-read the whole prepared fence after an
966
+ // auxiliary-row race; a changed aggregate or participant fence exits
967
+ // through the normal stale checks on the next attempt.
968
+ await waitForAggregateCommitRetry(retryAttempt, retryDeadlineAtMs, signal);
969
+ return await this.commitAggregateCore(
970
+ fence,
971
+ retryAttempt + 1,
972
+ retryDeadlineAtMs,
973
+ signal
974
+ );
975
+ }
976
+ if (aggregate.state !== 'committed') return { kind: 'stale' };
977
+ } else {
978
+ aggregate = { ...aggregate, state: 'committed' };
979
+ }
980
+ await this.normalizeCommittedAggregate(fence, aggregate, signal);
981
+ return { kind: 'committed' };
982
+ }
983
+
984
+ override async abortAggregate(
985
+ fence: ZLinkAggregateFence,
986
+ signal?: AbortSignal
987
+ ): Promise<ZLinkAggregateAbortResult> {
988
+ validateAggregateFence(fence);
989
+ const rowKey = aggregateKey(fence);
990
+ for (;;) {
991
+ const current = await this.provider.read(rowKey, signal);
992
+ if (current.kind === 'missing') return { kind: 'stale' };
993
+ const aggregate = decodeJson<AggregateRecord>(current.value.bytes);
994
+ if (aggregate.state === 'aborted') {
995
+ await this.clearAggregateMarkersByScan(fence, signal);
996
+ return { kind: 'alreadyAborted' };
997
+ }
998
+ if (aggregate.state === 'committed') return { kind: 'stale' };
999
+ const conditions: ZLinkStoreCondition[] = [{
1000
+ kind: 'version',
1001
+ key: rowKey,
1002
+ expected: current.value.version
1003
+ }];
1004
+ const mutations: ZLinkStoreWriteRequest['mutations'][number][] = [{
1005
+ kind: 'put',
1006
+ key: rowKey,
1007
+ bytes: encodeJson({ ...aggregate, state: 'aborted' } satisfies AggregateRecord)
1008
+ }];
1009
+ if (aggregate.state === 'prepared') {
1010
+ const targetCapacityKey = capacityKey(
1011
+ aggregate.targetDescriptor.meshName,
1012
+ String(aggregate.targetDescriptor.rid)
1013
+ );
1014
+ const targetCapacityRead = await this.provider.read(targetCapacityKey, signal);
1015
+ if (targetCapacityRead.kind === 'missing') return { kind: 'stale' };
1016
+ const capacity = decodeJson<CapacityRecord>(targetCapacityRead.value.bytes);
1017
+ conditions.push({
1018
+ kind: 'version',
1019
+ key: targetCapacityKey,
1020
+ expected: targetCapacityRead.value.version
1021
+ });
1022
+ mutations.push({
1023
+ kind: 'put',
1024
+ key: targetCapacityKey,
1025
+ bytes: encodeJson({
1026
+ active: capacity.active,
1027
+ pending: subtractCapacity(capacity.pending, aggregate.capacity)
1028
+ } satisfies CapacityRecord)
1029
+ });
1030
+ }
1031
+ const result = await this.provider.write({ conditions, mutations }, signal);
1032
+ if (result.kind === 'conflict') continue;
1033
+ await this.clearAggregateMarkersByScan(fence, signal);
1034
+ return { kind: 'aborted' };
1035
+ }
1036
+ }
1037
+
1038
+ override async reserve(
1039
+ request: ZLinkObjectReserveRequest,
1040
+ signal?: AbortSignal
1041
+ ): Promise<ZLinkObjectReserveResult> {
1042
+ const encodedAuthorityKey = encodeAuthorityKey(
1043
+ request.key.kind,
1044
+ request.key.globalId
1045
+ );
1046
+ for (;;) {
1047
+ signal?.throwIfAborted();
1048
+ const rowKey = authorityKey(encodedAuthorityKey.value);
1049
+ const descriptorKey = meshKey(request.target.meshName, request.target.nodeRid);
1050
+ const leaseKey = ownerKey(request.target.owner.ownerId);
1051
+ const capacityRowKey = capacityKey(
1052
+ request.target.meshName,
1053
+ String(request.target.nodeRid)
1054
+ );
1055
+ const [
1056
+ current,
1057
+ descriptorRead,
1058
+ leaseRead,
1059
+ capacityRead,
1060
+ objectGenerationRead,
1061
+ authorityOwnerGenerationRead
1062
+ ] =
1063
+ await Promise.all([
1064
+ this.provider.read(rowKey, signal),
1065
+ this.provider.read(descriptorKey, signal),
1066
+ this.provider.read(leaseKey, signal),
1067
+ this.provider.read(capacityRowKey, signal),
1068
+ this.provider.read(OBJECT_COUNTER_KEY, signal),
1069
+ this.provider.read(AUTHORITY_OWNER_COUNTER_KEY, signal)
1070
+ ]);
1071
+ if (current.kind === 'found') {
1072
+ const record = decodeAuthorityRecord(current.value.bytes);
1073
+ const snapshot = authoritySnapshot(
1074
+ record.snapshot,
1075
+ current.value.version,
1076
+ current.value.storeNow
1077
+ );
1078
+ if (
1079
+ snapshot.allocation.objectKind !== request.key.kind
1080
+ || snapshot.allocation.stableType !== request.intent.stableType
1081
+ ) {
1082
+ return { kind: 'typeMismatch', current: snapshot };
1083
+ }
1084
+ return snapshot.allocation.state === 'active'
1085
+ ? { kind: 'alreadyExists', current: snapshot }
1086
+ : { kind: 'conflict', current: snapshot };
1087
+ }
1088
+ const descriptor = liveTargetDescriptor(
1089
+ descriptorRead,
1090
+ leaseRead,
1091
+ request.target
1092
+ );
1093
+ if (descriptor === undefined) {
1094
+ return { kind: 'conflict', current: { kind: 'missing', storeNow: current.storeNow } };
1095
+ }
1096
+ const capacity = capacityRead.kind === 'missing'
1097
+ ? emptyCapacityRecord()
1098
+ : decodeJson<CapacityRecord>(capacityRead.value.bytes);
1099
+ if (!capacityAvailable(descriptor, request.capacity, capacity)) {
1100
+ return { kind: 'placementCapacityExhausted' };
1101
+ }
1102
+ const generation = counterNextValue(objectGenerationRead);
1103
+ const authorityOwnerGeneration = counterNextValue(authorityOwnerGenerationRead);
1104
+ // Counters retain the next value to issue. Issuing MAX_GENERATION
1105
+ // would require persisting MAX_GENERATION + 1, which is outside the
1106
+ // contract's valid stored range, so it fails before this batch mutates.
1107
+ if (generation >= MAX_GENERATION || authorityOwnerGeneration >= MAX_GENERATION) {
1108
+ return { kind: 'generationExhausted' };
1109
+ }
1110
+ const reservationId = randomUUID();
1111
+ const allocation: ZLinkPlacementAllocation = {
1112
+ state: 'reserved',
1113
+ objectKind: request.key.kind,
1114
+ stableType: request.intent.stableType,
1115
+ descriptor: {
1116
+ meshName: request.target.meshName,
1117
+ rid: request.target.nodeRid
1118
+ },
1119
+ descriptorLifecycleGeneration: request.target.nodeLifecycleGeneration,
1120
+ capacity: cloneCapacity(request.capacity)
1121
+ };
1122
+ const record: AuthorityRecord = {
1123
+ reservationId,
1124
+ snapshot: {
1125
+ payload: Buffer.from(request.creatingPayload),
1126
+ objectGeneration: generation,
1127
+ authorityOwnerGeneration,
1128
+ ownerId: request.target.owner.ownerId,
1129
+ ownerLeaseGeneration: request.target.owner.leaseGeneration,
1130
+ allocation,
1131
+ pendingCreation: {
1132
+ reservationId,
1133
+ requestContentReference: request.intent.requestContentReference,
1134
+ requestSha256: Buffer.from(request.intent.requestSha256),
1135
+ requestEncodedSize: request.intent.requestEncodedSize
1136
+ }
1137
+ }
1138
+ };
1139
+ const result = await this.provider.write({
1140
+ conditions: [
1141
+ { kind: 'missing', key: rowKey },
1142
+ versionCondition(descriptorKey, descriptorRead),
1143
+ versionCondition(leaseKey, leaseRead),
1144
+ conditionFor(capacityRowKey, capacityRead),
1145
+ conditionFor(OBJECT_COUNTER_KEY, objectGenerationRead),
1146
+ conditionFor(AUTHORITY_OWNER_COUNTER_KEY, authorityOwnerGenerationRead)
1147
+ ],
1148
+ mutations: [
1149
+ { kind: 'put', key: rowKey, bytes: encodeAuthorityRecord(record) },
1150
+ {
1151
+ kind: 'put',
1152
+ key: capacityRowKey,
1153
+ bytes: encodeJson({
1154
+ active: capacity.active,
1155
+ pending: addCapacity(capacity.pending, request.capacity)
1156
+ } satisfies CapacityRecord)
1157
+ },
1158
+ {
1159
+ kind: 'put',
1160
+ key: OBJECT_COUNTER_KEY,
1161
+ bytes: encodeText((generation + 1n).toString())
1162
+ },
1163
+ {
1164
+ kind: 'put',
1165
+ key: AUTHORITY_OWNER_COUNTER_KEY,
1166
+ bytes: encodeText((authorityOwnerGeneration + 1n).toString())
1167
+ }
1168
+ ]
1169
+ }, signal);
1170
+ if (result.kind === 'conflict') continue;
1171
+ const version = result.putVersions.find(entry =>
1172
+ entry.key.value === rowKey.value)?.version;
1173
+ if (version === undefined) throw new Error('Authority reserve did not return a row version.');
1174
+ return {
1175
+ kind: 'reserved',
1176
+ reservationId,
1177
+ creating: authoritySnapshot(record.snapshot, version, result.storeNow)
1178
+ };
1179
+ }
1180
+ }
1181
+
1182
+ override async commit(
1183
+ request: ZLinkObjectCommitRequest,
1184
+ signal?: AbortSignal
1185
+ ): Promise<ZLinkObjectCommitResult> {
1186
+ const key = encodeAuthorityKey(request.key.kind, request.key.globalId);
1187
+ const rowKey = authorityKey(key.value);
1188
+ for (;;) {
1189
+ signal?.throwIfAborted();
1190
+ const current = await this.provider.read(rowKey, signal);
1191
+ if (current.kind === 'missing') return { kind: 'stale' };
1192
+ const record = decodeAuthorityRecord(current.value.bytes);
1193
+ if (
1194
+ record.terminal === 'committed'
1195
+ && record.reservationId === request.reservationId
1196
+ && record.snapshot.allocation.state === 'active'
1197
+ ) {
1198
+ return {
1199
+ kind: 'alreadyCommitted',
1200
+ ready: authoritySnapshot(record.snapshot, current.value.version, current.value.storeNow)
1201
+ };
1202
+ }
1203
+ if (
1204
+ record.reservationId !== request.reservationId
1205
+ || current.value.version.value !== request.expectedStoreVersion
1206
+ || record.snapshot.allocation.state !== 'reserved'
1207
+ || !sameCreationTarget(record.snapshot, request.target)
1208
+ ) {
1209
+ return { kind: 'stale' };
1210
+ }
1211
+ const descriptorKey = meshKey(request.target.meshName, request.target.nodeRid);
1212
+ const leaseKey = ownerKey(request.target.owner.ownerId);
1213
+ const capacityRowKey = capacityKey(request.target.meshName, request.target.nodeRid);
1214
+ const [descriptorRead, leaseRead, capacityRead] = await Promise.all([
1215
+ this.provider.read(descriptorKey, signal),
1216
+ this.provider.read(leaseKey, signal),
1217
+ this.provider.read(capacityRowKey, signal)
1218
+ ]);
1219
+ if (liveTargetDescriptor(descriptorRead, leaseRead, request.target) === undefined) {
1220
+ return { kind: 'stale' };
1221
+ }
1222
+ const capacity = capacityRead.kind === 'missing'
1223
+ ? emptyCapacityRecord()
1224
+ : decodeJson<CapacityRecord>(capacityRead.value.bytes);
1225
+ const ready: AuthorityRecord = {
1226
+ reservationId: request.reservationId,
1227
+ terminal: 'committed',
1228
+ snapshot: {
1229
+ ...record.snapshot,
1230
+ payload: Buffer.from(request.readyPayload),
1231
+ allocation: { ...record.snapshot.allocation, state: 'active' },
1232
+ pendingCreation: undefined
1233
+ }
1234
+ };
1235
+ const result = await this.provider.write({
1236
+ conditions: [
1237
+ { kind: 'version', key: rowKey, expected: current.value.version },
1238
+ versionCondition(descriptorKey, descriptorRead),
1239
+ versionCondition(leaseKey, leaseRead),
1240
+ conditionFor(capacityRowKey, capacityRead)
1241
+ ],
1242
+ mutations: [
1243
+ { kind: 'put', key: rowKey, bytes: encodeAuthorityRecord(ready) },
1244
+ {
1245
+ kind: 'put',
1246
+ key: capacityRowKey,
1247
+ bytes: encodeJson({
1248
+ active: addCapacity(capacity.active, record.snapshot.allocation.capacity),
1249
+ pending: subtractCapacity(capacity.pending, record.snapshot.allocation.capacity)
1250
+ } satisfies CapacityRecord)
1251
+ }
1252
+ ]
1253
+ }, signal);
1254
+ if (result.kind === 'conflict') continue;
1255
+ const version = result.putVersions.find(entry =>
1256
+ entry.key.value === rowKey.value)?.version;
1257
+ if (version === undefined) throw new Error('Authority commit did not return a row version.');
1258
+ return {
1259
+ kind: 'committed',
1260
+ ready: authoritySnapshot(ready.snapshot, version, result.storeNow)
1261
+ };
1262
+ }
1263
+ }
1264
+
1265
+ override async abort(
1266
+ request: ZLinkObjectAbortRequest,
1267
+ signal?: AbortSignal
1268
+ ): Promise<ZLinkObjectAbortResult> {
1269
+ const key = encodeAuthorityKey(request.key.kind, request.key.globalId);
1270
+ const rowKey = authorityKey(key.value);
1271
+ for (;;) {
1272
+ signal?.throwIfAborted();
1273
+ const current = await this.provider.read(rowKey, signal);
1274
+ if (current.kind === 'missing') return { kind: 'stale' };
1275
+ const record = decodeAuthorityRecord(current.value.bytes);
1276
+ if (
1277
+ record.reservationId !== request.reservationId
1278
+ || current.value.version.value !== request.expectedStoreVersion
1279
+ || record.snapshot.allocation.state !== 'reserved'
1280
+ || !sameCreationTarget(record.snapshot, request.target)
1281
+ ) {
1282
+ return { kind: 'stale' };
1283
+ }
1284
+ const leaseKey = ownerKey(request.target.owner.ownerId);
1285
+ const capacityRowKey = capacityKey(
1286
+ request.target.meshName,
1287
+ String(request.target.nodeRid)
1288
+ );
1289
+ const [leaseRead, capacityRead] = await Promise.all([
1290
+ this.provider.read(leaseKey, signal),
1291
+ this.provider.read(capacityRowKey, signal)
1292
+ ]);
1293
+ if (!sameLiveOwner(leaseRead, record.snapshot)) return { kind: 'stale' };
1294
+ const capacity = capacityRead.kind === 'missing'
1295
+ ? emptyCapacityRecord()
1296
+ : decodeJson<CapacityRecord>(capacityRead.value.bytes);
1297
+ const result = await this.provider.write({
1298
+ conditions: [
1299
+ { kind: 'version', key: rowKey, expected: current.value.version },
1300
+ versionCondition(leaseKey, leaseRead),
1301
+ conditionFor(capacityRowKey, capacityRead)
1302
+ ],
1303
+ mutations: [
1304
+ { kind: 'delete', key: rowKey },
1305
+ {
1306
+ kind: 'put',
1307
+ key: capacityRowKey,
1308
+ bytes: encodeJson({
1309
+ active: capacity.active,
1310
+ pending: subtractCapacity(
1311
+ capacity.pending,
1312
+ record.snapshot.allocation.capacity
1313
+ )
1314
+ } satisfies CapacityRecord)
1315
+ }
1316
+ ]
1317
+ }, signal);
1318
+ if (result.kind === 'conflict') continue;
1319
+ return { kind: 'aborted' };
1320
+ }
1321
+ }
1322
+
1323
+ override async completeCreation(
1324
+ request: ZLinkObjectCreationCompleteRequest,
1325
+ signal?: AbortSignal
1326
+ ): Promise<ZLinkObjectCreationCompleteResult> {
1327
+ if (request.key.kind !== 'actor') {
1328
+ throw new TypeError('completeCreation is reserved for Actor creation.');
1329
+ }
1330
+ const terminal = createTerminalRecord(
1331
+ request,
1332
+ this.nowProvider()
1333
+ );
1334
+ const rowKey = authorityKey(
1335
+ encodeAuthorityKey(request.key.kind, request.key.globalId).value
1336
+ );
1337
+ const terminalRowKey = creationTerminalKey(terminal.operation);
1338
+ for (;;) {
1339
+ signal?.throwIfAborted();
1340
+ const [current, existingTerminal] = await Promise.all([
1341
+ this.provider.read(rowKey, signal),
1342
+ this.provider.read(terminalRowKey, signal)
1343
+ ]);
1344
+ if (existingTerminal.kind === 'found') {
1345
+ return {
1346
+ kind: 'alreadyCompleted',
1347
+ terminal: reviveCreationTerminal(
1348
+ decodeJson<ZLinkCreationTerminalRecord>(existingTerminal.value.bytes)
1349
+ )
1350
+ };
1351
+ }
1352
+ if (current.kind === 'missing') return { kind: 'stale' };
1353
+ const record = decodeAuthorityRecord(current.value.bytes);
1354
+ if (
1355
+ record.reservationId !== request.reservationId
1356
+ || current.value.version.value !== request.expectedStoreVersion
1357
+ || record.snapshot.allocation.state !== 'reserved'
1358
+ || !sameCreationTarget(record.snapshot, request.target)
1359
+ ) {
1360
+ return { kind: 'stale' };
1361
+ }
1362
+ const descriptorKey = meshKey(request.target.meshName, request.target.nodeRid);
1363
+ const leaseKey = ownerKey(request.target.owner.ownerId);
1364
+ const capacityRowKey = capacityKey(request.target.meshName, request.target.nodeRid);
1365
+ const [descriptorRead, leaseRead, capacityRead] = await Promise.all([
1366
+ this.provider.read(descriptorKey, signal),
1367
+ this.provider.read(leaseKey, signal),
1368
+ this.provider.read(capacityRowKey, signal)
1369
+ ]);
1370
+ if (liveTargetDescriptor(descriptorRead, leaseRead, request.target) === undefined) {
1371
+ return { kind: 'stale' };
1372
+ }
1373
+ const capacity = capacityRead.kind === 'missing'
1374
+ ? emptyCapacityRecord()
1375
+ : decodeJson<CapacityRecord>(capacityRead.value.bytes);
1376
+ const terminalAtStore = {
1377
+ ...terminal,
1378
+ storeNow: current.value.storeNow
1379
+ };
1380
+ const retentionMs = terminalAtStore.expiresAt.getTime()
1381
+ - current.value.storeNow.getTime();
1382
+ if (retentionMs <= 0) {
1383
+ throw new RangeError(
1384
+ 'Creation terminal expiry must be the live operation deadline plus five minutes.'
1385
+ );
1386
+ }
1387
+ const mutations = request.completion.kind === 'created'
1388
+ ? [
1389
+ {
1390
+ kind: 'put' as const,
1391
+ key: rowKey,
1392
+ bytes: encodeAuthorityRecord({
1393
+ reservationId: request.reservationId,
1394
+ terminal: 'committed',
1395
+ snapshot: {
1396
+ ...record.snapshot,
1397
+ payload: Buffer.from(request.completion.readyPayload),
1398
+ allocation: { ...record.snapshot.allocation, state: 'active' },
1399
+ pendingCreation: undefined
1400
+ }
1401
+ } satisfies AuthorityRecord)
1402
+ },
1403
+ {
1404
+ kind: 'put' as const,
1405
+ key: capacityRowKey,
1406
+ bytes: encodeJson({
1407
+ active: addCapacity(capacity.active, record.snapshot.allocation.capacity),
1408
+ pending: subtractCapacity(capacity.pending, record.snapshot.allocation.capacity)
1409
+ } satisfies CapacityRecord)
1410
+ }
1411
+ ]
1412
+ : [
1413
+ { kind: 'delete' as const, key: rowKey },
1414
+ {
1415
+ kind: 'put' as const,
1416
+ key: capacityRowKey,
1417
+ bytes: encodeJson({
1418
+ active: capacity.active,
1419
+ pending: subtractCapacity(capacity.pending, record.snapshot.allocation.capacity)
1420
+ } satisfies CapacityRecord)
1421
+ }
1422
+ ];
1423
+ const result = await this.provider.write({
1424
+ conditions: [
1425
+ { kind: 'version', key: rowKey, expected: current.value.version },
1426
+ { kind: 'missing', key: terminalRowKey },
1427
+ versionCondition(descriptorKey, descriptorRead),
1428
+ versionCondition(leaseKey, leaseRead),
1429
+ conditionFor(capacityRowKey, capacityRead)
1430
+ ],
1431
+ mutations: [
1432
+ ...mutations,
1433
+ {
1434
+ kind: 'put',
1435
+ key: terminalRowKey,
1436
+ bytes: encodeJson(terminalAtStore),
1437
+ retentionMs
1438
+ }
1439
+ ]
1440
+ }, signal);
1441
+ if (result.kind === 'conflict') continue;
1442
+ const publishedTerminal = {
1443
+ ...terminalAtStore,
1444
+ storeNow: result.storeNow
1445
+ };
1446
+ if (request.completion.kind !== 'created') {
1447
+ return { kind: request.completion.kind, terminal: publishedTerminal };
1448
+ }
1449
+ const version = result.putVersions.find(entry =>
1450
+ entry.key.value === rowKey.value)?.version;
1451
+ if (version === undefined) {
1452
+ throw new Error('Actor creation completion did not return an authority row version.');
1453
+ }
1454
+ const readyRecord = decodeAuthorityRecord(
1455
+ encodeAuthorityRecord({
1456
+ reservationId: request.reservationId,
1457
+ terminal: 'committed',
1458
+ snapshot: {
1459
+ ...record.snapshot,
1460
+ payload: Buffer.from(request.completion.readyPayload),
1461
+ allocation: { ...record.snapshot.allocation, state: 'active' },
1462
+ pendingCreation: undefined
1463
+ }
1464
+ } satisfies AuthorityRecord)
1465
+ );
1466
+ return {
1467
+ kind: 'created',
1468
+ ready: authoritySnapshot(readyRecord.snapshot, version, result.storeNow),
1469
+ terminal: publishedTerminal
1470
+ };
1471
+ }
1472
+ }
1473
+
1474
+ override async readCreationTerminal(
1475
+ operation: ZLinkCreationOperationIdentity,
1476
+ signal?: AbortSignal
1477
+ ): Promise<ZLinkCreationTerminalReadResult> {
1478
+ validateCreationOperation(operation);
1479
+ const result = await this.provider.read(creationTerminalKey(operation), signal);
1480
+ return result.kind === 'missing'
1481
+ ? { kind: 'missing', storeNow: result.storeNow }
1482
+ : {
1483
+ kind: 'found',
1484
+ record: reviveCreationTerminal(
1485
+ decodeJson<ZLinkCreationTerminalRecord>(result.value.bytes)
1486
+ )
1487
+ };
1488
+ }
1489
+
1490
+ override async claimOwnerLease(
1491
+ ownerId: string,
1492
+ leaseTtlMs: number,
1493
+ signal?: AbortSignal
1494
+ ): Promise<ZLinkOwnerLeaseClaimResult> {
1495
+ requireOwnerInput(ownerId, leaseTtlMs);
1496
+ for (;;) {
1497
+ const [owner, counter] = await Promise.all([
1498
+ this.provider.read(ownerKey(ownerId), signal),
1499
+ this.provider.read(OWNER_COUNTER_KEY, signal)
1500
+ ]);
1501
+ if (owner.kind === 'found') return { kind: 'conflict' };
1502
+ const generation = counterNextValue(counter);
1503
+ // Counters retain the next value to issue. Issuing MAX_GENERATION would
1504
+ // require persisting MAX_GENERATION + 1, outside the stored range.
1505
+ if (generation >= MAX_GENERATION) return { kind: 'generationExhausted' };
1506
+ const token = { ownerId, leaseGeneration: generation };
1507
+ const conditions: ZLinkStoreCondition[] = [
1508
+ { kind: 'missing', key: ownerKey(ownerId) },
1509
+ counter.kind === 'missing'
1510
+ ? { kind: 'missing', key: OWNER_COUNTER_KEY }
1511
+ : { kind: 'version', key: OWNER_COUNTER_KEY, expected: counter.value.version }
1512
+ ];
1513
+ const result = await this.provider.write({
1514
+ conditions,
1515
+ mutations: [
1516
+ {
1517
+ kind: 'put',
1518
+ key: ownerKey(ownerId),
1519
+ bytes: encodeOwnerRecord(ownerId, generation),
1520
+ retentionMs: leaseTtlMs
1521
+ },
1522
+ {
1523
+ kind: 'put',
1524
+ key: OWNER_COUNTER_KEY,
1525
+ bytes: encodeText((generation + 1n).toString())
1526
+ }
1527
+ ]
1528
+ }, signal);
1529
+ if (result.kind === 'conflict') continue;
1530
+ return {
1531
+ kind: 'claimed',
1532
+ token,
1533
+ leaseExpiresAt: new Date(result.storeNow.getTime() + leaseTtlMs),
1534
+ storeNow: result.storeNow
1535
+ };
1536
+ }
1537
+ }
1538
+
1539
+ override async readOwnerLease(
1540
+ ownerId: string,
1541
+ signal?: AbortSignal
1542
+ ): Promise<ZLinkOwnerLeaseReadResult> {
1543
+ const result = await this.provider.read(ownerKey(ownerId), signal);
1544
+ if (result.kind === 'missing') return { kind: 'missing' };
1545
+ const record = decodeOwnerRecord(result.value.bytes);
1546
+ if (record.ownerId !== ownerId || result.value.expiresAt === undefined) {
1547
+ throw new Error('Location Store owner lease record is invalid.');
1548
+ }
1549
+ return {
1550
+ kind: 'found',
1551
+ token: { ownerId, leaseGeneration: BigInt(record.leaseGeneration) },
1552
+ leaseExpiresAt: result.value.expiresAt,
1553
+ storeNow: result.value.storeNow
1554
+ };
1555
+ }
1556
+
1557
+ override async renewOwnerLease(
1558
+ token: ZLinkLocationOwnerToken,
1559
+ leaseTtlMs: number,
1560
+ signal?: AbortSignal
1561
+ ): Promise<ZLinkOwnerLeaseRenewResult> {
1562
+ requireOwnerInput(token.ownerId, leaseTtlMs);
1563
+ const key = ownerKey(token.ownerId);
1564
+ const current = await this.provider.read(key, signal);
1565
+ if (current.kind === 'missing') return { kind: 'stale' };
1566
+ const record = decodeOwnerRecord(current.value.bytes);
1567
+ if (BigInt(record.leaseGeneration) !== token.leaseGeneration) return { kind: 'stale' };
1568
+ const result = await this.provider.write({
1569
+ conditions: [{ kind: 'version', key, expected: current.value.version }],
1570
+ mutations: [{
1571
+ kind: 'put',
1572
+ key,
1573
+ bytes: current.value.bytes,
1574
+ retentionMs: leaseTtlMs
1575
+ }]
1576
+ }, signal);
1577
+ if (result.kind === 'conflict') return { kind: 'stale' };
1578
+ return {
1579
+ kind: 'renewed',
1580
+ leaseExpiresAt: new Date(result.storeNow.getTime() + leaseTtlMs),
1581
+ storeNow: result.storeNow
1582
+ };
1583
+ }
1584
+
1585
+ override async releaseOwnerLease(
1586
+ token: ZLinkLocationOwnerToken,
1587
+ signal?: AbortSignal
1588
+ ): Promise<ZLinkOwnerLeaseReleaseResult> {
1589
+ const key = ownerKey(token.ownerId);
1590
+ const current = await this.provider.read(key, signal);
1591
+ if (current.kind === 'missing') return 'stale';
1592
+ const record = decodeOwnerRecord(current.value.bytes);
1593
+ if (BigInt(record.leaseGeneration) !== token.leaseGeneration) return 'stale';
1594
+ const result = await this.provider.write({
1595
+ conditions: [{ kind: 'version', key, expected: current.value.version }],
1596
+ mutations: [{ kind: 'delete', key }]
1597
+ }, signal);
1598
+ return result.kind === 'applied' ? 'released' : 'stale';
1599
+ }
1600
+
1601
+ override async updateMeshNode(
1602
+ descriptor: ZLinkMeshNodeDescriptor,
1603
+ intent: ZLinkLocationWriteIntent,
1604
+ signal?: AbortSignal
1605
+ ): Promise<ZLinkLocationWriteResult> {
1606
+ const leaseKey = ownerKey(descriptor.ownerId);
1607
+ const rowKey = meshKey(descriptor.meshName, descriptor.rid);
1608
+ const [lease, current] = await Promise.all([
1609
+ this.provider.read(leaseKey, signal),
1610
+ this.provider.read(rowKey, signal)
1611
+ ]);
1612
+ if (lease.kind === 'missing') return rejected(lease.storeNow);
1613
+ if (liveOwnerLeaseGeneration(lease) !== descriptor.leaseGeneration) {
1614
+ return rejected(lease.value.storeNow);
1615
+ }
1616
+
1617
+ let generation = 1n;
1618
+ let rowCondition: ZLinkStoreCondition = { kind: 'missing', key: rowKey };
1619
+ if (current.kind === 'found') {
1620
+ const record = decodeCanonicalDescriptorRecord<ZLinkMeshNodeDescriptor>(current.value.bytes);
1621
+ const stored = reviveMeshDescriptor(record.descriptor);
1622
+ generation = descriptorStoreGeneration(record, current.value.version.value);
1623
+ if (sameMeshDescriptor(stored, descriptor)) {
1624
+ return { status: WriteStatus.Stored, generation, updatedAt: current.value.storeNow };
1625
+ }
1626
+ const currentLease = await this.provider.read(ownerKey(stored.ownerId), signal);
1627
+ const currentLeaseGeneration = liveOwnerLeaseGeneration(currentLease);
1628
+ const takeover = canTakeOverStoredLocation(
1629
+ intent,
1630
+ stored.ownerId,
1631
+ stored.leaseGeneration,
1632
+ descriptor.ownerId,
1633
+ descriptor.leaseGeneration,
1634
+ currentLeaseGeneration
1635
+ );
1636
+ const renew = intent === 2
1637
+ && stored.ownerId === descriptor.ownerId
1638
+ && stored.leaseGeneration === descriptor.leaseGeneration
1639
+ && stored.lifecycleGeneration === descriptor.lifecycleGeneration
1640
+ && descriptor.descriptorRevision > stored.descriptorRevision;
1641
+ if (!takeover && !renew) {
1642
+ return {
1643
+ status: WriteStatus.IgnoredStale,
1644
+ generation,
1645
+ updatedAt: current.value.storeNow
1646
+ };
1647
+ }
1648
+ if (takeover) generation += 1n;
1649
+ rowCondition = { kind: 'version', key: rowKey, expected: current.value.version };
1650
+ } else if (intent === 2) {
1651
+ return rejected(lease.value.storeNow);
1652
+ }
1653
+
1654
+ const result = await this.provider.write({
1655
+ conditions: [
1656
+ { kind: 'version', key: leaseKey, expected: lease.value.version },
1657
+ rowCondition
1658
+ ],
1659
+ mutations: [{
1660
+ kind: 'put',
1661
+ key: rowKey,
1662
+ bytes: encodeCanonicalDescriptorRecord(generation, persistMeshDescriptor(descriptor))
1663
+ }]
1664
+ }, signal);
1665
+ if (result.kind === 'conflict') return rejected(result.storeNow);
1666
+ return { status: WriteStatus.Stored, generation, updatedAt: result.storeNow };
1667
+ }
1668
+
1669
+ override async removeMeshNode(
1670
+ key: ZLinkMeshNodeDescriptorKey,
1671
+ owner: ZLinkLocationOwnerToken,
1672
+ signal?: AbortSignal
1673
+ ): Promise<ZLinkLocationWriteStatus> {
1674
+ const rowKey = meshKey(key.meshName, key.rid);
1675
+ const current = await this.provider.read(rowKey, signal);
1676
+ if (current.kind === 'missing') return WriteStatus.IgnoredStale;
1677
+ const descriptor = reviveMeshDescriptor(decodeCanonicalDescriptorRecord<ZLinkMeshNodeDescriptor>(current.value.bytes).descriptor);
1678
+ if (descriptor.ownerId !== owner.ownerId
1679
+ || descriptor.leaseGeneration !== owner.leaseGeneration) {
1680
+ return WriteStatus.IgnoredStale;
1681
+ }
1682
+ const result = await this.provider.write({
1683
+ conditions: [{ kind: 'version', key: rowKey, expected: current.value.version }],
1684
+ mutations: [{ kind: 'delete', key: rowKey }]
1685
+ }, signal);
1686
+ return result.kind === 'applied' ? WriteStatus.Stored : WriteStatus.IgnoredStale;
1687
+ }
1688
+
1689
+ override async listMeshNodes(
1690
+ meshName: string,
1691
+ page: ZLinkPageRequest = {},
1692
+ signal?: AbortSignal
1693
+ ): Promise<ZLinkLocationPage<ZLinkMeshNodeDescriptor>> {
1694
+ const result = await this.provider.scan({
1695
+ prefix: meshPrefix(meshName),
1696
+ cursor: page.continuationToken === undefined
1697
+ ? undefined
1698
+ : ({ value: page.continuationToken } as ZLinkStoreScanCursor),
1699
+ limit: page.pageSize ?? 100
1700
+ }, signal);
1701
+ if (result.kind === 'expired') {
1702
+ throw new Error('Location Store scan snapshot expired.');
1703
+ }
1704
+ const items = await Promise.all(result.value.items.map(async item => {
1705
+ const descriptor = reviveMeshDescriptor(
1706
+ decodeCanonicalDescriptorRecord<ZLinkMeshNodeDescriptor>(item.value.bytes).descriptor
1707
+ );
1708
+ const capacityRead = await this.provider.read(
1709
+ capacityKey(descriptor.meshName, String(descriptor.rid)),
1710
+ signal
1711
+ );
1712
+ const capacity = capacityRead.kind === 'missing'
1713
+ ? emptyCapacityRecord()
1714
+ : decodeJson<CapacityRecord>(capacityRead.value.bytes);
1715
+ return {
1716
+ ...descriptor,
1717
+ populationCapacity: {
1718
+ actors: {
1719
+ ...descriptor.populationCapacity.actors,
1720
+ active: capacity.active.actors,
1721
+ reserved: capacity.pending.actors
1722
+ },
1723
+ spots: {
1724
+ ...descriptor.populationCapacity.spots,
1725
+ active: capacity.active.spots,
1726
+ reserved: capacity.pending.spots
1727
+ },
1728
+ spotTypes: descriptor.populationCapacity.spotTypes.map(value => {
1729
+ const key = capacityTypeKey({
1730
+ objectKind: value.objectKind,
1731
+ stableType: value.stableType,
1732
+ count: 0
1733
+ });
1734
+ return {
1735
+ ...value,
1736
+ active: capacity.active.spotTypes[key] ?? 0,
1737
+ reserved: capacity.pending.spotTypes[key] ?? 0
1738
+ };
1739
+ })
1740
+ }
1741
+ };
1742
+ }));
1743
+ return {
1744
+ items,
1745
+ continuationToken: result.value.nextCursor?.value
1746
+ };
1747
+ }
1748
+
1749
+ override async updateClientServer(
1750
+ descriptor: ZLinkClientServerServerDescriptor,
1751
+ intent: ZLinkLocationWriteIntent,
1752
+ signal?: AbortSignal
1753
+ ): Promise<ZLinkLocationWriteResult> {
1754
+ validateClientServerDescriptor(descriptor);
1755
+ const normalized = reviveClientServerDescriptor(descriptor);
1756
+ return this.updateDescriptor(
1757
+ clientServerKey(normalized.channelName, normalized.serverRid),
1758
+ normalized,
1759
+ intent,
1760
+ reviveClientServerDescriptor,
1761
+ sameClientServerDescriptor,
1762
+ canRenewClientServer,
1763
+ signal
1764
+ );
1765
+ }
1766
+
1767
+ override async removeClientServer(
1768
+ key: ZLinkClientServerServerDescriptorKey,
1769
+ owner: ZLinkLocationOwnerToken,
1770
+ signal?: AbortSignal
1771
+ ): Promise<ZLinkLocationWriteStatus> {
1772
+ return this.removeDescriptor(
1773
+ clientServerKey(key.channelName, key.serverRid),
1774
+ owner,
1775
+ reviveClientServerDescriptor,
1776
+ signal
1777
+ );
1778
+ }
1779
+
1780
+ override async listClientServers(
1781
+ channelName: string,
1782
+ page: ZLinkPageRequest = {},
1783
+ signal?: AbortSignal
1784
+ ): Promise<ZLinkLocationPage<ZLinkClientServerServerDescriptor>> {
1785
+ return this.listDescriptors(
1786
+ clientServerPrefix(channelName),
1787
+ page,
1788
+ reviveClientServerDescriptor,
1789
+ signal
1790
+ );
1791
+ }
1792
+
1793
+ override async updateFanoutPublisher(
1794
+ descriptor: ZLinkFanoutPublisherDescriptor,
1795
+ intent: ZLinkLocationWriteIntent,
1796
+ signal?: AbortSignal
1797
+ ): Promise<ZLinkLocationWriteResult> {
1798
+ validateFanoutPublisherDescriptor(descriptor);
1799
+ const normalized = reviveFanoutDescriptor(descriptor);
1800
+ return this.updateDescriptor(
1801
+ fanoutKey(normalized.channelName, normalized.publisherRid),
1802
+ normalized,
1803
+ intent,
1804
+ reviveFanoutDescriptor,
1805
+ sameFanoutDescriptor,
1806
+ canRenewFanout,
1807
+ signal
1808
+ );
1809
+ }
1810
+
1811
+ override async removeFanoutPublisher(
1812
+ key: ZLinkFanoutPublisherDescriptorKey,
1813
+ owner: ZLinkLocationOwnerToken,
1814
+ signal?: AbortSignal
1815
+ ): Promise<ZLinkLocationWriteStatus> {
1816
+ return this.removeDescriptor(
1817
+ fanoutKey(key.channelName, key.publisherRid),
1818
+ owner,
1819
+ reviveFanoutDescriptor,
1820
+ signal
1821
+ );
1822
+ }
1823
+
1824
+ override async listFanoutPublishers(
1825
+ channelName: string,
1826
+ page: ZLinkPageRequest = {},
1827
+ signal?: AbortSignal
1828
+ ): Promise<ZLinkLocationPage<ZLinkFanoutPublisherDescriptor>> {
1829
+ return this.listDescriptors(
1830
+ fanoutPrefix(channelName),
1831
+ page,
1832
+ reviveFanoutDescriptor,
1833
+ signal
1834
+ );
1835
+ }
1836
+
1837
+ override async updateSpot(
1838
+ location: ZLinkSpotLocation,
1839
+ intent: ZLinkLocationWriteIntent,
1840
+ signal?: AbortSignal
1841
+ ): Promise<ZLinkLocationWriteResult> {
1842
+ return this.updateOwnedLocation(
1843
+ spotKey(location.meshName, String(location.spotId)),
1844
+ normalizeSpot(location),
1845
+ intent,
1846
+ signal
1847
+ );
1848
+ }
1849
+
1850
+ override async removeSpot(
1851
+ key: ZLinkSpotLocationKey,
1852
+ owner: ZLinkLocationOwnerToken,
1853
+ signal?: AbortSignal
1854
+ ): Promise<ZLinkLocationWriteStatus> {
1855
+ return this.removeOwnedLocation(
1856
+ spotKey(key.meshName, String(key.spotId)),
1857
+ owner,
1858
+ signal
1859
+ );
1860
+ }
1861
+
1862
+ override async resolveSpot(
1863
+ key: ZLinkSpotLocationKey,
1864
+ signal?: AbortSignal
1865
+ ): Promise<ZLinkSpotLocation | undefined> {
1866
+ const value = await this.readOwnedLocation<ZLinkSpotLocation>(
1867
+ spotKey(key.meshName, String(key.spotId)),
1868
+ signal
1869
+ );
1870
+ return value === undefined ? undefined : normalizeSpot(value);
1871
+ }
1872
+
1873
+ override async listSpots(
1874
+ filter: ZLinkSpotLocationFilter,
1875
+ page: ZLinkPageRequest = {},
1876
+ signal?: AbortSignal
1877
+ ): Promise<ZLinkLocationPage<ZLinkSpotLocation>> {
1878
+ return this.listOwnedLocations(
1879
+ `${PREFIX}spot:`,
1880
+ page,
1881
+ normalizeSpot,
1882
+ value => matchesSpot(value, filter),
1883
+ signal
1884
+ );
1885
+ }
1886
+
1887
+ override async updateActor(
1888
+ location: ZLinkActorLocation,
1889
+ intent: ZLinkLocationWriteIntent,
1890
+ signal?: AbortSignal
1891
+ ): Promise<ZLinkLocationWriteResult> {
1892
+ return this.updateOwnedLocation(
1893
+ actorKey(location.meshName, location.actorId),
1894
+ normalizeActor(location),
1895
+ intent,
1896
+ signal
1897
+ );
1898
+ }
1899
+
1900
+ override async removeActor(
1901
+ key: ZLinkActorLocationKey,
1902
+ owner: ZLinkLocationOwnerToken,
1903
+ signal?: AbortSignal
1904
+ ): Promise<ZLinkLocationWriteStatus> {
1905
+ return this.removeOwnedLocation(actorKey(key.meshName, key.actorId), owner, signal);
1906
+ }
1907
+
1908
+ override async resolveActor(
1909
+ key: ZLinkActorLocationKey,
1910
+ signal?: AbortSignal
1911
+ ): Promise<ZLinkActorLocation | undefined> {
1912
+ const value = await this.readOwnedLocation<ZLinkActorLocation>(
1913
+ actorKey(key.meshName, key.actorId),
1914
+ signal
1915
+ );
1916
+ return value === undefined ? undefined : normalizeActor(value);
1917
+ }
1918
+
1919
+ override async listActors(
1920
+ filter: ZLinkActorLocationFilter,
1921
+ page: ZLinkPageRequest = {},
1922
+ signal?: AbortSignal
1923
+ ): Promise<ZLinkLocationPage<ZLinkActorLocation>> {
1924
+ return this.listOwnedLocations(
1925
+ `${PREFIX}actor:`,
1926
+ page,
1927
+ normalizeActor,
1928
+ value => matchesActor(value, filter),
1929
+ signal
1930
+ );
1931
+ }
1932
+
1933
+ override async updateRoute(
1934
+ location: ZLinkRouteLocation,
1935
+ intent: ZLinkLocationWriteIntent,
1936
+ signal?: AbortSignal
1937
+ ): Promise<ZLinkLocationWriteResult> {
1938
+ const rowKey = routeKey(String(location.routeKind), location.routeKey);
1939
+ const normalized = normalizeRoute(location);
1940
+ const current = await this.provider.read(rowKey, signal);
1941
+ let generation = 1n;
1942
+ let condition: ZLinkStoreCondition = { kind: 'missing', key: rowKey };
1943
+ if (current.kind === 'found') {
1944
+ const record = decodeJson<DescriptorRecord<ZLinkRouteLocation>>(current.value.bytes);
1945
+ const stored = normalizeRoute(record.descriptor);
1946
+ generation = BigInt(record.generation);
1947
+ if (intent === 1) {
1948
+ const ownerLease = await this.provider.read(ownerKey(stored.ownerId), signal);
1949
+ if (ownerLease.kind === 'found') {
1950
+ return {
1951
+ status: WriteStatus.RejectedConflict,
1952
+ generation,
1953
+ updatedAt: current.value.storeNow
1954
+ };
1955
+ }
1956
+ } else if (intent === 2
1957
+ && (stored.ownerId !== normalized.ownerId
1958
+ || normalized.generation !== 0n && stored.generation !== normalized.generation)) {
1959
+ return {
1960
+ status: WriteStatus.IgnoredStale,
1961
+ generation,
1962
+ updatedAt: current.value.storeNow
1963
+ };
1964
+ }
1965
+ if (intent !== 2) generation += 1n;
1966
+ condition = { kind: 'version', key: rowKey, expected: current.value.version };
1967
+ } else if (intent === 2) {
1968
+ return rejected(new Date());
1969
+ }
1970
+ const stored = { ...normalized, generation };
1971
+ const result = await this.provider.write({
1972
+ conditions: [condition],
1973
+ mutations: [{
1974
+ kind: 'put',
1975
+ key: rowKey,
1976
+ bytes: encodeJson<DescriptorRecord<ZLinkRouteLocation>>({
1977
+ generation: generation.toString(),
1978
+ descriptor: stored
1979
+ })
1980
+ }]
1981
+ }, signal);
1982
+ return result.kind === 'applied'
1983
+ ? { status: WriteStatus.Stored, generation, updatedAt: result.storeNow }
1984
+ : rejected(result.storeNow);
1985
+ }
1986
+
1987
+ override async removeRoute(
1988
+ key: ZLinkRouteLocationKey,
1989
+ owner: ZLinkLocationOwnerToken,
1990
+ signal?: AbortSignal
1991
+ ): Promise<ZLinkLocationWriteResult> {
1992
+ const rowKey = routeKey(String(key.routeKind), key.routeKey);
1993
+ const current = await this.provider.read(rowKey, signal);
1994
+ if (current.kind === 'missing') return rejected(current.storeNow);
1995
+ const record = decodeJson<DescriptorRecord<ZLinkRouteLocation>>(current.value.bytes);
1996
+ if (record.descriptor.ownerId !== owner.ownerId
1997
+ || record.descriptor.generation !== owner.leaseGeneration) {
1998
+ return {
1999
+ status: WriteStatus.IgnoredStale,
2000
+ generation: BigInt(record.generation),
2001
+ updatedAt: current.value.storeNow
2002
+ };
2003
+ }
2004
+ const result = await this.provider.write({
2005
+ conditions: [{ kind: 'version', key: rowKey, expected: current.value.version }],
2006
+ mutations: [{ kind: 'delete', key: rowKey }]
2007
+ }, signal);
2008
+ return result.kind === 'applied'
2009
+ ? { status: WriteStatus.Stored, generation: BigInt(record.generation), updatedAt: result.storeNow }
2010
+ : rejected(result.storeNow);
2011
+ }
2012
+
2013
+ override async resolveRoute(
2014
+ key: ZLinkRouteLocationKey,
2015
+ signal?: AbortSignal
2016
+ ): Promise<ZLinkRouteLocation | undefined> {
2017
+ const value = await this.readOwnedLocation<ZLinkRouteLocation>(
2018
+ routeKey(String(key.routeKind), key.routeKey),
2019
+ signal
2020
+ );
2021
+ return value === undefined ? undefined : normalizeRoute(value);
2022
+ }
2023
+
2024
+ override async listRoutes(
2025
+ filter: ZLinkRouteLocationFilter,
2026
+ page: ZLinkPageRequest = {},
2027
+ signal?: AbortSignal
2028
+ ): Promise<ZLinkLocationPage<ZLinkRouteLocation>> {
2029
+ return this.listOwnedLocations(
2030
+ `${PREFIX}route:`,
2031
+ page,
2032
+ normalizeRoute,
2033
+ value => matchesRoute(value, filter),
2034
+ signal
2035
+ );
2036
+ }
2037
+
2038
+ override async removeAllByOwner(
2039
+ owner: ZLinkLocationOwnerToken,
2040
+ signal?: AbortSignal
2041
+ ): Promise<bigint> {
2042
+ const leaseKey = ownerKey(owner.ownerId);
2043
+ const lease = await this.provider.read(leaseKey, signal);
2044
+ if (liveOwnerLeaseGeneration(lease) !== owner.leaseGeneration) return 0n;
2045
+ let removed = await this.removeOwnedAuthorities(owner, signal);
2046
+ const candidates: OwnerCleanupCandidate[] = [];
2047
+ for (const prefix of [
2048
+ 'mesh-node\0',
2049
+ 'client-server\0',
2050
+ 'fanout-publisher\0',
2051
+ `${PREFIX}spot:`,
2052
+ `${PREFIX}actor:`,
2053
+ `${PREFIX}route:`
2054
+ ]) {
2055
+ for (;;) {
2056
+ const prefixCandidates: OwnerCleanupCandidate[] = [];
2057
+ let cursor: ZLinkStoreScanCursor | undefined;
2058
+ let expired = false;
2059
+ do {
2060
+ const result = await this.provider.scan({ prefix, cursor, limit: 1_000 }, signal);
2061
+ if (result.kind === 'expired') {
2062
+ expired = true;
2063
+ break;
2064
+ }
2065
+ for (const item of result.value.items) {
2066
+ prefixCandidates.push({ key: item.key, scanVersion: item.value.version });
2067
+ }
2068
+ cursor = result.value.nextCursor;
2069
+ } while (cursor !== undefined);
2070
+ if (expired) {
2071
+ // Snapshot scan expiry invalidates every page from this prefix.
2072
+ // Restart from its first page instead of silently leaving rows
2073
+ // behind after a partial scan.
2074
+ continue;
2075
+ }
2076
+ candidates.push(...prefixCandidates);
2077
+ break;
2078
+ }
2079
+ }
2080
+ for (let offset = 0; offset < candidates.length; offset += MAX_OWNER_CLEANUP_BATCH_ROWS) {
2081
+ removed += await this.removeOwnerCleanupBatch(
2082
+ owner,
2083
+ leaseKey,
2084
+ candidates.slice(offset, offset + MAX_OWNER_CLEANUP_BATCH_ROWS),
2085
+ signal
2086
+ );
2087
+ }
2088
+ return removed + await super.removeAllByOwner(owner);
2089
+ }
2090
+
2091
+ private async removeOwnedAuthorities(
2092
+ owner: ZLinkLocationOwnerToken,
2093
+ signal?: AbortSignal
2094
+ ): Promise<bigint> {
2095
+ const candidates: OwnerCleanupCandidate[] = [];
2096
+ for (;;) {
2097
+ const pageCandidates: OwnerCleanupCandidate[] = [];
2098
+ let cursor: ZLinkStoreScanCursor | undefined;
2099
+ let expired = false;
2100
+ do {
2101
+ const result = await this.provider.scan({
2102
+ prefix: AUTHORITY_PREIMAGE_PREFIX,
2103
+ cursor,
2104
+ limit: 1_000
2105
+ }, signal);
2106
+ if (result.kind === 'expired') {
2107
+ expired = true;
2108
+ break;
2109
+ }
2110
+ for (const item of result.value.items) {
2111
+ pageCandidates.push({ key: item.key, scanVersion: item.value.version });
2112
+ }
2113
+ cursor = result.value.nextCursor;
2114
+ } while (cursor !== undefined);
2115
+ if (expired) {
2116
+ candidates.length = 0;
2117
+ continue;
2118
+ }
2119
+ candidates.push(...pageCandidates);
2120
+ break;
2121
+ }
2122
+
2123
+ let removed = 0n;
2124
+ for (const candidate of candidates) {
2125
+ signal?.throwIfAborted();
2126
+ const current = await this.provider.read(candidate.key, signal);
2127
+ if (current.kind === 'missing'
2128
+ || current.value.version.value !== candidate.scanVersion.value) continue;
2129
+ const record = decodeAuthorityRecord(current.value.bytes);
2130
+ if (
2131
+ record.snapshot.ownerId !== owner.ownerId
2132
+ || record.snapshot.ownerLeaseGeneration !== owner.leaseGeneration
2133
+ || record.aggregate !== undefined
2134
+ ) continue;
2135
+ const encodedAuthority = authorityContractValueFromPreimage(candidate.key.value);
2136
+ const identity = decodeAuthorityKey({ value: encodedAuthority } as ZLinkAuthorityKey);
2137
+ if (record.snapshot.allocation.state === 'active') {
2138
+ const result = await this.compareExchangeAuthority(
2139
+ { value: encodedAuthority } as ZLinkAuthorityKey,
2140
+ current.value.version as unknown as ZLinkAuthorityStoreVersion,
2141
+ { kind: 'delete' },
2142
+ signal
2143
+ );
2144
+ if (result.kind === 'deleted') removed += 1n;
2145
+ continue;
2146
+ }
2147
+ if (record.reservationId === undefined) continue;
2148
+ const aborted = await this.abort({
2149
+ key: identity,
2150
+ reservationId: record.reservationId,
2151
+ expectedStoreVersion: current.value.version.value,
2152
+ target: {
2153
+ meshName: record.snapshot.allocation.descriptor.meshName,
2154
+ nodeRid: record.snapshot.allocation.descriptor.rid,
2155
+ nodeLifecycleGeneration:
2156
+ record.snapshot.allocation.descriptorLifecycleGeneration,
2157
+ owner: {
2158
+ ownerId: record.snapshot.ownerId,
2159
+ leaseGeneration: record.snapshot.ownerLeaseGeneration
2160
+ }
2161
+ }
2162
+ }, signal);
2163
+ if (aborted.kind === 'aborted') removed += 1n;
2164
+ }
2165
+ return removed;
2166
+ }
2167
+
2168
+ private async removeOwnerCleanupBatch(
2169
+ owner: ZLinkLocationOwnerToken,
2170
+ leaseKey: ZLinkStoreKey,
2171
+ candidates: readonly OwnerCleanupCandidate[],
2172
+ signal?: AbortSignal
2173
+ ): Promise<bigint> {
2174
+ if (candidates.length === 0) return 0n;
2175
+
2176
+ const currentRows = await Promise.all(candidates.map(candidate =>
2177
+ this.provider.read(candidate.key, signal)));
2178
+ const unchangedOwnedRows: OwnerCleanupCandidate[] = [];
2179
+ for (let index = 0; index < candidates.length; index += 1) {
2180
+ const candidate = candidates[index]!;
2181
+ const current = currentRows[index]!;
2182
+ if (current.kind === 'missing'
2183
+ || current.value.version.value !== candidate.scanVersion.value) {
2184
+ continue;
2185
+ }
2186
+ const record = decodeJson<OwnerCleanupRecord>(current.value.bytes);
2187
+ const descriptor = record.descriptor;
2188
+ if (descriptor.ownerId !== owner.ownerId
2189
+ || descriptorOwnerLeaseGeneration(descriptor) !== owner.leaseGeneration) {
2190
+ continue;
2191
+ }
2192
+ unchangedOwnedRows.push({
2193
+ key: candidate.key,
2194
+ scanVersion: current.value.version
2195
+ });
2196
+ }
2197
+ if (unchangedOwnedRows.length === 0) return 0n;
2198
+
2199
+ const currentLease = await this.provider.read(leaseKey, signal);
2200
+ if (currentLease.kind === 'missing'
2201
+ || liveOwnerLeaseGeneration(currentLease) !== owner.leaseGeneration) {
2202
+ return 0n;
2203
+ }
2204
+ const result = await this.provider.write({
2205
+ conditions: [
2206
+ { kind: 'version', key: leaseKey, expected: currentLease.value.version },
2207
+ ...unchangedOwnedRows.map(row => ({
2208
+ kind: 'version' as const,
2209
+ key: row.key,
2210
+ expected: row.scanVersion
2211
+ }))
2212
+ ],
2213
+ mutations: unchangedOwnedRows.map(row => ({
2214
+ kind: 'delete' as const,
2215
+ key: row.key
2216
+ }))
2217
+ }, signal);
2218
+ if (result.kind === 'applied') return BigInt(unchangedOwnedRows.length);
2219
+
2220
+ // A row may have changed while the page was being prepared. Split the
2221
+ // bounded batch so unaffected rows can still be removed atomically, while
2222
+ // the changed row is discarded by the next version re-read. A changed
2223
+ // owner lease causes every recursive branch to stop at the fence above.
2224
+ if (unchangedOwnedRows.length === 1) return 0n;
2225
+ const midpoint = Math.ceil(unchangedOwnedRows.length / 2);
2226
+ const left = await this.removeOwnerCleanupBatch(
2227
+ owner,
2228
+ leaseKey,
2229
+ unchangedOwnedRows.slice(0, midpoint),
2230
+ signal
2231
+ );
2232
+ const right = await this.removeOwnerCleanupBatch(
2233
+ owner,
2234
+ leaseKey,
2235
+ unchangedOwnedRows.slice(midpoint),
2236
+ signal
2237
+ );
2238
+ return left + right;
2239
+ }
2240
+
2241
+ private async updateDescriptor<T extends OwnedDescriptor>(
2242
+ rowKey: ZLinkStoreKey,
2243
+ descriptor: T,
2244
+ intent: ZLinkLocationWriteIntent,
2245
+ revive: (descriptor: T) => T,
2246
+ same: (left: T, right: T) => boolean,
2247
+ canRenew: (current: T, next: T) => boolean,
2248
+ signal?: AbortSignal
2249
+ ): Promise<ZLinkLocationWriteResult> {
2250
+ const leaseKey = ownerKey(descriptor.ownerId);
2251
+ const [lease, current] = await Promise.all([
2252
+ this.provider.read(leaseKey, signal),
2253
+ this.provider.read(rowKey, signal)
2254
+ ]);
2255
+ if (lease.kind === 'missing') return rejected(lease.storeNow);
2256
+ if (liveOwnerLeaseGeneration(lease) !== descriptor.leaseGeneration) {
2257
+ return rejected(lease.value.storeNow);
2258
+ }
2259
+
2260
+ let generation = 1n;
2261
+ let rowCondition: ZLinkStoreCondition = { kind: 'missing', key: rowKey };
2262
+ if (current.kind === 'found') {
2263
+ const record = decodeCanonicalDescriptorRecord<T>(current.value.bytes);
2264
+ const stored = revive(record.descriptor);
2265
+ generation = descriptorStoreGeneration(record, current.value.version.value);
2266
+ if (same(stored, descriptor)) {
2267
+ return { status: WriteStatus.Stored, generation, updatedAt: current.value.storeNow };
2268
+ }
2269
+ const currentLease = await this.provider.read(ownerKey(stored.ownerId), signal);
2270
+ const currentLeaseGeneration = liveOwnerLeaseGeneration(currentLease);
2271
+ const takeover = canTakeOverStoredLocation(
2272
+ intent,
2273
+ stored.ownerId,
2274
+ stored.leaseGeneration,
2275
+ descriptor.ownerId,
2276
+ descriptor.leaseGeneration,
2277
+ currentLeaseGeneration
2278
+ );
2279
+ const renew = intent === 2 && canRenew(stored, descriptor);
2280
+ if (!takeover && !renew) {
2281
+ return {
2282
+ status: WriteStatus.IgnoredStale,
2283
+ generation,
2284
+ updatedAt: current.value.storeNow
2285
+ };
2286
+ }
2287
+ if (takeover) generation += 1n;
2288
+ rowCondition = { kind: 'version', key: rowKey, expected: current.value.version };
2289
+ } else if (intent === 2) {
2290
+ return rejected(lease.value.storeNow);
2291
+ }
2292
+
2293
+ const result = await this.provider.write({
2294
+ conditions: [
2295
+ { kind: 'version', key: leaseKey, expected: lease.value.version },
2296
+ rowCondition
2297
+ ],
2298
+ mutations: [{
2299
+ kind: 'put',
2300
+ key: rowKey,
2301
+ bytes: encodeCanonicalDescriptorRecord(generation, descriptor)
2302
+ }]
2303
+ }, signal);
2304
+ if (result.kind === 'conflict') return rejected(result.storeNow);
2305
+ return { status: WriteStatus.Stored, generation, updatedAt: result.storeNow };
2306
+ }
2307
+
2308
+ private async removeDescriptor<T extends OwnedDescriptor>(
2309
+ rowKey: ZLinkStoreKey,
2310
+ owner: ZLinkLocationOwnerToken,
2311
+ revive: (descriptor: T) => T,
2312
+ signal?: AbortSignal
2313
+ ): Promise<ZLinkLocationWriteStatus> {
2314
+ const current = await this.provider.read(rowKey, signal);
2315
+ if (current.kind === 'missing') return WriteStatus.IgnoredStale;
2316
+ const descriptor = revive(
2317
+ decodeCanonicalDescriptorRecord<T>(current.value.bytes).descriptor);
2318
+ if (descriptor.ownerId !== owner.ownerId
2319
+ || descriptor.leaseGeneration !== owner.leaseGeneration) {
2320
+ return WriteStatus.IgnoredStale;
2321
+ }
2322
+ const result = await this.provider.write({
2323
+ conditions: [{ kind: 'version', key: rowKey, expected: current.value.version }],
2324
+ mutations: [{ kind: 'delete', key: rowKey }]
2325
+ }, signal);
2326
+ return result.kind === 'applied' ? WriteStatus.Stored : WriteStatus.IgnoredStale;
2327
+ }
2328
+
2329
+ private async listDescriptors<T extends OwnedDescriptor>(
2330
+ prefix: string,
2331
+ page: ZLinkPageRequest,
2332
+ revive: (descriptor: T) => T,
2333
+ signal?: AbortSignal
2334
+ ): Promise<ZLinkLocationPage<T>> {
2335
+ const result = await this.provider.scan({
2336
+ prefix,
2337
+ cursor: page.continuationToken === undefined
2338
+ ? undefined
2339
+ : ({ value: page.continuationToken } as ZLinkStoreScanCursor),
2340
+ limit: page.pageSize ?? 100
2341
+ }, signal);
2342
+ if (result.kind === 'expired') {
2343
+ throw new Error('Location Store scan snapshot expired.');
2344
+ }
2345
+ return {
2346
+ items: result.value.items.map(item =>
2347
+ revive(decodeCanonicalDescriptorRecord<T>(item.value.bytes).descriptor)),
2348
+ continuationToken: result.value.nextCursor?.value
2349
+ };
2350
+ }
2351
+
2352
+ private async updateOwnedLocation<T extends LeaseOwnedLocation>(
2353
+ rowKey: ZLinkStoreKey,
2354
+ location: T,
2355
+ intent: ZLinkLocationWriteIntent,
2356
+ signal?: AbortSignal
2357
+ ): Promise<ZLinkLocationWriteResult> {
2358
+ const leaseKey = ownerKey(location.ownerId);
2359
+ const [lease, current] = await Promise.all([
2360
+ this.provider.read(leaseKey, signal),
2361
+ this.provider.read(rowKey, signal)
2362
+ ]);
2363
+ if (lease.kind === 'missing') return rejected(lease.storeNow);
2364
+ if (liveOwnerLeaseGeneration(lease) !== locationOwnerGeneration(location)) {
2365
+ return rejected(lease.value.storeNow);
2366
+ }
2367
+
2368
+ let generation = 1n;
2369
+ let rowCondition: ZLinkStoreCondition = { kind: 'missing', key: rowKey };
2370
+ if (current.kind === 'found') {
2371
+ const record = decodeJson<DescriptorRecord<T>>(current.value.bytes);
2372
+ generation = BigInt(record.generation);
2373
+ const stored = record.descriptor;
2374
+ if (intent === 2) {
2375
+ if (stored.ownerId !== location.ownerId
2376
+ || locationOwnerGeneration(stored) !== locationOwnerGeneration(location)) {
2377
+ return {
2378
+ status: WriteStatus.IgnoredStale,
2379
+ generation,
2380
+ updatedAt: current.value.storeNow
2381
+ };
2382
+ }
2383
+ } else {
2384
+ const currentLease = await this.provider.read(ownerKey(stored.ownerId), signal);
2385
+ const currentLeaseGeneration = liveOwnerLeaseGeneration(currentLease);
2386
+ const takeover = canTakeOverStoredLocation(
2387
+ intent,
2388
+ stored.ownerId,
2389
+ locationOwnerGeneration(stored),
2390
+ location.ownerId,
2391
+ locationOwnerGeneration(location),
2392
+ currentLeaseGeneration
2393
+ );
2394
+ if (!takeover) {
2395
+ return {
2396
+ status: WriteStatus.RejectedConflict,
2397
+ generation,
2398
+ updatedAt: current.value.storeNow
2399
+ };
2400
+ }
2401
+ generation += 1n;
2402
+ }
2403
+ rowCondition = { kind: 'version', key: rowKey, expected: current.value.version };
2404
+ } else if (intent === 2) {
2405
+ return rejected(lease.value.storeNow);
2406
+ }
2407
+
2408
+ const result = await this.provider.write({
2409
+ conditions: [
2410
+ { kind: 'version', key: leaseKey, expected: lease.value.version },
2411
+ rowCondition
2412
+ ],
2413
+ mutations: [{
2414
+ kind: 'put',
2415
+ key: rowKey,
2416
+ bytes: encodeJson<DescriptorRecord<T>>({
2417
+ generation: generation.toString(),
2418
+ descriptor: location
2419
+ })
2420
+ }]
2421
+ }, signal);
2422
+ return result.kind === 'applied'
2423
+ ? { status: WriteStatus.Stored, generation, updatedAt: result.storeNow }
2424
+ : rejected(result.storeNow);
2425
+ }
2426
+
2427
+ private async removeOwnedLocation(
2428
+ rowKey: ZLinkStoreKey,
2429
+ owner: ZLinkLocationOwnerToken,
2430
+ signal?: AbortSignal
2431
+ ): Promise<ZLinkLocationWriteStatus> {
2432
+ const current = await this.provider.read(rowKey, signal);
2433
+ if (current.kind === 'missing') return WriteStatus.IgnoredStale;
2434
+ const record = decodeJson<DescriptorRecord<LeaseOwnedLocation>>(current.value.bytes);
2435
+ const descriptor = record.descriptor as unknown as {
2436
+ readonly ownerId: string;
2437
+ readonly leaseGeneration?: bigint;
2438
+ };
2439
+ const leaseGeneration = descriptor.leaseGeneration ?? BigInt(record.generation);
2440
+ if (descriptor.ownerId !== owner.ownerId
2441
+ || leaseGeneration !== owner.leaseGeneration) {
2442
+ return WriteStatus.IgnoredStale;
2443
+ }
2444
+ const result = await this.provider.write({
2445
+ conditions: [{ kind: 'version', key: rowKey, expected: current.value.version }],
2446
+ mutations: [{ kind: 'delete', key: rowKey }]
2447
+ }, signal);
2448
+ return result.kind === 'applied' ? WriteStatus.Stored : WriteStatus.IgnoredStale;
2449
+ }
2450
+
2451
+ private async readOwnedLocation<T extends StoredLocation>(
2452
+ rowKey: ZLinkStoreKey,
2453
+ signal?: AbortSignal
2454
+ ): Promise<T | undefined> {
2455
+ const result = await this.provider.read(rowKey, signal);
2456
+ return result.kind === 'missing'
2457
+ ? undefined
2458
+ : decodeJson<DescriptorRecord<T>>(result.value.bytes).descriptor;
2459
+ }
2460
+
2461
+ private async listOwnedLocations<T extends StoredLocation>(
2462
+ prefix: string,
2463
+ page: ZLinkPageRequest,
2464
+ revive: (value: T) => T,
2465
+ matches: (value: T) => boolean,
2466
+ signal?: AbortSignal
2467
+ ): Promise<ZLinkLocationPage<T>> {
2468
+ const requested = page.pageSize ?? 100;
2469
+ let cursor = page.continuationToken === undefined
2470
+ ? undefined
2471
+ : ({ value: page.continuationToken } as ZLinkStoreScanCursor);
2472
+ const items: T[] = [];
2473
+ do {
2474
+ const result = await this.provider.scan({
2475
+ prefix,
2476
+ cursor,
2477
+ limit: requested
2478
+ }, signal);
2479
+ if (result.kind === 'expired') {
2480
+ throw new Error('Location Store scan snapshot expired.');
2481
+ }
2482
+ for (const item of result.value.items) {
2483
+ const value = revive(
2484
+ decodeJson<DescriptorRecord<T>>(item.value.bytes).descriptor);
2485
+ if (matches(value)) items.push(value);
2486
+ if (items.length === requested) {
2487
+ return {
2488
+ items,
2489
+ continuationToken: result.value.nextCursor?.value
2490
+ };
2491
+ }
2492
+ }
2493
+ cursor = result.value.nextCursor;
2494
+ } while (cursor !== undefined);
2495
+ return { items };
2496
+ }
2497
+
2498
+ private async projectAuthority(
2499
+ record: AuthorityRecord,
2500
+ version: ZLinkStoreVersion,
2501
+ storeNow: Date,
2502
+ signal?: AbortSignal
2503
+ ): Promise<ZLinkAuthoritySnapshot> {
2504
+ const marker = record.aggregate;
2505
+ if (marker === undefined) {
2506
+ return authoritySnapshot(
2507
+ record.snapshot,
2508
+ record.visibleStoreVersion === undefined
2509
+ ? version
2510
+ : ({ value: record.visibleStoreVersion } as ZLinkStoreVersion),
2511
+ storeNow
2512
+ );
2513
+ }
2514
+ const aggregateRead = await this.provider.read(
2515
+ aggregateKey(aggregateFence(
2516
+ aggregateId(marker.aggregateId),
2517
+ marker.aggregateGeneration
2518
+ )),
2519
+ signal
2520
+ );
2521
+ if (aggregateRead.kind === 'missing') {
2522
+ throw new Error('Aggregate participant references a missing authority record.');
2523
+ }
2524
+ const aggregate = decodeJson<AggregateRecord>(aggregateRead.value.bytes);
2525
+ if (aggregate.state !== 'committed') {
2526
+ return authoritySnapshot(
2527
+ record.snapshot,
2528
+ { value: marker.expectedStoreVersion } as ZLinkStoreVersion,
2529
+ storeNow
2530
+ );
2531
+ }
2532
+ const fence = aggregateFence(
2533
+ aggregateId(marker.aggregateId),
2534
+ marker.aggregateGeneration
2535
+ );
2536
+ const payload = await requireProviderBytes(
2537
+ this.provider,
2538
+ aggregateParticipantPayloadKey(fence, marker.index),
2539
+ signal
2540
+ );
2541
+ if (sha256Hex(payload) !== marker.authorityPayloadSha256) {
2542
+ throw new Error('Committed aggregate participant payload checksum is invalid.');
2543
+ }
2544
+ const projected: StoredAuthoritySnapshot = marker.ownerTransition === 'newOwner'
2545
+ ? {
2546
+ payload: Buffer.from(payload),
2547
+ objectGeneration: record.snapshot.objectGeneration,
2548
+ authorityOwnerGeneration: marker.targetAuthorityOwnerGeneration,
2549
+ ownerId: aggregate.targetOwner.ownerId,
2550
+ ownerLeaseGeneration: aggregate.targetOwner.leaseGeneration,
2551
+ allocation: {
2552
+ ...record.snapshot.allocation,
2553
+ descriptor: { ...aggregate.targetDescriptor },
2554
+ descriptorLifecycleGeneration:
2555
+ aggregate.targetDescriptorLifecycleGeneration,
2556
+ capacity: cloneCapacity(record.snapshot.allocation.capacity)
2557
+ }
2558
+ }
2559
+ : {
2560
+ ...record.snapshot,
2561
+ payload: Buffer.from(payload)
2562
+ };
2563
+ return authoritySnapshot(projected, version, storeNow);
2564
+ }
2565
+
2566
+ private async normalizeCommittedAggregate(
2567
+ fence: ZLinkAggregateFence,
2568
+ aggregate: AggregateRecord,
2569
+ signal?: AbortSignal
2570
+ ): Promise<void> {
2571
+ const entries = await this.aggregateInventory.read(
2572
+ fence,
2573
+ Buffer.from(aggregate.inventoryDigest),
2574
+ signal
2575
+ );
2576
+ await parallelForEach(entries, 64, async (entry, index) => {
2577
+ const rowKey = authorityKey(entry.authorityKey);
2578
+ for (;;) {
2579
+ const current = await this.provider.read(rowKey, signal);
2580
+ if (current.kind === 'missing') {
2581
+ throw new Error('Committed aggregate participant authority is missing.');
2582
+ }
2583
+ const record = decodeAuthorityRecord(current.value.bytes);
2584
+ if (record.aggregate === undefined) {
2585
+ if (
2586
+ !Buffer.from(record.snapshot.payload).equals(
2587
+ Buffer.from(await requireProviderBytes(
2588
+ this.provider,
2589
+ aggregateParticipantPayloadKey(fence, index),
2590
+ signal
2591
+ ))
2592
+ )
2593
+ ) {
2594
+ throw new Error('Normalized aggregate participant payload changed.');
2595
+ }
2596
+ return;
2597
+ }
2598
+ if (!sameAggregateMarkerEntry(record.aggregate, fence, index, entry)) {
2599
+ throw new Error('Committed aggregate participant fence changed.');
2600
+ }
2601
+ const payload = await requireProviderBytes(
2602
+ this.provider,
2603
+ aggregateParticipantPayloadKey(fence, index),
2604
+ signal
2605
+ );
2606
+ if (sha256Hex(payload) !== entry.authorityPayloadSha256) {
2607
+ throw new Error('Committed aggregate participant payload checksum is invalid.');
2608
+ }
2609
+ const snapshot: StoredAuthoritySnapshot =
2610
+ record.aggregate.ownerTransition === 'newOwner'
2611
+ ? {
2612
+ payload: Buffer.from(payload),
2613
+ objectGeneration: record.snapshot.objectGeneration,
2614
+ authorityOwnerGeneration:
2615
+ record.aggregate.targetAuthorityOwnerGeneration,
2616
+ ownerId: aggregate.targetOwner.ownerId,
2617
+ ownerLeaseGeneration: aggregate.targetOwner.leaseGeneration,
2618
+ allocation: {
2619
+ ...record.snapshot.allocation,
2620
+ descriptor: { ...aggregate.targetDescriptor },
2621
+ descriptorLifecycleGeneration:
2622
+ aggregate.targetDescriptorLifecycleGeneration,
2623
+ capacity: cloneCapacity(record.snapshot.allocation.capacity)
2624
+ }
2625
+ }
2626
+ : {
2627
+ ...record.snapshot,
2628
+ payload: Buffer.from(payload)
2629
+ };
2630
+ const normalized: AuthorityRecord = {
2631
+ ...record,
2632
+ snapshot,
2633
+ aggregate: undefined,
2634
+ visibleStoreVersion: undefined
2635
+ };
2636
+ const result = await this.provider.write({
2637
+ conditions: [{
2638
+ kind: 'version',
2639
+ key: rowKey,
2640
+ expected: current.value.version
2641
+ }],
2642
+ mutations: [{
2643
+ kind: 'put',
2644
+ key: rowKey,
2645
+ bytes: encodeAuthorityRecord(normalized)
2646
+ }]
2647
+ }, signal);
2648
+ if (result.kind === 'applied') return;
2649
+ }
2650
+ });
2651
+ }
2652
+
2653
+ private async putImmutable(
2654
+ key: ZLinkStoreKey,
2655
+ bytes: Uint8Array,
2656
+ signal?: AbortSignal
2657
+ ): Promise<void> {
2658
+ if (bytes.byteLength > 1024 * 1024) {
2659
+ throw new RangeError('Aggregate participant staging value exceeds 1 MiB.');
2660
+ }
2661
+ const result = await this.provider.write({
2662
+ conditions: [{ kind: 'missing', key }],
2663
+ mutations: [{ kind: 'put', key, bytes: Buffer.from(bytes) }]
2664
+ }, signal);
2665
+ if (result.kind === 'applied') return;
2666
+ const current = await this.provider.read(key, signal);
2667
+ if (
2668
+ current.kind !== 'found'
2669
+ || !Buffer.from(current.value.bytes).equals(Buffer.from(bytes))
2670
+ ) {
2671
+ throw new Error(`Immutable aggregate participant value changed: ${key.value}.`);
2672
+ }
2673
+ }
2674
+
2675
+ private async abortAggregateStaging(
2676
+ fence: ZLinkAggregateFence,
2677
+ signal?: AbortSignal
2678
+ ): Promise<void> {
2679
+ const key = aggregateKey(fence);
2680
+ for (;;) {
2681
+ const current = await this.provider.read(key, signal);
2682
+ if (current.kind === 'missing') return;
2683
+ const record = decodeJson<AggregateRecord>(current.value.bytes);
2684
+ if (record.state === 'aborted') {
2685
+ await this.clearAggregateMarkersByScan(fence, signal);
2686
+ return;
2687
+ }
2688
+ if (record.state !== 'staging') return;
2689
+ const result = await this.provider.write({
2690
+ conditions: [{ kind: 'version', key, expected: current.value.version }],
2691
+ mutations: [{
2692
+ kind: 'put',
2693
+ key,
2694
+ bytes: encodeJson({ ...record, state: 'aborted' } satisfies AggregateRecord)
2695
+ }]
2696
+ }, signal);
2697
+ if (result.kind === 'applied') {
2698
+ await this.clearAggregateMarkersByScan(fence, signal);
2699
+ return;
2700
+ }
2701
+ }
2702
+ }
2703
+
2704
+ private async clearAggregateMarkers(
2705
+ fence: ZLinkAggregateFence,
2706
+ installed: readonly {
2707
+ readonly key: ZLinkStoreKey;
2708
+ readonly expectedStoreVersion: string;
2709
+ }[],
2710
+ signal?: AbortSignal
2711
+ ): Promise<void> {
2712
+ await parallelForEach(installed, 64, async value => {
2713
+ await this.clearAggregateMarker(fence, value.key, signal);
2714
+ });
2715
+ }
2716
+
2717
+ private async clearAggregateMarkersByScan(
2718
+ fence: ZLinkAggregateFence,
2719
+ signal?: AbortSignal
2720
+ ): Promise<void> {
2721
+ let cursor: ZLinkStoreScanCursor | undefined;
2722
+ for (;;) {
2723
+ const result = await this.provider.scan({
2724
+ prefix: AUTHORITY_PREIMAGE_PREFIX,
2725
+ cursor,
2726
+ limit: 1_000
2727
+ }, signal);
2728
+ if (result.kind === 'expired') {
2729
+ cursor = undefined;
2730
+ continue;
2731
+ }
2732
+ const matching = result.value.items.filter(item => {
2733
+ const record = decodeAuthorityRecord(item.value.bytes);
2734
+ return record.aggregate?.aggregateId === fence.aggregateId.value
2735
+ && record.aggregate.aggregateGeneration === fence.aggregateGeneration;
2736
+ });
2737
+ await parallelForEach(matching, 64, async item => {
2738
+ await this.clearAggregateMarker(fence, item.key, signal);
2739
+ });
2740
+ if (result.value.nextCursor === undefined) return;
2741
+ cursor = result.value.nextCursor;
2742
+ }
2743
+ }
2744
+
2745
+ private async clearAggregateMarker(
2746
+ fence: ZLinkAggregateFence,
2747
+ key: ZLinkStoreKey,
2748
+ signal?: AbortSignal
2749
+ ): Promise<void> {
2750
+ for (;;) {
2751
+ const current = await this.provider.read(key, signal);
2752
+ if (current.kind === 'missing') return;
2753
+ const record = decodeAuthorityRecord(current.value.bytes);
2754
+ if (
2755
+ record.aggregate === undefined
2756
+ || record.aggregate.aggregateId !== fence.aggregateId.value
2757
+ || record.aggregate.aggregateGeneration !== fence.aggregateGeneration
2758
+ ) {
2759
+ return;
2760
+ }
2761
+ const result = await this.provider.write({
2762
+ conditions: [{ kind: 'version', key, expected: current.value.version }],
2763
+ mutations: [{
2764
+ kind: 'put',
2765
+ key,
2766
+ bytes: encodeAuthorityRecord({ ...record, aggregate: undefined } satisfies AuthorityRecord)
2767
+ }]
2768
+ }, signal);
2769
+ if (result.kind === 'applied') return;
2770
+ }
2771
+ }
2772
+ }
2773
+
2774
+ const AMBIGUOUS_WRITE_RECONCILIATION_TIMEOUT_MS = 5_000;
2775
+
2776
+ /**
2777
+ * Keeps provider failures private while preserving the opaque Store contract.
2778
+ *
2779
+ * A write response can be lost after the provider applied the atomic batch.
2780
+ * The Framework confirms every mutation by an independent exact read. A put
2781
+ * must retain the requested bytes and a version different from the conditioned
2782
+ * version; a delete must remain absent. Any mismatch is a normal conflict, so
2783
+ * the domain repository can reread its authoritative record and classify the
2784
+ * operation without exposing a provider-specific retry API.
2785
+ */
2786
+ class AmbiguousWriteReconcilingLocationStore implements ZLinkLocationStore {
2787
+ constructor(private readonly inner: ZLinkLocationStore) {}
2788
+
2789
+ read(key: ZLinkStoreKey, signal?: AbortSignal): Promise<ZLinkStoreReadResult> {
2790
+ return this.inner.read(key, signal);
2791
+ }
2792
+
2793
+ scan(
2794
+ request: ZLinkStoreScanRequest,
2795
+ signal?: AbortSignal
2796
+ ): Promise<ZLinkStoreScanResult> {
2797
+ return this.inner.scan(request, signal);
2798
+ }
2799
+
2800
+ async write(
2801
+ request: ZLinkStoreWriteRequest,
2802
+ signal?: AbortSignal
2803
+ ): Promise<ZLinkStoreWriteResult> {
2804
+ try {
2805
+ return await this.inner.write(request, signal);
2806
+ } catch (failure) {
2807
+ try {
2808
+ return await this.reconcile(request);
2809
+ } catch {
2810
+ throw failure;
2811
+ }
2812
+ }
2813
+ }
2814
+
2815
+ private async reconcile(
2816
+ request: ZLinkStoreWriteRequest
2817
+ ): Promise<ZLinkStoreWriteResult> {
2818
+ if (request.mutations.length === 0) {
2819
+ throw new Error('Cannot reconcile an opaque Store write without mutations.');
2820
+ }
2821
+ const reconciliationSignal = AbortSignal.timeout(
2822
+ AMBIGUOUS_WRITE_RECONCILIATION_TIMEOUT_MS
2823
+ );
2824
+ const reads = await Promise.all(request.mutations.map(
2825
+ mutation => this.inner.read(mutation.key, reconciliationSignal)
2826
+ ));
2827
+ const putVersions: Array<{
2828
+ readonly key: ZLinkStoreKey;
2829
+ readonly version: ZLinkStoreVersion;
2830
+ }> = [];
2831
+ let storeNow = new Date(0);
2832
+
2833
+ for (let index = 0; index < request.mutations.length; index += 1) {
2834
+ const mutation = request.mutations[index];
2835
+ const read = reads[index];
2836
+ storeNow = read.kind === 'found'
2837
+ ? latestDate(storeNow, read.value.storeNow)
2838
+ : latestDate(storeNow, read.storeNow);
2839
+
2840
+ if (mutation.kind === 'delete') {
2841
+ if (read.kind !== 'missing') return { kind: 'conflict', storeNow };
2842
+ continue;
2843
+ }
2844
+ if (read.kind !== 'found'
2845
+ || !Buffer.from(read.value.bytes).equals(Buffer.from(mutation.bytes))
2846
+ || !versionAdvanced(request.conditions, mutation.key, read.value.version)) {
2847
+ return { kind: 'conflict', storeNow };
2848
+ }
2849
+ putVersions.push({ key: mutation.key, version: read.value.version });
2850
+ }
2851
+
2852
+ return { kind: 'applied', putVersions, storeNow };
2853
+ }
2854
+ }
2855
+
2856
+ function versionAdvanced(
2857
+ conditions: readonly ZLinkStoreCondition[],
2858
+ key: ZLinkStoreKey,
2859
+ current: ZLinkStoreVersion
2860
+ ): boolean {
2861
+ const condition = conditions.find(candidate => candidate.key.value === key.value);
2862
+ return condition?.kind !== 'version' || condition.expected.value !== current.value;
2863
+ }
2864
+
2865
+ function latestDate(left: Date, right: Date): Date {
2866
+ return left.getTime() >= right.getTime() ? left : right;
2867
+ }
2868
+
2869
+ type OwnedDescriptor =
2870
+ | ZLinkMeshNodeDescriptor
2871
+ | ZLinkClientServerServerDescriptor
2872
+ | ZLinkFanoutPublisherDescriptor;
2873
+
2874
+ type LeaseOwnedLocation = ZLinkSpotLocation | ZLinkActorLocation;
2875
+ type StoredLocation = LeaseOwnedLocation | ZLinkRouteLocation;
2876
+ type OwnedStoreRecord = OwnedDescriptor | StoredLocation;
2877
+
2878
+ function validateProviderAggregateRequest(request: ZLinkAggregatePrepareRequest): void {
2879
+ requireText(request.aggregateId.value, 'aggregate ID');
2880
+ if (request.aggregateGeneration < 1n || request.participants.length < 1) {
2881
+ throw new RangeError('Aggregate generation and participant count are invalid.');
2882
+ }
2883
+ if (request.inventoryDigest.byteLength !== 32) {
2884
+ throw new TypeError('Aggregate inventory digest must contain 32 bytes.');
2885
+ }
2886
+ const keys = request.participants.map(value => value.authorityKey.value);
2887
+ if (
2888
+ new Set(keys).size !== keys.length
2889
+ || keys.some((key, index) => index > 0 && keys[index - 1]!.localeCompare(key) >= 0)
2890
+ ) {
2891
+ throw new TypeError('Aggregate participants must be unique and canonically sorted.');
2892
+ }
2893
+ for (const participant of request.participants) {
2894
+ requireText(participant.authorityKey.value, 'aggregate authority key');
2895
+ requireText(participant.expectedStoreVersion.value, 'aggregate expected Store version');
2896
+ if (
2897
+ participant.authorityPayload.byteLength > 1024 * 1024
2898
+ || participant.membershipMutation.byteLength > 1024 * 1024
2899
+ ) {
2900
+ throw new RangeError('Aggregate participant value exceeds 1 MiB.');
2901
+ }
2902
+ }
2903
+ }
2904
+
2905
+ function validateAggregateFence(fence: ZLinkAggregateFence): void {
2906
+ requireText(fence.aggregateId.value, 'aggregate ID');
2907
+ if (fence.aggregateGeneration < 1n) {
2908
+ throw new RangeError('Aggregate generation must be positive.');
2909
+ }
2910
+ }
2911
+
2912
+ function aggregateRecord(
2913
+ request: ZLinkAggregatePrepareRequest,
2914
+ requestFingerprint: string,
2915
+ state: AggregateRecord['state']
2916
+ ): AggregateRecord {
2917
+ return {
2918
+ state,
2919
+ requestFingerprint,
2920
+ participantCount: request.participants.length,
2921
+ inventoryDigest: Buffer.from(request.inventoryDigest),
2922
+ targetDescriptor: { ...request.targetDescriptor },
2923
+ targetDescriptorLifecycleGeneration:
2924
+ request.targetDescriptorLifecycleGeneration,
2925
+ capacity: cloneCapacity(request.capacity),
2926
+ targetOwner: { ...request.targetOwner }
2927
+ };
2928
+ }
2929
+
2930
+ function reconcileAggregatePrepare(
2931
+ record: AggregateRecord,
2932
+ fingerprint: string,
2933
+ fence: ZLinkAggregateFence
2934
+ ): ZLinkAggregatePrepareResult | undefined {
2935
+ if (record.requestFingerprint !== fingerprint) return { kind: 'conflict' };
2936
+ if (record.state === 'prepared') return { kind: 'alreadyPrepared', fence };
2937
+ if (record.state === 'committed') return { kind: 'stale' };
2938
+ if (record.state === 'aborted') return { kind: 'conflict' };
2939
+ return undefined;
2940
+ }
2941
+
2942
+ function sameAggregateMarker(
2943
+ marker: AggregateParticipantFenceRecord | undefined,
2944
+ fence: ZLinkAggregateFence,
2945
+ index: number,
2946
+ participant: ZLinkAggregatePrepareRequest['participants'][number]
2947
+ ): boolean {
2948
+ return marker !== undefined
2949
+ && marker.aggregateId === fence.aggregateId.value
2950
+ && marker.aggregateGeneration === fence.aggregateGeneration
2951
+ && marker.index === index
2952
+ && marker.expectedStoreVersion === participant.expectedStoreVersion.value
2953
+ && marker.ownerTransition === participant.ownerTransition;
2954
+ }
2955
+
2956
+ function sameAggregateMarkerEntry(
2957
+ marker: AggregateParticipantFenceRecord | undefined,
2958
+ fence: ZLinkAggregateFence,
2959
+ index: number,
2960
+ entry: {
2961
+ readonly expectedStoreVersion: string;
2962
+ readonly ownerTransition: 'preserve' | 'newOwner';
2963
+ readonly authorityPayloadSha256: string;
2964
+ readonly membershipMutationSha256: string;
2965
+ }
2966
+ ): boolean {
2967
+ return marker !== undefined
2968
+ && marker.aggregateId === fence.aggregateId.value
2969
+ && marker.aggregateGeneration === fence.aggregateGeneration
2970
+ && marker.index === index
2971
+ && marker.expectedStoreVersion === entry.expectedStoreVersion
2972
+ && marker.ownerTransition === entry.ownerTransition
2973
+ && marker.authorityPayloadSha256 === entry.authorityPayloadSha256
2974
+ && marker.membershipMutationSha256 === entry.membershipMutationSha256;
2975
+ }
2976
+
2977
+ function aggregateTarget(
2978
+ request: ZLinkAggregatePrepareRequest
2979
+ ): ZLinkObjectCommitRequest['target'] {
2980
+ return {
2981
+ meshName: request.targetDescriptor.meshName,
2982
+ nodeRid: request.targetDescriptor.rid,
2983
+ nodeLifecycleGeneration: request.targetDescriptorLifecycleGeneration,
2984
+ owner: { ...request.targetOwner }
2985
+ };
2986
+ }
2987
+
2988
+ function aggregateTargetFromRecord(
2989
+ record: AggregateRecord
2990
+ ): ZLinkObjectCommitRequest['target'] {
2991
+ return {
2992
+ meshName: record.targetDescriptor.meshName,
2993
+ nodeRid: record.targetDescriptor.rid,
2994
+ nodeLifecycleGeneration: record.targetDescriptorLifecycleGeneration,
2995
+ owner: { ...record.targetOwner }
2996
+ };
2997
+ }
2998
+
2999
+ function addCapacityVector(
3000
+ left: ZLinkCapacityVector,
3001
+ right: ZLinkCapacityVector
3002
+ ): ZLinkCapacityVector {
3003
+ let spotType = left.spotType;
3004
+ if (right.spotType !== undefined) {
3005
+ if (
3006
+ spotType !== undefined
3007
+ && (
3008
+ spotType.objectKind !== right.spotType.objectKind
3009
+ || spotType.stableType !== right.spotType.stableType
3010
+ )
3011
+ ) {
3012
+ throw new TypeError('Aggregate capacity contains more than one Spot type.');
3013
+ }
3014
+ spotType = {
3015
+ ...right.spotType,
3016
+ count: (spotType?.count ?? 0) + right.spotType.count
3017
+ };
3018
+ }
3019
+ return {
3020
+ actors: left.actors + right.actors,
3021
+ spots: left.spots + right.spots,
3022
+ ...(spotType === undefined ? {} : { spotType })
3023
+ };
3024
+ }
3025
+
3026
+ async function requireProviderBytes(
3027
+ provider: ZLinkLocationStore,
3028
+ key: ZLinkStoreKey,
3029
+ signal?: AbortSignal
3030
+ ): Promise<Uint8Array> {
3031
+ const read = await provider.read(key, signal);
3032
+ if (read.kind === 'missing') {
3033
+ throw new Error(`Aggregate participant value is missing: ${key.value}.`);
3034
+ }
3035
+ return read.value.bytes;
3036
+ }
3037
+
3038
+ async function parallelForEach<T>(
3039
+ values: readonly T[],
3040
+ concurrency: number,
3041
+ operation: (value: T, index: number) => Promise<void>
3042
+ ): Promise<void> {
3043
+ let next = 0;
3044
+ await Promise.all(Array.from(
3045
+ { length: Math.min(concurrency, values.length) },
3046
+ async () => {
3047
+ while (next < values.length) {
3048
+ const index = next++;
3049
+ await operation(values[index]!, index);
3050
+ }
3051
+ }
3052
+ ));
3053
+ }
3054
+
3055
+ async function waitForAggregateCommitRetry(
3056
+ retryAttempt: number,
3057
+ deadlineAtMs: number,
3058
+ signal?: AbortSignal
3059
+ ): Promise<void> {
3060
+ signal?.throwIfAborted();
3061
+ const remainingMs = deadlineAtMs - performance.now();
3062
+ if (remainingMs <= 0) return;
3063
+ const exponentialMs = Math.min(100, 2 << Math.min(retryAttempt, 5));
3064
+ const delayMs = Math.min(
3065
+ remainingMs,
3066
+ exponentialMs + Math.floor(Math.random() * (exponentialMs + 1))
3067
+ );
3068
+ await new Promise<void>((resolve, reject) => {
3069
+ let timer: ReturnType<typeof setTimeout> | undefined;
3070
+ const aborted = () => {
3071
+ if (timer !== undefined) clearTimeout(timer);
3072
+ reject(signal?.reason ?? new Error('Aggregate commit was aborted.'));
3073
+ };
3074
+ signal?.addEventListener('abort', aborted, { once: true });
3075
+ timer = setTimeout(() => {
3076
+ signal?.removeEventListener('abort', aborted);
3077
+ resolve();
3078
+ }, delayMs);
3079
+ });
3080
+ }
3081
+
3082
+ function sha256Hex(bytes: Uint8Array): string {
3083
+ return createHash('sha256').update(bytes).digest('hex');
3084
+ }
3085
+
3086
+ // Logical key preimages (21-location-runtime.md#2.4). Values are joined with
3087
+ // literal NUL bytes -- the same scheme the opaque record store hashes with
3088
+ // SHA-256 to derive the Redis key -- so a runtime in one language can read a
3089
+ // record another language wrote. Not used for framework-internal-only rows
3090
+ // (aggregate/capacity/creation-terminal/spot/actor/route), which stay on the
3091
+ // legacy PREFIX scheme since they aren't part of the public opaque contract.
3092
+ function ownerKey(ownerId: string) {
3093
+ return storeKey(`owner-lease\0${requireNoNul(ownerId, 'OwnerId')}`);
3094
+ }
3095
+
3096
+ const AUTHORITY_PREIMAGE_PREFIX = 'authority\0';
3097
+
3098
+ function authorityKey(value: string) {
3099
+ return storeKey(authorityPreimage(value));
3100
+ }
3101
+
3102
+ function authorityPreimage(value: string): string {
3103
+ const decoded = decodeAuthorityKey({ value } as ZLinkAuthorityKey);
3104
+ // §2.3: Entry|User|Instance Spot kinds share one segment ("spot") -- one
3105
+ // Id has exactly one authority row regardless of spot kind.
3106
+ const segment = decoded.kind === 'actor' ? 'actor' : 'spot';
3107
+ return `${AUTHORITY_PREIMAGE_PREFIX}${segment}\0${requireNoNul(decoded.globalId, 'Authority Id')}`;
3108
+ }
3109
+
3110
+ // Reverses authorityPreimage(): recovers the framework-internal zla1-encoded
3111
+ // ZLinkAuthorityKey contract value from a scanned opaque record's logical
3112
+ // key. Used by the authority list/cleanup scans below, which see raw
3113
+ // preimages (authority\0actor\0{id} | authority\0spot\0{id}) and must hand
3114
+ // callers back the same encodeAuthorityKey() representation authorityKey()
3115
+ // was given.
3116
+ function authorityContractValueFromPreimage(logicalKey: string): string {
3117
+ if (!logicalKey.startsWith(AUTHORITY_PREIMAGE_PREFIX)) {
3118
+ throw new Error('Authority scan returned a non-authority logical key.');
3119
+ }
3120
+ const rest = logicalKey.slice(AUTHORITY_PREIMAGE_PREFIX.length);
3121
+ const separator = rest.indexOf('\0');
3122
+ if (separator < 0) throw new Error('Authority logical key preimage is malformed.');
3123
+ const segment = rest.slice(0, separator);
3124
+ const globalId = rest.slice(separator + 1);
3125
+ return encodeAuthorityKey(segment === 'actor' ? 'actor' : 'user_spot', globalId).value;
3126
+ }
3127
+
3128
+ function requireNoNul(value: string, name: string): string {
3129
+ if (value.includes('\0')) {
3130
+ throw new TypeError(`${name} must not contain a NUL byte.`);
3131
+ }
3132
+ return value;
3133
+ }
3134
+
3135
+ function authorityContractKey(value: string): ZLinkAuthorityKey {
3136
+ return { value } as ZLinkAuthorityKey;
3137
+ }
3138
+
3139
+ function aggregateId(value: string): ZLinkAggregateId {
3140
+ return { value } as ZLinkAggregateId;
3141
+ }
3142
+
3143
+ function aggregateFence(
3144
+ id: ZLinkAggregateId,
3145
+ generation: bigint
3146
+ ): ZLinkAggregateFence {
3147
+ return { aggregateId: id, aggregateGeneration: generation };
3148
+ }
3149
+
3150
+ function aggregateKey(fence: ZLinkAggregateFence): ZLinkStoreKey {
3151
+ return storeKey(
3152
+ `${PREFIX}aggregate:${encodeURIComponent(fence.aggregateId.value)}:${fence.aggregateGeneration}`
3153
+ );
3154
+ }
3155
+
3156
+ function aggregateParticipantPayloadKey(
3157
+ fence: ZLinkAggregateFence,
3158
+ index: number
3159
+ ): ZLinkStoreKey {
3160
+ return storeKey(
3161
+ `${PREFIX}aggregate-participant:${encodeURIComponent(fence.aggregateId.value)}:`
3162
+ + `${fence.aggregateGeneration}:${index}:authority`
3163
+ );
3164
+ }
3165
+
3166
+ function aggregateParticipantMembershipKey(
3167
+ fence: ZLinkAggregateFence,
3168
+ index: number
3169
+ ): ZLinkStoreKey {
3170
+ return storeKey(
3171
+ `${PREFIX}aggregate-participant:${encodeURIComponent(fence.aggregateId.value)}:`
3172
+ + `${fence.aggregateGeneration}:${index}:membership`
3173
+ );
3174
+ }
3175
+
3176
+ function capacityKey(meshName: string, nodeRid: string) {
3177
+ return storeKey(
3178
+ `${PREFIX}capacity:${encodeURIComponent(meshName)}:${encodeURIComponent(nodeRid)}`
3179
+ );
3180
+ }
3181
+
3182
+ function creationTerminalKey(operation: ZLinkCreationOperationIdentity) {
3183
+ validateCreationOperation(operation);
3184
+ return storeKey(`${PREFIX}creation-terminal:${[
3185
+ String(operation.sourceNodeRid),
3186
+ operation.sourceNodeGeneration.toString(),
3187
+ operation.operationId.high.toString(16).padStart(16, '0'),
3188
+ operation.operationId.low.toString(16).padStart(16, '0')
3189
+ ].map(encodeURIComponent).join(':')}`);
3190
+ }
3191
+
3192
+ function meshPrefix(meshName: string): string {
3193
+ return `mesh-node\0${requireNoNul(meshName, 'MeshName')}\0`;
3194
+ }
3195
+
3196
+ function meshKey(meshName: string, nodeRid: RoutingId) {
3197
+ return storeKey(`${meshPrefix(meshName)}${routingIdHexSegment(nodeRid)}`);
3198
+ }
3199
+
3200
+ function clientServerPrefix(channelName: string): string {
3201
+ return `client-server\0${requireNoNul(channelName, 'ChannelName')}\0`;
3202
+ }
3203
+
3204
+ function clientServerKey(channelName: string, serverRid: RoutingId) {
3205
+ return storeKey(`${clientServerPrefix(channelName)}${routingIdHexSegment(serverRid)}`);
3206
+ }
3207
+
3208
+ // {hex(RoutingId)}: lowercase hex of the RoutingId's raw bytes
3209
+ // (21-location-runtime.md#2.4).
3210
+ function routingIdHexSegment(rid: RoutingId): string {
3211
+ return encodeRoutingIdStorageHex(rid).toLowerCase();
3212
+ }
3213
+
3214
+ function fanoutPrefix(channelName: string): string {
3215
+ return `fanout-publisher\0${requireNoNul(channelName, 'ChannelName')}\0`;
3216
+ }
3217
+
3218
+ function fanoutKey(channelName: string, publisherRid: RoutingId) {
3219
+ return storeKey(`${fanoutPrefix(channelName)}${routingIdHexSegment(publisherRid)}`);
3220
+ }
3221
+
3222
+ function spotKey(meshName: string, spotId: string) {
3223
+ return storeKey(
3224
+ `${PREFIX}spot:${encodeURIComponent(meshName)}:${encodeURIComponent(spotId)}`);
3225
+ }
3226
+
3227
+ function actorKey(meshName: string, actorId: string) {
3228
+ return storeKey(
3229
+ `${PREFIX}actor:${encodeURIComponent(meshName)}:${encodeURIComponent(actorId)}`);
3230
+ }
3231
+
3232
+ function routeKey(routeKind: string, value: string) {
3233
+ return storeKey(
3234
+ `${PREFIX}route:${encodeURIComponent(routeKind)}:${encodeURIComponent(value)}`);
3235
+ }
3236
+
3237
+ function encodeText(value: string): Uint8Array {
3238
+ return Buffer.from(value, 'utf8');
3239
+ }
3240
+
3241
+ function decodeText(value: Uint8Array): string {
3242
+ return Buffer.from(value).toString('utf8');
3243
+ }
3244
+
3245
+ /** Counter rows are bare, canonical decimal next-to-issue values. */
3246
+ function counterNextValue(counter: ZLinkStoreReadResult): bigint {
3247
+ if (counter.kind === 'missing') return 1n;
3248
+ const text = decodeText(counter.value.bytes);
3249
+ if (!/^[1-9][0-9]*$/.test(text)) {
3250
+ throw new TypeError('Location Store counter is not canonical decimal.');
3251
+ }
3252
+ const value = BigInt(text);
3253
+ if (value > MAX_GENERATION) {
3254
+ throw new RangeError('Location Store counter is outside its valid range.');
3255
+ }
3256
+ return value;
3257
+ }
3258
+
3259
+ function encodeJson<T>(value: T): Uint8Array {
3260
+ return Buffer.from(JSON.stringify(value, (key, candidate) => {
3261
+ if (typeof candidate === 'bigint') return { $bigint: candidate.toString() };
3262
+ if (candidate instanceof Uint8Array) {
3263
+ return { $bytes: Buffer.from(candidate).toString('base64') };
3264
+ }
3265
+ if (
3266
+ key === 'spotTypes'
3267
+ && candidate !== null
3268
+ && typeof candidate === 'object'
3269
+ && !Array.isArray(candidate)
3270
+ ) {
3271
+ return Object.fromEntries(
3272
+ Object.entries(candidate as Record<string, unknown>)
3273
+ .sort(([left], [right]) => compareUtf16Ordinal(left, right))
3274
+ );
3275
+ }
3276
+ return candidate;
3277
+ }), 'utf8');
3278
+ }
3279
+
3280
+ function compareUtf16Ordinal(left: string, right: string): number {
3281
+ return left < right ? -1 : left > right ? 1 : 0;
3282
+ }
3283
+
3284
+ function decodeJson<T>(value: Uint8Array): T {
3285
+ return JSON.parse(decodeText(value), (_key, candidate) => {
3286
+ if (candidate !== null
3287
+ && typeof candidate === 'object'
3288
+ && Object.keys(candidate).length === 1
3289
+ && typeof candidate.$bigint === 'string') {
3290
+ return BigInt(candidate.$bigint);
3291
+ }
3292
+ if (candidate !== null
3293
+ && typeof candidate === 'object'
3294
+ && Object.keys(candidate).length === 1
3295
+ && typeof candidate.$bytes === 'string') {
3296
+ return Buffer.from(candidate.$bytes, 'base64');
3297
+ }
3298
+ return candidate;
3299
+ }) as T;
3300
+ }
3301
+
3302
+ function requireRecordVersion(value: unknown, kind: string): void {
3303
+ if (value === null || typeof value !== 'object'
3304
+ || (value as { recordVersion?: unknown }).recordVersion !== 1) {
3305
+ throw new Error(`Location Store ${kind} record has an unrecognized recordVersion.`);
3306
+ }
3307
+ }
3308
+
3309
+ function canonicalize(value: unknown): unknown {
3310
+ if (typeof value === 'bigint') return value.toString();
3311
+ if (value instanceof Uint8Array) return Buffer.from(value).toString('base64');
3312
+ if (value instanceof Date) return value.toISOString();
3313
+ if (Array.isArray(value)) return value.map(canonicalize);
3314
+ if (value !== null && typeof value === 'object') {
3315
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, canonicalize(item)]));
3316
+ }
3317
+ return value;
3318
+ }
3319
+
3320
+ function reviveCanonical(value: unknown, key = ''): unknown {
3321
+ const generationKeys = new Set([
3322
+ 'generation', 'leaseGeneration', 'ownerLeaseGeneration', 'objectGeneration',
3323
+ 'authorityOwnerGeneration', 'aggregateGeneration', 'lifecycleGeneration', 'descriptorRevision',
3324
+ 'nodeGeneration', 'applicationVersion', 'requestEncodedSize'
3325
+ ]);
3326
+ if (typeof value === 'string' && generationKeys.has(key)) return BigInt(value);
3327
+ if (Array.isArray(value)) return value.map(item => reviveCanonical(item));
3328
+ if (value !== null && typeof value === 'object') {
3329
+ return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, reviveCanonical(item, name)]));
3330
+ }
3331
+ return value;
3332
+ }
3333
+
3334
+ function decodeOwnerRecord(bytes: Uint8Array): OwnerRecord {
3335
+ const record = decodeJson<OwnerRecord>(bytes);
3336
+ requireRecordVersion(record, 'owner lease');
3337
+ return record;
3338
+ }
3339
+
3340
+ function encodeOwnerRecord(ownerId: string, leaseGeneration: bigint): Uint8Array {
3341
+ return encodeJson<OwnerRecord>({ recordVersion: 1, ownerId, leaseGeneration: leaseGeneration.toString() });
3342
+ }
3343
+
3344
+ function encodeCanonicalDescriptorRecord<T extends OwnedDescriptor>(
3345
+ generation: bigint,
3346
+ descriptor: T
3347
+ ): Uint8Array {
3348
+ // `generation` is an old Node-local row counter. The opaque record's
3349
+ // cmsgpack version is the interoperable row version, so it is deliberately
3350
+ // not serialized (21-location-runtime §2.4).
3351
+ void generation;
3352
+ return Buffer.from(JSON.stringify({
3353
+ recordVersion: 1,
3354
+ ownerId: descriptor.ownerId,
3355
+ leaseGeneration: descriptor.leaseGeneration.toString(),
3356
+ descriptorRevision: descriptor.descriptorRevision.toString(),
3357
+ descriptor: canonicalDescriptor(descriptor)
3358
+ } satisfies CanonicalDescriptorRecord<unknown>), 'utf8');
3359
+ }
3360
+
3361
+ function decodeCanonicalDescriptorRecord<T extends OwnedDescriptor>(bytes: Uint8Array): CanonicalDescriptorRecord<T> {
3362
+ const record = JSON.parse(decodeText(bytes)) as CanonicalDescriptorRecord<unknown>;
3363
+ requireRecordVersion(record, 'descriptor');
3364
+ return reviveCanonical(record) as CanonicalDescriptorRecord<T>;
3365
+ }
3366
+
3367
+ function descriptorStoreGeneration(
3368
+ record: CanonicalDescriptorRecord<unknown>,
3369
+ storeVersion: string
3370
+ ): bigint {
3371
+ return record.generation === undefined ? BigInt(storeVersion) : BigInt(record.generation);
3372
+ }
3373
+
3374
+ function canonicalDescriptor(descriptor: OwnedDescriptor): Record<string, unknown> {
3375
+ if ('rid' in descriptor) return canonicalMeshDescriptor(descriptor);
3376
+ if ('serverRid' in descriptor) return {
3377
+ channelName: descriptor.channelName,
3378
+ serverRoutingIdHex: encodeRoutingIdStorageHex(descriptor.serverRid),
3379
+ lifecycleGeneration: descriptor.lifecycleGeneration.toString(),
3380
+ descriptorRevision: descriptor.descriptorRevision.toString(),
3381
+ endpoint: descriptor.endpoint,
3382
+ weight: descriptor.weight,
3383
+ state: canonicalRuntimeState(descriptor.state),
3384
+ securityIdentity: descriptor.securityIdentity,
3385
+ ownerId: descriptor.ownerId,
3386
+ leaseGeneration: descriptor.leaseGeneration.toString(),
3387
+ updatedAtEpochMs: descriptor.updatedAt.getTime().toString()
3388
+ };
3389
+ const publisher = descriptor as ZLinkFanoutPublisherDescriptor;
3390
+ return {
3391
+ channelName: publisher.channelName,
3392
+ publisherRoutingIdHex: encodeRoutingIdStorageHex(publisher.publisherRid),
3393
+ lifecycleGeneration: publisher.lifecycleGeneration.toString(),
3394
+ descriptorRevision: publisher.descriptorRevision.toString(),
3395
+ endpoint: publisher.endpoint,
3396
+ state: canonicalRuntimeState(publisher.state),
3397
+ securityIdentity: publisher.securityIdentity,
3398
+ ownerId: publisher.ownerId,
3399
+ leaseGeneration: publisher.leaseGeneration.toString(),
3400
+ updatedAtEpochMs: publisher.updatedAt.getTime().toString()
3401
+ };
3402
+ }
3403
+
3404
+ function canonicalMeshDescriptor(descriptor: ZLinkMeshNodeDescriptor): Record<string, unknown> {
3405
+ return {
3406
+ meshName: descriptor.meshName,
3407
+ routingIdHex: encodeRoutingIdStorageHex(descriptor.rid),
3408
+ lifecycleGeneration: descriptor.lifecycleGeneration.toString(),
3409
+ descriptorRevision: descriptor.descriptorRevision.toString(),
3410
+ endpoint: descriptor.endpoint,
3411
+ entrySpotId: descriptor.entrySpotId ?? null,
3412
+ channelWeights: descriptor.channelWeights,
3413
+ applicationVersion: descriptor.applicationVersion.toString(),
3414
+ objectCapabilities: descriptor.objectCapabilities.map(capability => ({
3415
+ ...capability,
3416
+ objectKind: canonicalObjectKind(capability.objectKind),
3417
+ policy: capability.policy === 'disabled' ? 'disabled' : capability.policy
3418
+ })),
3419
+ objectRole: descriptor.objectRole,
3420
+ placementWeight: descriptor.placementWeight,
3421
+ capacity: {
3422
+ actors: descriptor.populationCapacity.actors,
3423
+ spots: descriptor.populationCapacity.spots,
3424
+ spotTypes: descriptor.populationCapacity.spotTypes.map(capacity => ({
3425
+ ...capacity,
3426
+ objectKind: canonicalObjectKind(capacity.objectKind)
3427
+ }))
3428
+ },
3429
+ activationConcurrency: descriptor.activationConcurrency,
3430
+ maintenanceWave: descriptor.maintenanceWave ?? null,
3431
+ state: canonicalRuntimeState(descriptor.state),
3432
+ securityIdentity: descriptor.securityIdentity,
3433
+ ownerId: descriptor.ownerId,
3434
+ leaseGeneration: descriptor.leaseGeneration.toString(),
3435
+ updatedAtEpochMs: descriptor.updatedAt.getTime().toString()
3436
+ };
3437
+ }
3438
+
3439
+ function reviveCanonicalCapacity(value: Record<string, unknown>): ZLinkMeshNodeDescriptor['populationCapacity'] {
3440
+ return {
3441
+ actors: value.actors as ZLinkMeshNodeDescriptor['populationCapacity']['actors'],
3442
+ spots: value.spots as ZLinkMeshNodeDescriptor['populationCapacity']['spots'],
3443
+ spotTypes: (value.spotTypes as readonly Record<string, unknown>[]).map(capacity => ({
3444
+ ...capacity,
3445
+ objectKind: runtimeSpotObjectKind(String(capacity.objectKind))
3446
+ })) as unknown as ZLinkMeshNodeDescriptor['populationCapacity']['spotTypes']
3447
+ };
3448
+ }
3449
+
3450
+ function reviveCanonicalCapabilities(value: unknown): ZLinkMeshNodeDescriptor['objectCapabilities'] {
3451
+ return (value as readonly Record<string, unknown>[]).map(capability => ({
3452
+ ...capability,
3453
+ objectKind: runtimeObjectKind(String(capability.objectKind))
3454
+ })) as unknown as ZLinkMeshNodeDescriptor['objectCapabilities'];
3455
+ }
3456
+
3457
+ function canonicalObjectKind(kind: 'actor' | 'user_spot' | 'instance_spot'): string {
3458
+ return kind === 'user_spot' ? 'userSpot' : kind === 'instance_spot' ? 'instanceSpot' : 'actor';
3459
+ }
3460
+
3461
+ function runtimeObjectKind(kind: string): 'actor' | 'user_spot' | 'instance_spot' {
3462
+ if (kind === 'actor') return 'actor';
3463
+ if (kind === 'userSpot') return 'user_spot';
3464
+ if (kind === 'instanceSpot') return 'instance_spot';
3465
+ throw new TypeError(`Location Store descriptor has invalid objectKind '${kind}'.`);
3466
+ }
3467
+
3468
+ function runtimeSpotObjectKind(kind: string): 'user_spot' | 'instance_spot' {
3469
+ const result = runtimeObjectKind(kind);
3470
+ if (result === 'actor') throw new TypeError('Location Store spot capacity cannot have actor objectKind.');
3471
+ return result;
3472
+ }
3473
+
3474
+ function canonicalRuntimeState(state: ZLinkFrameworkRuntimeState): string {
3475
+ return ['preparing', 'serving', 'relocating', 'relocated', 'draining', 'stopped', 'error'][state]
3476
+ ?? (() => { throw new TypeError(`Location Store descriptor has invalid state '${state}'.`); })();
3477
+ }
3478
+
3479
+ function runtimeState(state: string): ZLinkFrameworkRuntimeState {
3480
+ const index = ['preparing', 'serving', 'relocating', 'relocated', 'draining', 'stopped', 'error'].indexOf(state);
3481
+ if (index < 0) throw new TypeError(`Location Store descriptor has invalid state '${state}'.`);
3482
+ return index as ZLinkFrameworkRuntimeState;
3483
+ }
3484
+
3485
+ function encodeAuthorityRecord(record: AuthorityRecord): Uint8Array {
3486
+ const snapshot = record.snapshot;
3487
+ const allocation = snapshot.allocation;
3488
+ const envelope: Record<string, unknown> = {
3489
+ recordVersion: 1,
3490
+ payload: Buffer.from(snapshot.payload).toString('base64'),
3491
+ objectGeneration: snapshot.objectGeneration.toString(),
3492
+ authorityOwnerGeneration: snapshot.authorityOwnerGeneration.toString(),
3493
+ ownerId: snapshot.ownerId,
3494
+ ownerLeaseGeneration: snapshot.ownerLeaseGeneration.toString(),
3495
+ allocation: {
3496
+ state: allocation.state,
3497
+ objectKind: canonicalPlacementObjectKind(allocation.objectKind),
3498
+ stableType: allocation.stableType,
3499
+ descriptor: {
3500
+ meshName: allocation.descriptor.meshName,
3501
+ routingIdHex: encodeRoutingIdStorageHex(allocation.descriptor.rid)
3502
+ },
3503
+ descriptorLifecycleGeneration: allocation.descriptorLifecycleGeneration.toString(),
3504
+ capacity: canonicalAuthorityCapacity(allocation.capacity)
3505
+ },
3506
+ pendingCreation: snapshot.pendingCreation === undefined ? null : {
3507
+ reservationId: snapshot.pendingCreation.reservationId,
3508
+ requestContentReference: snapshot.pendingCreation.requestContentReference,
3509
+ requestSha256: Buffer.from(snapshot.pendingCreation.requestSha256).toString('hex'),
3510
+ requestEncodedSize: Number(snapshot.pendingCreation.requestEncodedSize)
3511
+ }
3512
+ };
3513
+ // These fields gate Node-only creation/aggregate recovery. They are absent
3514
+ // from normal authority values (including the golden vector), while the
3515
+ // interoperable envelope above remains byte-canonical.
3516
+ if (record.reservationId !== undefined) envelope.reservationId = record.reservationId;
3517
+ if (record.terminal !== undefined) envelope.terminal = record.terminal;
3518
+ if (record.aggregate !== undefined) envelope.aggregate = canonicalize(record.aggregate);
3519
+ if (record.visibleStoreVersion !== undefined) envelope.visibleStoreVersion = record.visibleStoreVersion;
3520
+ return Buffer.from(JSON.stringify(envelope), 'utf8');
3521
+ }
3522
+
3523
+ function decodeAuthorityRecord(bytes: Uint8Array): AuthorityRecord {
3524
+ const value = JSON.parse(decodeText(bytes)) as Record<string, unknown>;
3525
+ requireRecordVersion(value, 'authority');
3526
+ const allocation = value.allocation as Record<string, unknown>;
3527
+ const descriptor = allocation.descriptor as Record<string, unknown>;
3528
+ const capacity = allocation.capacity as Record<string, unknown>;
3529
+ const pending = value.pendingCreation as Record<string, unknown> | null;
3530
+ const objectKind = runtimePlacementObjectKind(String(allocation.objectKind));
3531
+ return {
3532
+ reservationId: typeof value.reservationId === 'string' ? value.reservationId : undefined,
3533
+ terminal: value.terminal as AuthorityRecord['terminal'],
3534
+ aggregate: value.aggregate === undefined
3535
+ ? undefined
3536
+ : reviveCanonical(value.aggregate) as AggregateParticipantFenceRecord,
3537
+ visibleStoreVersion: typeof value.visibleStoreVersion === 'string'
3538
+ ? value.visibleStoreVersion : undefined,
3539
+ snapshot: {
3540
+ payload: Buffer.from(String(value.payload), 'base64'),
3541
+ objectGeneration: BigInt(String(value.objectGeneration)),
3542
+ authorityOwnerGeneration: BigInt(String(value.authorityOwnerGeneration)),
3543
+ ownerId: String(value.ownerId),
3544
+ ownerLeaseGeneration: BigInt(String(value.ownerLeaseGeneration)),
3545
+ allocation: {
3546
+ state: allocation.state as ZLinkPlacementAllocation['state'],
3547
+ objectKind: objectKind as ZLinkPlacementAllocation['objectKind'],
3548
+ stableType: String(allocation.stableType),
3549
+ descriptor: {
3550
+ meshName: String(descriptor.meshName),
3551
+ rid: decodeRoutingId(
3552
+ String(descriptor.routingIdHex),
3553
+ descriptor.routingIdHex
3554
+ )
3555
+ },
3556
+ descriptorLifecycleGeneration: BigInt(String(allocation.descriptorLifecycleGeneration)),
3557
+ capacity: {
3558
+ actors: Number(capacity.actors),
3559
+ spots: Number(capacity.spots),
3560
+ spotType: capacity.spotType === null
3561
+ ? undefined
3562
+ : decodeAuthoritySpotType(capacity.spotType)
3563
+ }
3564
+ },
3565
+ pendingCreation: pending === null ? undefined : {
3566
+ reservationId: String(pending.reservationId),
3567
+ requestContentReference: String(pending.requestContentReference),
3568
+ requestSha256: Buffer.from(String(pending.requestSha256), 'hex'),
3569
+ requestEncodedSize: BigInt(String(pending.requestEncodedSize))
3570
+ }
3571
+ }
3572
+ };
3573
+ }
3574
+
3575
+ function canonicalPlacementObjectKind(kind: ZLinkPlacementAllocation['objectKind']): string {
3576
+ switch (kind) {
3577
+ case 'actor': return 'actor';
3578
+ case 'user_spot': return 'userSpot';
3579
+ case 'instance_spot': return 'instanceSpot';
3580
+ }
3581
+ }
3582
+
3583
+ function runtimePlacementObjectKind(kind: string): ZLinkPlacementAllocation['objectKind'] {
3584
+ switch (kind) {
3585
+ case 'actor': return 'actor';
3586
+ case 'userSpot': return 'user_spot';
3587
+ case 'instanceSpot': return 'instance_spot';
3588
+ default: throw new Error(`Location Store authority record has an invalid allocation objectKind '${kind}'.`);
3589
+ }
3590
+ }
3591
+
3592
+ function canonicalAuthorityCapacity(capacity: ZLinkCapacityVector): Record<string, unknown> {
3593
+ return {
3594
+ actors: capacity.actors,
3595
+ spots: capacity.spots,
3596
+ spotType: capacity.spotType === undefined
3597
+ ? null
3598
+ : {
3599
+ objectKind: canonicalPlacementObjectKind(capacity.spotType.objectKind),
3600
+ stableType: capacity.spotType.stableType,
3601
+ count: capacity.spotType.count
3602
+ }
3603
+ };
3604
+ }
3605
+
3606
+ function decodeAuthoritySpotType(value: unknown): ZLinkCapacityVector['spotType'] {
3607
+ const spotType = value as Record<string, unknown>;
3608
+ return {
3609
+ objectKind: runtimeSpotPlacementObjectKind(String(spotType.objectKind)),
3610
+ stableType: String(spotType.stableType),
3611
+ count: Number(spotType.count)
3612
+ };
3613
+ }
3614
+
3615
+ function runtimeSpotPlacementObjectKind(
3616
+ kind: string
3617
+ ): Exclude<ZLinkPlacementAllocation['objectKind'], 'actor'> {
3618
+ const objectKind = runtimePlacementObjectKind(kind);
3619
+ if (objectKind === 'actor') {
3620
+ throw new Error('Location Store authority capacity spotType cannot be an actor.');
3621
+ }
3622
+ return objectKind;
3623
+ }
3624
+
3625
+ function createTerminalRecord(
3626
+ request: ZLinkObjectCreationCompleteRequest,
3627
+ now: Date
3628
+ ): ZLinkCreationTerminalRecord {
3629
+ const publication = request.completion.terminal;
3630
+ validateCreationOperation(publication.operation);
3631
+ if (
3632
+ publication.terminalEnvelope.byteLength > MAX_CREATION_TERMINAL_BYTES
3633
+ || publication.terminalEnvelopeSha256.byteLength !== 32
3634
+ ) {
3635
+ throw new RangeError(
3636
+ 'Creation terminal envelope must not exceed 1 MiB and requires a SHA-256 digest.'
3637
+ );
3638
+ }
3639
+ const actualSha = createHash('sha256').update(publication.terminalEnvelope).digest();
3640
+ if (!timingSafeEqual(actualSha, Buffer.from(publication.terminalEnvelopeSha256))) {
3641
+ throw new TypeError('Creation terminal envelope SHA-256 does not match its bytes.');
3642
+ }
3643
+ const deadlineMs = publication.operationDeadline.getTime();
3644
+ const expiresAtMs = deadlineMs + CREATION_TERMINAL_RETENTION_MS;
3645
+ if (
3646
+ !Number.isSafeInteger(deadlineMs)
3647
+ || !Number.isSafeInteger(expiresAtMs)
3648
+ || expiresAtMs <= now.getTime()
3649
+ ) {
3650
+ throw new RangeError(
3651
+ 'Creation terminal expiry must be the live operation deadline plus five minutes.'
3652
+ );
3653
+ }
3654
+ if (request.completion.kind === 'created') {
3655
+ validatePayloadSize(request.completion.readyPayload, 'Actor ready payload');
3656
+ }
3657
+ return {
3658
+ state: request.completion.kind,
3659
+ operation: {
3660
+ sourceNodeRid: publication.operation.sourceNodeRid,
3661
+ sourceNodeGeneration: publication.operation.sourceNodeGeneration,
3662
+ operationId: { ...publication.operation.operationId }
3663
+ },
3664
+ reservationId: requireText(request.reservationId, 'creation reservation ID'),
3665
+ objectKind: request.key.kind,
3666
+ terminalEnvelope: Buffer.from(publication.terminalEnvelope),
3667
+ terminalEnvelopeSha256: Buffer.from(publication.terminalEnvelopeSha256),
3668
+ expiresAt: new Date(expiresAtMs),
3669
+ storeNow: new Date(now)
3670
+ };
3671
+ }
3672
+
3673
+ function reviveCreationTerminal(
3674
+ record: ZLinkCreationTerminalRecord
3675
+ ): ZLinkCreationTerminalRecord {
3676
+ return {
3677
+ ...record,
3678
+ operation: {
3679
+ ...record.operation,
3680
+ sourceNodeRid: String(record.operation.sourceNodeRid),
3681
+ operationId: { ...record.operation.operationId }
3682
+ },
3683
+ terminalEnvelope: Buffer.from(record.terminalEnvelope),
3684
+ terminalEnvelopeSha256: Buffer.from(record.terminalEnvelopeSha256),
3685
+ expiresAt: reviveDate(record.expiresAt),
3686
+ storeNow: reviveDate(record.storeNow)
3687
+ };
3688
+ }
3689
+
3690
+ function validateCreationOperation(operation: ZLinkCreationOperationIdentity): void {
3691
+ const sourceRid = String(operation.sourceNodeRid);
3692
+ const sourceRidBytes = Buffer.byteLength(sourceRid, 'utf8');
3693
+ if (sourceRidBytes < 1 || sourceRidBytes > 255 || sourceRid.includes('\0')) {
3694
+ throw new TypeError(
3695
+ 'Creation terminal source node RID must contain 1..255 UTF-8 bytes without NUL.'
3696
+ );
3697
+ }
3698
+ if (
3699
+ operation.sourceNodeGeneration < 1n
3700
+ || operation.sourceNodeGeneration > MAX_GENERATION
3701
+ || operation.operationId.high < 0n
3702
+ || operation.operationId.high > MAX_U64
3703
+ || operation.operationId.low < 0n
3704
+ || operation.operationId.low > MAX_U64
3705
+ || (operation.operationId.high === 0n && operation.operationId.low === 0n)
3706
+ ) {
3707
+ throw new RangeError('Creation terminal source generation and operation ID are invalid.');
3708
+ }
3709
+ }
3710
+
3711
+ function validatePayloadSize(value: Uint8Array, name: string): void {
3712
+ if (value.byteLength > MAX_CREATION_TERMINAL_BYTES) {
3713
+ throw new RangeError(`${name} must not exceed 1 MiB.`);
3714
+ }
3715
+ }
3716
+
3717
+ function requireText(value: string, name: string): string {
3718
+ if (value.length === 0 || value.includes('\0')) {
3719
+ throw new TypeError(`${name} must be non-empty text without NUL.`);
3720
+ }
3721
+ return value;
3722
+ }
3723
+
3724
+ function authoritySnapshot(
3725
+ snapshot: StoredAuthoritySnapshot,
3726
+ storeVersion: ZLinkStoreVersion,
3727
+ storeNow: Date
3728
+ ): ZLinkAuthoritySnapshot {
3729
+ return {
3730
+ kind: 'snapshot',
3731
+ ...snapshot,
3732
+ payload: Buffer.from(snapshot.payload),
3733
+ pendingCreation: snapshot.pendingCreation === undefined
3734
+ ? undefined
3735
+ : {
3736
+ ...snapshot.pendingCreation,
3737
+ requestSha256: Buffer.from(snapshot.pendingCreation.requestSha256)
3738
+ },
3739
+ storeVersion: { value: storeVersion.value } as ZLinkAuthorityStoreVersion,
3740
+ storeNow
3741
+ };
3742
+ }
3743
+
3744
+ function liveTargetDescriptor(
3745
+ descriptorRead: ZLinkStoreReadResult,
3746
+ leaseRead: ZLinkStoreReadResult,
3747
+ target: {
3748
+ readonly meshName: string;
3749
+ readonly nodeRid: unknown;
3750
+ readonly nodeLifecycleGeneration: bigint;
3751
+ readonly owner: ZLinkLocationOwnerToken;
3752
+ }
3753
+ ): ZLinkMeshNodeDescriptor | undefined {
3754
+ if (descriptorRead.kind === 'missing' || leaseRead.kind === 'missing') return undefined;
3755
+ const descriptor = reviveMeshDescriptor(
3756
+ decodeCanonicalDescriptorRecord<ZLinkMeshNodeDescriptor>(descriptorRead.value.bytes).descriptor
3757
+ );
3758
+ const lease = decodeOwnerRecord(leaseRead.value.bytes);
3759
+ return descriptor.meshName === target.meshName
3760
+ && String(descriptor.rid) === String(target.nodeRid)
3761
+ && descriptor.lifecycleGeneration === target.nodeLifecycleGeneration
3762
+ && descriptor.ownerId === target.owner.ownerId
3763
+ && descriptor.leaseGeneration === target.owner.leaseGeneration
3764
+ && descriptor.objectRole === ZLinkObjectRole.Server
3765
+ && descriptor.state === ZLinkFrameworkRuntimeState.Serving
3766
+ && lease.ownerId === target.owner.ownerId
3767
+ && BigInt(lease.leaseGeneration) === target.owner.leaseGeneration
3768
+ && leaseRead.value.expiresAt !== undefined
3769
+ && leaseRead.value.expiresAt.getTime() > leaseRead.value.storeNow.getTime()
3770
+ ? descriptor
3771
+ : undefined;
3772
+ }
3773
+
3774
+ function conditionFor(
3775
+ key: ZLinkStoreKey,
3776
+ read: ZLinkStoreReadResult
3777
+ ): ZLinkStoreCondition {
3778
+ return read.kind === 'missing'
3779
+ ? { kind: 'missing', key }
3780
+ : { kind: 'version', key, expected: read.value.version };
3781
+ }
3782
+
3783
+ function versionCondition(
3784
+ key: ZLinkStoreKey,
3785
+ read: ZLinkStoreReadResult
3786
+ ): ZLinkStoreCondition {
3787
+ if (read.kind === 'missing') {
3788
+ throw new Error(`Required provider row '${key}' is missing.`);
3789
+ }
3790
+ return { kind: 'version', key, expected: read.value.version };
3791
+ }
3792
+
3793
+ function emptyCapacityRecord(): CapacityRecord {
3794
+ return {
3795
+ active: { actors: 0, spots: 0, spotTypes: {} },
3796
+ pending: { actors: 0, spots: 0, spotTypes: {} }
3797
+ };
3798
+ }
3799
+
3800
+ function capacityAvailable(
3801
+ descriptor: ZLinkMeshNodeDescriptor,
3802
+ requested: ZLinkCapacityVector,
3803
+ capacity: CapacityRecord
3804
+ ): boolean {
3805
+ const spotType = requested.spotType;
3806
+ const typeCapacity = spotType === undefined
3807
+ ? undefined
3808
+ : descriptor.populationCapacity.spotTypes.find(candidate =>
3809
+ candidate.objectKind === spotType.objectKind
3810
+ && candidate.stableType === spotType.stableType);
3811
+ const typeKey = spotType === undefined ? undefined : capacityTypeKey(spotType);
3812
+ return (descriptor.populationCapacity.actors.limit === 0
3813
+ || capacity.active.actors + capacity.pending.actors + requested.actors
3814
+ <= descriptor.populationCapacity.actors.limit)
3815
+ && (descriptor.populationCapacity.spots.limit === 0
3816
+ || capacity.active.spots + capacity.pending.spots + requested.spots
3817
+ <= descriptor.populationCapacity.spots.limit)
3818
+ && (spotType === undefined
3819
+ || typeCapacity !== undefined
3820
+ && (typeCapacity.limit === 0
3821
+ || (capacity.active.spotTypes[typeKey!] ?? 0)
3822
+ + (capacity.pending.spotTypes[typeKey!] ?? 0)
3823
+ + spotType.count <= typeCapacity.limit));
3824
+ }
3825
+
3826
+ function addCapacity(usage: CapacityUsage, delta: ZLinkCapacityVector): CapacityUsage {
3827
+ return adjustCapacity(usage, delta, 1);
3828
+ }
3829
+
3830
+ function subtractCapacity(usage: CapacityUsage, delta: ZLinkCapacityVector): CapacityUsage {
3831
+ return adjustCapacity(usage, delta, -1);
3832
+ }
3833
+
3834
+ function adjustCapacity(
3835
+ usage: CapacityUsage,
3836
+ delta: ZLinkCapacityVector,
3837
+ direction: 1 | -1
3838
+ ): CapacityUsage {
3839
+ const spotTypes = { ...usage.spotTypes };
3840
+ if (delta.spotType !== undefined) {
3841
+ const key = capacityTypeKey(delta.spotType);
3842
+ const next = (spotTypes[key] ?? 0) + direction * delta.spotType.count;
3843
+ if (next < 0) throw new Error('Provider capacity counter underflow.');
3844
+ if (next === 0) delete spotTypes[key];
3845
+ else spotTypes[key] = next;
3846
+ }
3847
+ const actors = usage.actors + direction * delta.actors;
3848
+ const spots = usage.spots + direction * delta.spots;
3849
+ if (actors < 0 || spots < 0) throw new Error('Provider capacity counter underflow.');
3850
+ return { actors, spots, spotTypes };
3851
+ }
3852
+
3853
+ function capacityTypeKey(
3854
+ value: NonNullable<ZLinkCapacityVector['spotType']>
3855
+ ): string {
3856
+ return `${value.objectKind}\0${value.stableType}`;
3857
+ }
3858
+
3859
+ function cloneCapacity(value: ZLinkCapacityVector): ZLinkCapacityVector {
3860
+ return {
3861
+ actors: value.actors,
3862
+ spots: value.spots,
3863
+ spotType: value.spotType === undefined ? undefined : { ...value.spotType }
3864
+ };
3865
+ }
3866
+
3867
+ function sameCapacityVector(left: ZLinkCapacityVector, right: ZLinkCapacityVector): boolean {
3868
+ return left.actors === right.actors
3869
+ && left.spots === right.spots
3870
+ && left.spotType?.objectKind === right.spotType?.objectKind
3871
+ && left.spotType?.stableType === right.spotType?.stableType
3872
+ && left.spotType?.count === right.spotType?.count;
3873
+ }
3874
+
3875
+ function sameCreationTarget(
3876
+ snapshot: StoredAuthoritySnapshot,
3877
+ target: ZLinkObjectCommitRequest['target']
3878
+ ): boolean {
3879
+ return snapshot.allocation.descriptor.meshName === target.meshName
3880
+ && String(snapshot.allocation.descriptor.rid) === String(target.nodeRid)
3881
+ && snapshot.allocation.descriptorLifecycleGeneration
3882
+ === target.nodeLifecycleGeneration
3883
+ && snapshot.ownerId === target.owner.ownerId
3884
+ && snapshot.ownerLeaseGeneration === target.owner.leaseGeneration;
3885
+ }
3886
+
3887
+ function sameLiveOwner(
3888
+ lease: ZLinkStoreReadResult,
3889
+ snapshot: StoredAuthoritySnapshot
3890
+ ): boolean {
3891
+ if (liveOwnerLeaseGeneration(lease) !== snapshot.ownerLeaseGeneration) return false;
3892
+ const owner = decodeOwnerRecord((lease as Extract<ZLinkStoreReadResult, { kind: 'found' }>).value.bytes);
3893
+ return owner.ownerId === snapshot.ownerId;
3894
+ }
3895
+
3896
+ function liveOwnerLeaseGeneration(
3897
+ lease: ZLinkStoreReadResult
3898
+ ): bigint | undefined {
3899
+ if (lease.kind === 'missing'
3900
+ || lease.value.expiresAt === undefined
3901
+ || lease.value.expiresAt.getTime() <= lease.value.storeNow.getTime()) {
3902
+ return undefined;
3903
+ }
3904
+ return BigInt(decodeOwnerRecord(lease.value.bytes).leaseGeneration);
3905
+ }
3906
+
3907
+ function canTakeOverStoredLocation(
3908
+ intent: ZLinkLocationWriteIntent,
3909
+ currentOwnerId: string,
3910
+ currentLeaseGeneration: bigint,
3911
+ nextOwnerId: string,
3912
+ nextLeaseGeneration: bigint,
3913
+ liveLeaseGeneration: bigint | undefined
3914
+ ): boolean {
3915
+ if (intent === ZLinkLocationWriteIntent.Takeover) {
3916
+ // Takeover is an explicit handoff operation. The provider CAS still
3917
+ // fences concurrent stale writes while the next owner lease is checked.
3918
+ return true;
3919
+ }
3920
+ if (intent !== ZLinkLocationWriteIntent.NewClaim) {
3921
+ return false;
3922
+ }
3923
+ if (liveLeaseGeneration === undefined) return true;
3924
+ return currentOwnerId === nextOwnerId
3925
+ && currentLeaseGeneration !== nextLeaseGeneration
3926
+ && liveLeaseGeneration === nextLeaseGeneration;
3927
+ }
3928
+
3929
+ function persistMeshDescriptor(descriptor: ZLinkMeshNodeDescriptor): ZLinkMeshNodeDescriptor {
3930
+ return descriptor;
3931
+ }
3932
+
3933
+ function reviveMeshDescriptor(descriptor: ZLinkMeshNodeDescriptor): ZLinkMeshNodeDescriptor {
3934
+ const value = descriptor as unknown as Record<string, unknown>;
3935
+ if ('routingIdHex' in value) {
3936
+ const capacity = value.capacity as Record<string, unknown>;
3937
+ return {
3938
+ meshName: String(value.meshName),
3939
+ rid: decodeRoutingId(String(value.routingIdHex), value.routingIdHex),
3940
+ lifecycleGeneration: BigInt(String(value.lifecycleGeneration)),
3941
+ descriptorRevision: BigInt(String(value.descriptorRevision)),
3942
+ endpoint: String(value.endpoint),
3943
+ objectRole: value.objectRole as ZLinkObjectRole,
3944
+ entrySpotId: value.entrySpotId === null ? undefined : value.entrySpotId as string | undefined,
3945
+ placementWeight: Number(value.placementWeight),
3946
+ populationCapacity: reviveCanonicalCapacity(capacity),
3947
+ activationConcurrency: value.activationConcurrency as ZLinkMeshNodeDescriptor['activationConcurrency'],
3948
+ channelWeights: value.channelWeights as Readonly<Record<string, number>>,
3949
+ applicationVersion: BigInt(String(value.applicationVersion)),
3950
+ spotTypes: [],
3951
+ objectCapabilities: reviveCanonicalCapabilities(value.objectCapabilities),
3952
+ maintenanceWave: value.maintenanceWave === null ? undefined : value.maintenanceWave as string | undefined,
3953
+ state: runtimeState(String(value.state)),
3954
+ securityIdentity: String(value.securityIdentity),
3955
+ ownerId: String(value.ownerId),
3956
+ leaseGeneration: BigInt(String(value.leaseGeneration)),
3957
+ updatedAt: new Date(Number(value.updatedAtEpochMs))
3958
+ };
3959
+ }
3960
+ return {
3961
+ ...descriptor,
3962
+ rid: descriptor.rid,
3963
+ updatedAt: descriptor.updatedAt instanceof Date
3964
+ ? descriptor.updatedAt
3965
+ : new Date(descriptor.updatedAt)
3966
+ };
3967
+ }
3968
+
3969
+ function reviveClientServerDescriptor(
3970
+ descriptor: ZLinkClientServerServerDescriptor
3971
+ ): ZLinkClientServerServerDescriptor {
3972
+ const value = descriptor as unknown as Record<string, unknown>;
3973
+ if ('serverRoutingIdHex' in value) {
3974
+ return {
3975
+ channelName: String(value.channelName),
3976
+ serverRid: decodeRoutingId(String(value.serverRoutingIdHex), value.serverRoutingIdHex),
3977
+ lifecycleGeneration: BigInt(String(value.lifecycleGeneration)),
3978
+ descriptorRevision: BigInt(String(value.descriptorRevision)),
3979
+ endpoint: String(value.endpoint),
3980
+ weight: Number(value.weight),
3981
+ state: runtimeState(String(value.state)),
3982
+ securityIdentity: String(value.securityIdentity),
3983
+ ownerId: String(value.ownerId),
3984
+ leaseGeneration: BigInt(String(value.leaseGeneration)),
3985
+ updatedAt: new Date(Number(value.updatedAtEpochMs))
3986
+ };
3987
+ }
3988
+ return {
3989
+ ...descriptor,
3990
+ serverRid: descriptor.serverRid,
3991
+ updatedAt: reviveDate(descriptor.updatedAt)
3992
+ };
3993
+ }
3994
+
3995
+ function reviveFanoutDescriptor(
3996
+ descriptor: ZLinkFanoutPublisherDescriptor
3997
+ ): ZLinkFanoutPublisherDescriptor {
3998
+ const value = descriptor as unknown as Record<string, unknown>;
3999
+ if ('publisherRoutingIdHex' in value) {
4000
+ return {
4001
+ channelName: String(value.channelName),
4002
+ publisherRid: decodeRoutingId(String(value.publisherRoutingIdHex), value.publisherRoutingIdHex),
4003
+ lifecycleGeneration: BigInt(String(value.lifecycleGeneration)),
4004
+ descriptorRevision: BigInt(String(value.descriptorRevision)),
4005
+ endpoint: String(value.endpoint),
4006
+ state: runtimeState(String(value.state)),
4007
+ securityIdentity: String(value.securityIdentity),
4008
+ ownerId: String(value.ownerId),
4009
+ leaseGeneration: BigInt(String(value.leaseGeneration)),
4010
+ updatedAt: new Date(Number(value.updatedAtEpochMs))
4011
+ };
4012
+ }
4013
+ return {
4014
+ ...descriptor,
4015
+ publisherRid: descriptor.publisherRid,
4016
+ updatedAt: reviveDate(descriptor.updatedAt)
4017
+ };
4018
+ }
4019
+
4020
+ function reviveDate(value: Date): Date {
4021
+ return value instanceof Date ? value : new Date(value);
4022
+ }
4023
+
4024
+ function normalizeSpot(value: ZLinkSpotLocation): ZLinkSpotLocation {
4025
+ return {
4026
+ ...value,
4027
+ spotId: String(value.spotId),
4028
+ ownerNodeRid: String(value.ownerNodeRid),
4029
+ updatedAt: reviveDate(value.updatedAt)
4030
+ };
4031
+ }
4032
+
4033
+ function normalizeActor(value: ZLinkActorLocation): ZLinkActorLocation {
4034
+ return {
4035
+ ...value,
4036
+ actorRef: {
4037
+ ...value.actorRef,
4038
+ nodeRid: String(value.actorRef.nodeRid)
4039
+ },
4040
+ ownerNodeRid: String(value.ownerNodeRid),
4041
+ spotId: String(value.spotId),
4042
+ updatedAt: reviveDate(value.updatedAt)
4043
+ };
4044
+ }
4045
+
4046
+ function normalizeRoute(value: ZLinkRouteLocation): ZLinkRouteLocation {
4047
+ return {
4048
+ ...value,
4049
+ ownerNodeRid: String(value.ownerNodeRid),
4050
+ value: Buffer.from(value.value),
4051
+ updatedAt: reviveDate(value.updatedAt)
4052
+ };
4053
+ }
4054
+
4055
+ function matchesSpot(value: ZLinkSpotLocation, filter: ZLinkSpotLocationFilter): boolean {
4056
+ return (filter.meshName === undefined || value.meshName === filter.meshName)
4057
+ && (filter.spotType === undefined || value.spotType === filter.spotType)
4058
+ && (filter.nodeRid === undefined || String(value.ownerNodeRid) === String(filter.nodeRid))
4059
+ && (filter.spotKind === undefined || value.spotKind === filter.spotKind);
4060
+ }
4061
+
4062
+ function matchesActor(value: ZLinkActorLocation, filter: ZLinkActorLocationFilter): boolean {
4063
+ return (filter.actorType === undefined || value.actorType === filter.actorType)
4064
+ && (filter.nodeRid === undefined || String(value.ownerNodeRid) === String(filter.nodeRid))
4065
+ && (filter.spotId === undefined || String(value.spotId) === String(filter.spotId))
4066
+ && (filter.locationKind === undefined || value.spotKind === filter.locationKind);
4067
+ }
4068
+
4069
+ function matchesRoute(value: ZLinkRouteLocation, filter: ZLinkRouteLocationFilter): boolean {
4070
+ return (filter.routeKind === undefined || value.routeKind === filter.routeKind)
4071
+ && (filter.ownerNodeRid === undefined
4072
+ || String(value.ownerNodeRid) === String(filter.ownerNodeRid))
4073
+ && (filter.ownerId === undefined || value.ownerId === filter.ownerId);
4074
+ }
4075
+
4076
+ function locationOwnerGeneration(value: LeaseOwnedLocation): bigint {
4077
+ return value.leaseGeneration;
4078
+ }
4079
+
4080
+ function descriptorOwnerLeaseGeneration(value: OwnedStoreRecord): bigint | undefined {
4081
+ if ('leaseGeneration' in value) {
4082
+ return typeof value.leaseGeneration === 'bigint'
4083
+ ? value.leaseGeneration
4084
+ : BigInt(value.leaseGeneration);
4085
+ }
4086
+ if ('generation' in value) {
4087
+ return typeof value.generation === 'bigint'
4088
+ ? value.generation
4089
+ : BigInt(value.generation);
4090
+ }
4091
+ return undefined;
4092
+ }
4093
+
4094
+ function sameMeshDescriptor(
4095
+ left: ZLinkMeshNodeDescriptor,
4096
+ right: ZLinkMeshNodeDescriptor
4097
+ ): boolean {
4098
+ return Buffer.from(encodeJson(persistMeshDescriptor(left))).equals(
4099
+ Buffer.from(encodeJson(persistMeshDescriptor(right))));
4100
+ }
4101
+
4102
+ function sameClientServerDescriptor(
4103
+ left: ZLinkClientServerServerDescriptor,
4104
+ right: ZLinkClientServerServerDescriptor
4105
+ ): boolean {
4106
+ return descriptorFingerprint(left, ['updatedAt']) === descriptorFingerprint(right, ['updatedAt']);
4107
+ }
4108
+
4109
+ function sameFanoutDescriptor(
4110
+ left: ZLinkFanoutPublisherDescriptor,
4111
+ right: ZLinkFanoutPublisherDescriptor
4112
+ ): boolean {
4113
+ return descriptorFingerprint(left, ['updatedAt']) === descriptorFingerprint(right, ['updatedAt']);
4114
+ }
4115
+
4116
+ function canRenewClientServer(
4117
+ current: ZLinkClientServerServerDescriptor,
4118
+ next: ZLinkClientServerServerDescriptor
4119
+ ): boolean {
4120
+ return sameOwnerGeneration(current, next)
4121
+ && next.descriptorRevision > current.descriptorRevision
4122
+ && descriptorFingerprint(current, ['descriptorRevision', 'weight', 'state', 'updatedAt'])
4123
+ === descriptorFingerprint(next, ['descriptorRevision', 'weight', 'state', 'updatedAt']);
4124
+ }
4125
+
4126
+ function canRenewFanout(
4127
+ current: ZLinkFanoutPublisherDescriptor,
4128
+ next: ZLinkFanoutPublisherDescriptor
4129
+ ): boolean {
4130
+ return sameOwnerGeneration(current, next)
4131
+ && next.descriptorRevision > current.descriptorRevision
4132
+ && descriptorFingerprint(current, ['descriptorRevision', 'state', 'updatedAt'])
4133
+ === descriptorFingerprint(next, ['descriptorRevision', 'state', 'updatedAt']);
4134
+ }
4135
+
4136
+ function sameOwnerGeneration(left: OwnedDescriptor, right: OwnedDescriptor): boolean {
4137
+ return left.ownerId === right.ownerId
4138
+ && left.leaseGeneration === right.leaseGeneration
4139
+ && left.lifecycleGeneration === right.lifecycleGeneration;
4140
+ }
4141
+
4142
+ function descriptorFingerprint(
4143
+ descriptor: OwnedDescriptor,
4144
+ omitted: readonly string[]
4145
+ ): string {
4146
+ // Descriptor rows are canonicalized through routing-id hex. Comparing the
4147
+ // in-memory shape here would distinguish a binding RoutingId instance from
4148
+ // the equivalent ID revived from a canonical row, incorrectly rejecting a
4149
+ // legitimate renew as stale.
4150
+ const canonical = canonicalDescriptor(descriptor);
4151
+ for (const key of omitted) {
4152
+ delete canonical[key === 'updatedAt' ? 'updatedAtEpochMs' : key];
4153
+ }
4154
+ return Buffer.from(encodeJson(canonical)).toString('base64');
4155
+ }
4156
+
4157
+ function validateClientServerDescriptor(descriptor: ZLinkClientServerServerDescriptor): void {
4158
+ validateDescriptorIdentity([
4159
+ descriptor.channelName,
4160
+ String(descriptor.serverRid),
4161
+ descriptor.endpoint,
4162
+ descriptor.securityIdentity,
4163
+ descriptor.ownerId
4164
+ ], 'ClientServer');
4165
+ validateDescriptorGenerations(descriptor, 'ClientServer');
4166
+ if (!Number.isInteger(descriptor.weight) || descriptor.weight < 0 || descriptor.weight > 10_000) {
4167
+ throw new RangeError('ClientServer descriptor weight must be an integer in 0..10000.');
4168
+ }
4169
+ }
4170
+
4171
+ function validateFanoutPublisherDescriptor(descriptor: ZLinkFanoutPublisherDescriptor): void {
4172
+ validateDescriptorIdentity([
4173
+ descriptor.channelName,
4174
+ String(descriptor.publisherRid),
4175
+ descriptor.endpoint,
4176
+ descriptor.securityIdentity,
4177
+ descriptor.ownerId
4178
+ ], 'Fanout publisher');
4179
+ validateDescriptorGenerations(descriptor, 'Fanout publisher');
4180
+ }
4181
+
4182
+ function validateDescriptorIdentity(values: readonly string[], kind: string): void {
4183
+ if (values.some(value => Buffer.byteLength(value, 'utf8') < 1 || value.includes('\0'))) {
4184
+ throw new TypeError(`${kind} descriptor identity and endpoint are required.`);
4185
+ }
4186
+ }
4187
+
4188
+ function validateDescriptorGenerations(descriptor: OwnedDescriptor, kind: string): void {
4189
+ if (descriptor.lifecycleGeneration < 1n || descriptor.lifecycleGeneration > MAX_GENERATION
4190
+ || descriptor.descriptorRevision < 1n || descriptor.descriptorRevision > MAX_GENERATION
4191
+ || descriptor.leaseGeneration < 1n || descriptor.leaseGeneration > MAX_GENERATION) {
4192
+ throw new RangeError(`${kind} descriptor generations are invalid.`);
4193
+ }
4194
+ }
4195
+
4196
+ function rejected(updatedAt: Date): ZLinkLocationWriteResult {
4197
+ return {
4198
+ status: WriteStatus.RejectedConflict,
4199
+ generation: 0n,
4200
+ updatedAt
4201
+ };
4202
+ }
4203
+
4204
+ function requireOwnerInput(ownerId: string, leaseTtlMs: number): void {
4205
+ if (Buffer.byteLength(ownerId, 'utf8') < 1 || ownerId.includes('\0')) {
4206
+ throw new TypeError('Owner ID must be non-empty UTF-8 without NUL.');
4207
+ }
4208
+ if (!Number.isSafeInteger(leaseTtlMs) || leaseTtlMs < 1) {
4209
+ throw new RangeError('Owner lease TTL must be a positive safe integer.');
4210
+ }
4211
+ }