@zlink-systems/framework 0.30.1 → 0.30.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
  3. package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
  4. package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
  5. package/dist/contracts/Common/encoded-payload-storage.js +5 -2
  6. package/dist/contracts/Configuration/Builders.d.ts +1 -1
  7. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
  8. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
  9. package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
  10. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
  11. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
  12. package/dist/contracts/Locations/Rows.d.ts +2 -0
  13. package/dist/contracts/Spots/Contracts.d.ts +4 -0
  14. package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
  15. package/dist/runtime/abort.d.ts +5 -0
  16. package/dist/runtime/abort.js +10 -0
  17. package/dist/runtime/actors/actor-authority-publication.js +3 -2
  18. package/dist/runtime/actors/actor-client.d.ts +0 -1
  19. package/dist/runtime/actors/actor-client.js +38 -45
  20. package/dist/runtime/actors/actor-context.d.ts +2 -0
  21. package/dist/runtime/actors/actor-context.js +46 -9
  22. package/dist/runtime/actors/actor-handoff.d.ts +7 -3
  23. package/dist/runtime/actors/actor-handoff.js +212 -88
  24. package/dist/runtime/actors/actor-join-relocation.d.ts +2 -0
  25. package/dist/runtime/actors/actor-local-native-join.js +4 -0
  26. package/dist/runtime/actors/actor-mailbox.js +27 -1
  27. package/dist/runtime/actors/actor-remote-joiner.js +3 -1
  28. package/dist/runtime/actors/actor-reply.d.ts +4 -0
  29. package/dist/runtime/actors/actor-reply.js +29 -0
  30. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
  31. package/dist/runtime/actors/actor-runtime-state.js +2 -20
  32. package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
  33. package/dist/runtime/actors/index.d.ts +6 -2
  34. package/dist/runtime/actors/index.js +37 -21
  35. package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
  36. package/dist/runtime/actors/session-disconnected-wire.js +48 -0
  37. package/dist/runtime/admission.d.ts +9 -1
  38. package/dist/runtime/admission.js +55 -32
  39. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +13 -0
  40. package/dist/runtime/application-jobs/application-job-queue-scope.js +27 -1
  41. package/dist/runtime/application-jobs/contracts.d.ts +2 -0
  42. package/dist/runtime/backend/contracts/index.d.ts +19 -3
  43. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
  44. package/dist/runtime/backend/mesh-completion-table.js +5 -0
  45. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +26 -2
  46. package/dist/runtime/backend/mesh-dispatch-pump.js +193 -107
  47. package/dist/runtime/backend/node/node-raw-binding-port.js +90 -58
  48. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +33 -8
  49. package/dist/runtime/backend/node/node-raw-mesh-backend.js +142 -143
  50. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
  51. package/dist/runtime/backend/node/node-socket-backend-adapter.js +5 -5
  52. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  53. package/dist/runtime/channels/channel-clients.js +20 -5
  54. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +22 -3
  55. package/dist/runtime/channels/channel-dispatch-pipeline.js +103 -57
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +3 -2
  57. package/dist/runtime/channels/channel-dispatchers.js +44 -37
  58. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  59. package/dist/runtime/channels/channel-envelope.js +74 -31
  60. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
  61. package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
  62. package/dist/runtime/channels/channel-runtime-manager.d.ts +3 -2
  63. package/dist/runtime/channels/channel-runtime-manager.js +4 -4
  64. package/dist/runtime/channels/channel-transports.d.ts +0 -1
  65. package/dist/runtime/channels/channel-transports.js +35 -33
  66. package/dist/runtime/channels/client-server-location-runtime.js +5 -4
  67. package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
  68. package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
  69. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  70. package/dist/runtime/channels/fanout-location-runtime.js +3 -3
  71. package/dist/runtime/diagnostics/flow-context.js +19 -7
  72. package/dist/runtime/diagnostics/index.js +4 -9
  73. package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
  74. package/dist/runtime/diagnostics/message-flow.js +35 -5
  75. package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
  76. package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
  77. package/dist/runtime/execution/index.d.ts +4 -2
  78. package/dist/runtime/execution/index.js +33 -10
  79. package/dist/runtime/execution/serial-execution-queue.d.ts +4 -0
  80. package/dist/runtime/execution/serial-execution-queue.js +21 -2
  81. package/dist/runtime/execution/state-lane.d.ts +2 -0
  82. package/dist/runtime/execution/state-lane.js +5 -0
  83. package/dist/runtime/foundation/operation-registry.d.ts +25 -1
  84. package/dist/runtime/foundation/operation-registry.js +86 -18
  85. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +39 -3
  86. package/dist/runtime/foundation/raw-service-mesh-runtime.js +151 -55
  87. package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
  88. package/dist/runtime/foundation/service-liveness-registry.js +38 -0
  89. package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
  90. package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
  91. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -3
  92. package/dist/runtime/foundation/service-relocation-object-owner.js +48 -35
  93. package/dist/runtime/foundation/service-relocation-runtime.js +7 -3
  94. package/dist/runtime/foundation/service-runtime-contracts.d.ts +8 -1
  95. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
  96. package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
  97. package/dist/runtime/foundation/service-stateful-registry.js +24 -26
  98. package/dist/runtime/foundation/service-stateful-runtime.d.ts +72 -6
  99. package/dist/runtime/foundation/service-stateful-runtime.js +444 -117
  100. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -1
  101. package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
  102. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
  103. package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
  104. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  105. package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
  106. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +10 -0
  107. package/dist/runtime/foundation/service-wire-m6a-codec.js +166 -53
  108. package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
  109. package/dist/runtime/host/actor-packet-relay.js +59 -72
  110. package/dist/runtime/host/actor-placement-coordinator.js +25 -8
  111. package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
  112. package/dist/runtime/host/actor-transfer-runtime.js +85 -331
  113. package/dist/runtime/host/application-job-queue.d.ts +24 -3
  114. package/dist/runtime/host/application-job-queue.js +28 -41
  115. package/dist/runtime/host/index.d.ts +5 -1
  116. package/dist/runtime/host/index.js +171 -97
  117. package/dist/runtime/host/location-runtime-owner.js +2 -6
  118. package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
  119. package/dist/runtime/host/mesh-router-resolver.js +14 -6
  120. package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
  121. package/dist/runtime/host/remote-bound-session-relay.js +71 -190
  122. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
  123. package/dist/runtime/host/route-mesh-runtime.js +5 -3
  124. package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
  125. package/dist/runtime/host/runtime-shutdown.js +3 -2
  126. package/dist/runtime/host/service-relocation-host-runtime.d.ts +17 -7
  127. package/dist/runtime/host/service-relocation-host-runtime.js +550 -367
  128. package/dist/runtime/host/spot-runtime-options-factory.js +15 -7
  129. package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
  130. package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
  131. package/dist/runtime/locations/auto-connect-loop.js +22 -14
  132. package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
  133. package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
  134. package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
  135. package/dist/runtime/locations/descriptor-publication.js +11 -0
  136. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  137. package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
  138. package/dist/runtime/locations/in-memory-authority-store.js +56 -19
  139. package/dist/runtime/locations/in-memory-location-store.js +1 -10
  140. package/dist/runtime/locations/index.d.ts +1 -0
  141. package/dist/runtime/locations/index.js +1 -0
  142. package/dist/runtime/locations/lease-tracker.js +1 -6
  143. package/dist/runtime/locations/location-store-repository.d.ts +51 -1
  144. package/dist/runtime/locations/location-store-repository.js +363 -139
  145. package/dist/runtime/locations/relocation-blob.d.ts +18 -1
  146. package/dist/runtime/locations/relocation-blob.js +52 -1
  147. package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
  148. package/dist/runtime/locations/request-source-resolver.js +80 -0
  149. package/dist/runtime/locations/resolvers.js +1 -1
  150. package/dist/runtime/locations/runtime.d.ts +6 -2
  151. package/dist/runtime/locations/runtime.js +37 -30
  152. package/dist/runtime/messaging/payload-codec.d.ts +7 -1
  153. package/dist/runtime/messaging/payload-codec.js +7 -6
  154. package/dist/runtime/messaging/request-result.js +29 -26
  155. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +19 -1
  156. package/dist/runtime/protocol/service_wire_codec.generated.js +85 -0
  157. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +7 -1
  158. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +23 -7
  159. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +3 -2
  160. package/dist/runtime/spots/index.d.ts +18 -11
  161. package/dist/runtime/spots/index.js +234 -176
  162. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  163. package/dist/runtime/spots/spot-activation-registry.js +21 -11
  164. package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
  165. package/dist/runtime/spots/spot-activation-state.js +7 -7
  166. package/dist/runtime/spots/spot-activation.d.ts +6 -3
  167. package/dist/runtime/spots/spot-activation.js +123 -44
  168. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
  169. package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
  170. package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
  171. package/dist/runtime/spots/spot-actor-membership.js +0 -8
  172. package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
  173. package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
  174. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
  175. package/dist/runtime/spots/spot-entry-activation.js +14 -9
  176. package/dist/runtime/spots/spot-handler-registry.d.ts +4 -3
  177. package/dist/runtime/spots/spot-handler-registry.js +6 -2
  178. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
  179. package/dist/runtime/spots/spot-manager-public.js +2 -2
  180. package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
  181. package/dist/runtime/spots/spot-node-autoconnect.js +18 -39
  182. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
  183. package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
  184. package/dist/runtime/spots/spot-outbound.js +3 -3
  185. package/dist/runtime/spots/spot-remote-codec.js +5 -1
  186. package/dist/runtime/spots/spot-runtime-ports.d.ts +0 -1
  187. package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
  188. package/dist/runtime/spots/spot-serial-executor.js +61 -8
  189. package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
  190. package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
  191. package/dist/runtime/spots/spot-timer.d.ts +57 -5
  192. package/dist/runtime/spots/spot-timer.js +287 -103
  193. package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
  194. package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
  195. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
  196. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
  197. package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
  198. package/dist/runtime/streams/bound-session-service.d.ts +1 -1
  199. package/dist/runtime/streams/bound-session-service.js +6 -11
  200. package/dist/runtime/streams/index.d.ts +3 -2
  201. package/dist/runtime/streams/index.js +6 -4
  202. package/dist/runtime/streams/managed-stream.js +3 -2
  203. package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
  204. package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
  205. package/dist/runtime/streams/session-actor-coordinator.js +15 -32
  206. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
  207. package/dist/runtime/streams/stream-session-runtime.js +1 -4
  208. package/dist/runtime/workers/index.js +1 -1
  209. package/package.json +3 -3
  210. package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
  211. package/src/contracts/Common/encoded-payload-storage.ts +6 -3
  212. package/src/contracts/Configuration/Builders.ts +4 -1
  213. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
  214. package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
  215. package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
  216. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
  217. package/src/contracts/Locations/Rows.ts +2 -0
  218. package/src/contracts/Spots/Contracts.ts +8 -0
  219. package/src/contracts/Spots/ZLinkSpot.ts +3 -3
  220. package/src/runtime/abort.ts +12 -0
  221. package/src/runtime/actors/actor-authority-publication.ts +3 -2
  222. package/src/runtime/actors/actor-client.ts +61 -70
  223. package/src/runtime/actors/actor-context.ts +49 -9
  224. package/src/runtime/actors/actor-handoff.ts +282 -106
  225. package/src/runtime/actors/actor-join-relocation.ts +2 -0
  226. package/src/runtime/actors/actor-local-native-join.ts +4 -0
  227. package/src/runtime/actors/actor-mailbox.ts +40 -2
  228. package/src/runtime/actors/actor-remote-joiner.ts +6 -1
  229. package/src/runtime/actors/actor-reply.ts +42 -0
  230. package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
  231. package/src/runtime/actors/actor-runtime-state.ts +2 -20
  232. package/src/runtime/actors/actor-source-transfer.ts +1 -34
  233. package/src/runtime/actors/index.ts +41 -27
  234. package/src/runtime/actors/session-disconnected-wire.ts +66 -0
  235. package/src/runtime/admission.ts +69 -34
  236. package/src/runtime/application-jobs/application-job-queue-scope.ts +33 -1
  237. package/src/runtime/application-jobs/contracts.ts +2 -0
  238. package/src/runtime/backend/contracts/index.ts +39 -4
  239. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
  240. package/src/runtime/backend/mesh-completion-table.ts +4 -0
  241. package/src/runtime/backend/mesh-dispatch-pump.ts +223 -124
  242. package/src/runtime/backend/node/node-raw-binding-port.ts +106 -70
  243. package/src/runtime/backend/node/node-raw-mesh-backend.ts +221 -170
  244. package/src/runtime/backend/node/node-socket-backend-adapter.ts +5 -5
  245. package/src/runtime/channels/channel-clients.ts +49 -24
  246. package/src/runtime/channels/channel-dispatch-pipeline.ts +173 -124
  247. package/src/runtime/channels/channel-dispatchers.ts +116 -72
  248. package/src/runtime/channels/channel-envelope.ts +105 -36
  249. package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
  250. package/src/runtime/channels/channel-runtime-manager.ts +12 -5
  251. package/src/runtime/channels/channel-transports.ts +49 -58
  252. package/src/runtime/channels/client-server-location-runtime.ts +11 -10
  253. package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
  254. package/src/runtime/channels/fanout-location-runtime.ts +17 -9
  255. package/src/runtime/diagnostics/flow-context.ts +20 -7
  256. package/src/runtime/diagnostics/index.ts +1 -7
  257. package/src/runtime/diagnostics/message-flow.ts +47 -9
  258. package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
  259. package/src/runtime/execution/index.ts +40 -14
  260. package/src/runtime/execution/serial-execution-queue.ts +31 -4
  261. package/src/runtime/execution/state-lane.ts +7 -0
  262. package/src/runtime/foundation/operation-registry.ts +98 -20
  263. package/src/runtime/foundation/raw-service-mesh-runtime.ts +244 -67
  264. package/src/runtime/foundation/service-liveness-registry.ts +39 -0
  265. package/src/runtime/foundation/service-mailbox.ts +8 -0
  266. package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
  267. package/src/runtime/foundation/service-relocation-object-owner.ts +54 -37
  268. package/src/runtime/foundation/service-relocation-runtime.ts +7 -3
  269. package/src/runtime/foundation/service-runtime-contracts.ts +12 -1
  270. package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
  271. package/src/runtime/foundation/service-stateful-registry.ts +38 -35
  272. package/src/runtime/foundation/service-stateful-runtime.ts +667 -152
  273. package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -11
  274. package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
  275. package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
  276. package/src/runtime/foundation/service-wire-m6a-codec.ts +187 -51
  277. package/src/runtime/host/actor-packet-relay.ts +113 -94
  278. package/src/runtime/host/actor-placement-coordinator.ts +31 -8
  279. package/src/runtime/host/actor-transfer-runtime.ts +104 -430
  280. package/src/runtime/host/application-job-queue.ts +29 -44
  281. package/src/runtime/host/index.ts +286 -129
  282. package/src/runtime/host/location-runtime-owner.ts +2 -6
  283. package/src/runtime/host/mesh-router-resolver.ts +13 -5
  284. package/src/runtime/host/remote-bound-session-relay.ts +86 -248
  285. package/src/runtime/host/route-mesh-runtime.ts +11 -5
  286. package/src/runtime/host/runtime-shutdown.ts +15 -4
  287. package/src/runtime/host/service-relocation-host-runtime.ts +784 -475
  288. package/src/runtime/host/spot-runtime-options-factory.ts +18 -7
  289. package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
  290. package/src/runtime/locations/auto-connect-loop.ts +22 -14
  291. package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
  292. package/src/runtime/locations/auto-connect-types.ts +0 -1
  293. package/src/runtime/locations/descriptor-publication.ts +7 -0
  294. package/src/runtime/locations/domain-store-contract.ts +5 -0
  295. package/src/runtime/locations/in-memory-authority-store.ts +85 -23
  296. package/src/runtime/locations/in-memory-location-store.ts +1 -12
  297. package/src/runtime/locations/index.ts +1 -0
  298. package/src/runtime/locations/lease-tracker.ts +2 -9
  299. package/src/runtime/locations/location-store-repository.ts +628 -152
  300. package/src/runtime/locations/relocation-blob.ts +75 -1
  301. package/src/runtime/locations/request-source-resolver.ts +138 -0
  302. package/src/runtime/locations/resolvers.ts +2 -2
  303. package/src/runtime/locations/runtime.ts +70 -40
  304. package/src/runtime/messaging/payload-codec.ts +8 -11
  305. package/src/runtime/messaging/request-result.ts +33 -29
  306. package/src/runtime/protocol/service_wire_codec.generated.ts +87 -4
  307. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +13 -10
  308. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +3 -2
  309. package/src/runtime/spots/index.ts +375 -281
  310. package/src/runtime/spots/spot-activation-registry.ts +25 -13
  311. package/src/runtime/spots/spot-activation-state.ts +12 -19
  312. package/src/runtime/spots/spot-activation.ts +170 -86
  313. package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
  314. package/src/runtime/spots/spot-actor-membership.ts +0 -15
  315. package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
  316. package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
  317. package/src/runtime/spots/spot-entry-activation.ts +24 -19
  318. package/src/runtime/spots/spot-handler-registry.ts +15 -4
  319. package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
  320. package/src/runtime/spots/spot-manager-public.ts +2 -2
  321. package/src/runtime/spots/spot-node-autoconnect.ts +22 -45
  322. package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
  323. package/src/runtime/spots/spot-outbound.ts +3 -3
  324. package/src/runtime/spots/spot-remote-codec.ts +9 -2
  325. package/src/runtime/spots/spot-runtime-ports.ts +0 -1
  326. package/src/runtime/spots/spot-serial-executor.ts +97 -25
  327. package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
  328. package/src/runtime/spots/spot-subscription-dispatch.ts +1 -1
  329. package/src/runtime/spots/spot-timer.ts +413 -157
  330. package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
  331. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
  332. package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
  333. package/src/runtime/streams/bound-session-service.ts +7 -10
  334. package/src/runtime/streams/index.ts +12 -6
  335. package/src/runtime/streams/managed-stream.ts +4 -2
  336. package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
  337. package/src/runtime/streams/session-actor-coordinator.ts +39 -88
  338. package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
  339. package/src/runtime/streams/stream-session-runtime.ts +1 -5
  340. package/src/runtime/workers/index.ts +1 -1
@@ -27,6 +27,12 @@ export interface ZLinkTimerRelocationState {
27
27
  readonly nextDueAtUnixMs: number;
28
28
  readonly pendingTicks: readonly ZLinkTimerRelocationPendingTick[];
29
29
  }
30
+ export interface ZLinkManagedTimerStart {
31
+ /** Created paused; the owner starts it with `resume()`. */
32
+ readonly paused?: boolean;
33
+ /** Relocated logical schedule the timer continues from. */
34
+ readonly cursor?: ZLinkTimerRelocationState;
35
+ }
30
36
  export interface ZLinkTimerRelocationPendingTick {
31
37
  readonly deliveryIndex: bigint;
32
38
  readonly scheduledIndex: bigint;
@@ -44,23 +50,58 @@ export declare class ZLinkSpotTimerRegistry {
44
50
  private readonly timers;
45
51
  private readonly generations;
46
52
  private executionBarrier;
53
+ /** Frozen from the source capture or the target restore until abort or Ready. */
54
+ private frozen;
55
+ /**
56
+ * The lifecycle owner opens this window around the target's Configure and
57
+ * pre-Ready OnInitialize only (Spot timer §1). A registration captures it at
58
+ * the call, so a registration started inside the window reattaches a
59
+ * restored key even when its asynchronous part finishes after the window.
60
+ */
61
+ private initializing;
62
+ /**
63
+ * Handler constructors the target Spot announced with `addTimer(...)` during
64
+ * Configure. Together with `handlers.addTimerHandler(...)` they form the
65
+ * table that resolves a restored timer's handler by name.
66
+ */
67
+ private readonly configureTimerHandlers;
68
+ private relocationHandlersResolved;
47
69
  constructor(_metrics?: import('../diagnostics').ZLinkRuntimeMetrics, flowCreationEnabled?: () => boolean, executionSerialForTimer?: ((name: string, fallback: ZLinkSpotSerialTurnExecutor) => ZLinkSpotSerialTurnExecutor) | undefined, executionAllowed?: () => boolean, executeTimer?: (<T>(name: string, operation: () => Promise<T> | T) => Promise<T>) | undefined, isTimerExecuting?: ((name: string) => boolean) | undefined, clock?: ZLinkTimerClock | undefined);
48
70
  setExecutionBarrier(barrier: ZLinkExecutionBarrier): void;
49
71
  get hasActiveTimers(): boolean;
50
72
  add<TSpot extends ZLinkTimerOwnerSpot, THandler extends ZLinkSpotTimerHandler<TSpot>>(name: string, periodMs: number, options: ZLinkTimerOptions | undefined, handlerType: Type<THandler>, serial: ZLinkSpotSerialTurnExecutor, spot: TSpot, providerResolver?: ZLinkProviderResolver, signal?: AbortSignal, reportFailure?: ZLinkTimerFailureReporter): Promise<ZLinkTimer>;
73
+ /**
74
+ * Stages the source payload on a fresh relocation target before Configure.
75
+ * The restored registrations keep their schedule and stay frozen until Ready.
76
+ */
77
+ stageRelocation(states: readonly ZLinkTimerRelocationState[]): void;
78
+ /** Runs one relocation-target initialization callback inside the reattach window. */
79
+ runRelocationInitialization<T>(operation: () => Promise<T> | T): Promise<T>;
80
+ /**
81
+ * After Configure, resolves every restored timer's handler constructor by
82
+ * name among the constructors the Spot announced in Configure: `addTimer(...)`
83
+ * there or `handlers.addTimerHandler(...)`. A restored key that Configure did
84
+ * not reattach is registered with the resolved constructor so it survives
85
+ * Ready without re-registration. No match or more than one match fails the
86
+ * target restore.
87
+ */
88
+ resolveRelocationHandlers(declared: readonly Type[], register: (name: string, periodMs: number, handlerType: Type) => Promise<unknown>): Promise<void>;
89
+ /** Ready: starts the restored and newly registered timers. */
90
+ publishRelocation(): Promise<void>;
51
91
  dispose(): Promise<void>;
52
92
  captureRelocation(): Promise<readonly ZLinkTimerRelocationState[]>;
53
- restoreRelocation(states: readonly ZLinkTimerRelocationState[]): void;
54
- abortRelocation(states: readonly ZLinkTimerRelocationState[]): void;
93
+ /** Source abort: the captured timers continue from their own unchanged cursor. */
94
+ abortRelocation(): void;
55
95
  commitRelocation(): Promise<void>;
56
96
  cancel(name: string, generation: bigint, timer: ZLinkManagedTimer, signal?: AbortSignal): Promise<void>;
97
+ private createTimer;
57
98
  private prepareAddCore;
58
99
  private completeAddCore;
59
100
  private cancelCore;
60
101
  }
61
102
  export declare class ZLinkManagedTimer implements ZLinkTimer {
62
103
  private readonly name;
63
- private readonly periodMs;
104
+ readonly periodMs: number;
64
105
  private readonly options;
65
106
  private readonly onTick;
66
107
  private readonly onFailure?;
@@ -71,24 +112,35 @@ export declare class ZLinkManagedTimer implements ZLinkTimer {
71
112
  private pausedForRelocation;
72
113
  private startedAtMs;
73
114
  private startedAtUnixMs;
115
+ /** DeliveryIndex and ScheduledIndex of the last completed tick. */
74
116
  private deliveryIndex;
75
117
  private lastScheduledIndex;
118
+ /**
119
+ * The selected tick whose callback has not completed (Spot timer §1). It is
120
+ * the only pending tick a relocation captures, and a restored timer delivers
121
+ * it before it selects another tick.
122
+ */
123
+ private pendingScheduledIndex;
76
124
  private timeout;
125
+ /** The dispatch in flight, from its timer callback until `completeFireCore`. */
77
126
  private running;
78
127
  private dispatchFailure;
79
128
  private finalization;
80
- constructor(name: string, periodMs: number, options: Required<ZLinkTimerOptions>, onTick: (tick: ZLinkTimerTick) => Promise<void>, onFailure?: ZLinkTimerFailureReporter | undefined, shouldWaitForRunningOnCancel?: () => boolean, clock?: ZLinkTimerClock);
129
+ constructor(name: string, periodMs: number, options: Required<ZLinkTimerOptions>, onTick: (tick: ZLinkTimerTick) => Promise<void>, onFailure?: ZLinkTimerFailureReporter | undefined, shouldWaitForRunningOnCancel?: () => boolean, clock?: ZLinkTimerClock, start?: ZLinkManagedTimerStart);
81
130
  get isDisposed(): boolean;
82
131
  cancel(_signal?: AbortSignal): Promise<void>;
83
132
  dispose(): Promise<void>;
84
133
  captureRelocation(handlerType?: string): Promise<ZLinkTimerRelocationState>;
85
- restoreRelocation(state: ZLinkTimerRelocationState, handlerType?: string): void;
134
+ /** Starts a timer created paused, or continues one paused by a relocation capture. */
135
+ resume(): void;
86
136
  private scheduleNext;
87
137
  private fire;
88
138
  private cancelCore;
89
139
  private completeFinalization;
90
140
  private prepareCaptureCore;
91
141
  private prepareFireCore;
142
+ /** The tick info of the pending tick at `scheduledIndex` after the completed cursor. */
143
+ private pendingTick;
92
144
  private completeFireCore;
93
145
  private selectScheduledIndex;
94
146
  private elapsedMs;
@@ -8,11 +8,10 @@ const internal_event_contracts_1 = require("../diagnostics/internal-event-contra
8
8
  const contracts_1 = require("../../contracts");
9
9
  const TimerRegistrationValidator_1 = require("../../contracts/Configuration/TimerRegistrationValidator");
10
10
  const abort_1 = require("../abort");
11
+ const framework_errors_internal_1 = require("../framework-errors-internal");
11
12
  const handler_instance_scope_1 = require("../handlers/handler-instance-scope");
12
13
  const flow_context_1 = require("../diagnostics/flow-context");
13
14
  const state_lane_1 = require("../execution/state-lane");
14
- const node_async_hooks_1 = require("node:async_hooks");
15
- const detachedTimerStateLaneResource = new node_async_hooks_1.AsyncResource('zlink:spot-timer');
16
15
  const systemTimerClock = {
17
16
  now: () => performance.now(),
18
17
  utcNow: () => Date.now(),
@@ -30,6 +29,22 @@ class ZLinkSpotTimerRegistry {
30
29
  timers = new Map();
31
30
  generations = new Map();
32
31
  executionBarrier;
32
+ /** Frozen from the source capture or the target restore until abort or Ready. */
33
+ frozen = false;
34
+ /**
35
+ * The lifecycle owner opens this window around the target's Configure and
36
+ * pre-Ready OnInitialize only (Spot timer §1). A registration captures it at
37
+ * the call, so a registration started inside the window reattaches a
38
+ * restored key even when its asynchronous part finishes after the window.
39
+ */
40
+ initializing = false;
41
+ /**
42
+ * Handler constructors the target Spot announced with `addTimer(...)` during
43
+ * Configure. Together with `handlers.addTimerHandler(...)` they form the
44
+ * table that resolves a restored timer's handler by name.
45
+ */
46
+ configureTimerHandlers = new Set();
47
+ relocationHandlersResolved = false;
33
48
  constructor(_metrics, flowCreationEnabled = () => true, executionSerialForTimer, executionAllowed = () => true, executeTimer, isTimerExecuting, clock) {
34
49
  this.flowCreationEnabled = flowCreationEnabled;
35
50
  this.executionSerialForTimer = executionSerialForTimer;
@@ -49,44 +64,135 @@ class ZLinkSpotTimerRegistry {
49
64
  }
50
65
  async add(name, periodMs, options, handlerType, serial, spot, providerResolver, signal, reportFailure) {
51
66
  (0, TimerRegistrationValidator_1.validateTimerRegistration)(name, periodMs, options);
67
+ const initializing = this.initializing;
68
+ if (initializing && !this.relocationHandlersResolved) {
69
+ this.configureTimerHandlers.add(handlerType);
70
+ }
52
71
  (0, abort_1.throwIfAborted)(signal);
53
72
  (0, handler_instance_scope_1.prepareHandlerInstance)(providerResolver, handlerType);
54
73
  const handler = await (0, handler_instance_scope_1.resolveLifecycleHandler)(spot, handlerType, providerResolver);
55
- const prepared = await this.lane.run(() => this.prepareAddCore(name));
56
- if (prepared.previous !== undefined)
57
- await prepared.previous.timer.cancel(signal);
58
74
  const executionSerial = this.executeTimer === undefined
59
75
  ? (this.executionSerialForTimer?.(name, serial) ?? serial)
60
76
  : undefined;
61
77
  if (this.executionBarrier !== undefined)
62
78
  executionSerial?.setExecutionBarrier(this.executionBarrier);
63
- let callbackStarted = false;
64
- const timer = startOutsideStateLane(() => new ZLinkManagedTimer(name, periodMs, normalizeTimerOptions(options), async (tick) => {
65
- callbackStarted = false;
66
- const timerFlow = (0, flow_context_1.createInboundFlow)(undefined, 'Timer', this.flowCreationEnabled(), undefined);
67
- const operation = () => {
68
- const current = this.timers.get(name);
69
- if (current === undefined ||
70
- current.generation !== prepared.generation ||
71
- current.timer !== timer) {
72
- return undefined;
73
- }
74
- if (!this.executionAllowed())
75
- return undefined;
76
- callbackStarted = true;
77
- return (0, flow_context_1.runWithFlow)(timerFlow, () => handler.handle(spot, tick));
79
+ const binding = {
80
+ handler: handler,
81
+ spot,
82
+ executionSerial,
83
+ reportFailure
84
+ };
85
+ const prepared = await this.lane.run(() => this.prepareAddCore(name, handlerType.name, initializing, binding));
86
+ if (prepared.kind === 'reattached')
87
+ return prepared.handle;
88
+ if (prepared.previous !== undefined)
89
+ await prepared.previous.timer.cancel(signal);
90
+ const slot = { binding };
91
+ const timer = this.createTimer(name, prepared.generation, periodMs, options, slot);
92
+ const handle = new ZLinkRegisteredTimer(this, name, prepared.generation, timer);
93
+ const registered = await this.lane.run(() => this.completeAddCore(name, {
94
+ generation: prepared.generation,
95
+ handlerType: handlerType.name,
96
+ timer,
97
+ handle,
98
+ restored: false,
99
+ slot
100
+ }));
101
+ if (!registered)
102
+ await timer.cancel(signal);
103
+ return handle;
104
+ }
105
+ /**
106
+ * Stages the source payload on a fresh relocation target before Configure.
107
+ * The restored registrations keep their schedule and stay frozen until Ready.
108
+ */
109
+ stageRelocation(states) {
110
+ if (this.frozen || this.timers.size !== 0) {
111
+ throw new Error('Timer relocation can only be restored into a fresh registry.');
112
+ }
113
+ const restored = states.map((state) => {
114
+ if (states.some((other) => other !== state && other.name === state.name)) {
115
+ throw new Error(`Timer '${state.name}' appears twice in relocation state.`);
116
+ }
117
+ const options = {
118
+ overrunPolicy: state.overrunPolicy,
119
+ maxCatchUpTicks: state.maxCatchUpTicks,
120
+ stopOnUnhandledException: state.stopOnUnhandledException
78
121
  };
79
- if (this.executeTimer !== undefined) {
80
- await this.executeTimer(name, operation);
122
+ (0, TimerRegistrationValidator_1.validateTimerRegistration)(state.name, state.periodMs, options);
123
+ const slot = { binding: undefined };
124
+ const timer = this.createTimer(state.name, 1n, state.periodMs, options, slot, state);
125
+ return [
126
+ state.name,
127
+ {
128
+ generation: 1n,
129
+ handlerType: state.handlerType,
130
+ timer,
131
+ handle: new ZLinkRegisteredTimer(this, state.name, 1n, timer),
132
+ restored: true,
133
+ slot
134
+ }
135
+ ];
136
+ });
137
+ this.frozen = true;
138
+ for (const [name, entry] of restored) {
139
+ this.generations.set(name, entry.generation);
140
+ this.timers.set(name, entry);
141
+ }
142
+ }
143
+ /** Runs one relocation-target initialization callback inside the reattach window. */
144
+ async runRelocationInitialization(operation) {
145
+ if (!this.frozen || this.initializing) {
146
+ throw new Error('Timer relocation initialization is not active.');
147
+ }
148
+ this.initializing = true;
149
+ try {
150
+ return await operation();
151
+ }
152
+ finally {
153
+ this.initializing = false;
154
+ }
155
+ }
156
+ /**
157
+ * After Configure, resolves every restored timer's handler constructor by
158
+ * name among the constructors the Spot announced in Configure: `addTimer(...)`
159
+ * there or `handlers.addTimerHandler(...)`. A restored key that Configure did
160
+ * not reattach is registered with the resolved constructor so it survives
161
+ * Ready without re-registration. No match or more than one match fails the
162
+ * target restore.
163
+ */
164
+ async resolveRelocationHandlers(declared, register) {
165
+ if (!this.frozen || !this.initializing || this.relocationHandlersResolved) {
166
+ throw new Error('Timer relocation handler resolution is not active.');
167
+ }
168
+ this.relocationHandlersResolved = true;
169
+ const constructors = [...new Set([...declared, ...this.configureTimerHandlers])];
170
+ const restored = await this.lane.run(() => [...this.timers.entries()].filter(([, entry]) => entry.restored));
171
+ for (const [name, entry] of restored) {
172
+ const matches = constructors.filter((type) => type.name === entry.handlerType);
173
+ if (matches.length !== 1) {
174
+ throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RelocationFailed, matches.length === 0
175
+ ? `Timer '${name}' handler '${entry.handlerType}' is not declared. Register its timer with context.addTimer(...) in configure(), or declare it with context.handlers.addTimerHandler(Handler) in configure().`
176
+ : `Timer '${name}' handler '${entry.handlerType}' is ambiguous: ${matches.length} declared constructors share the name.`);
81
177
  }
82
- else {
83
- await executionSerial.execute(operation);
178
+ if (entry.slot.binding === undefined) {
179
+ await register(name, entry.timer.periodMs, matches[0]);
84
180
  }
85
- }, reportFailure, () => callbackStarted, this.clock));
86
- const registered = await this.lane.run(() => this.completeAddCore(name, prepared.generation, handlerType.name, timer));
87
- if (!registered)
88
- await timer.cancel(signal);
89
- return new ZLinkRegisteredTimer(this, name, prepared.generation, timer);
181
+ }
182
+ }
183
+ /** Ready: starts the restored and newly registered timers. */
184
+ async publishRelocation() {
185
+ await this.lane.run(() => {
186
+ for (const [name, entry] of this.timers) {
187
+ if (entry.slot.binding === undefined) {
188
+ throw new Error(`Restored timer '${name}' has no resolved handler at Ready.`);
189
+ }
190
+ }
191
+ this.frozen = false;
192
+ for (const entry of this.timers.values()) {
193
+ (0, state_lane_1.startOutsideStateLane)(() => entry.timer.resume());
194
+ }
195
+ });
90
196
  }
91
197
  async dispose() {
92
198
  const timers = await this.lane.run(() => {
@@ -102,7 +208,10 @@ class ZLinkSpotTimerRegistry {
102
208
  await Promise.all(finalizations.filter((_, index) => timers[index].wait));
103
209
  }
104
210
  async captureRelocation() {
105
- const timers = await this.lane.run(() => [...this.timers.entries()].sort(([left], [right]) => left.localeCompare(right)));
211
+ const timers = await this.lane.run(() => {
212
+ this.frozen = true;
213
+ return [...this.timers.entries()].sort(([left], [right]) => left.localeCompare(right));
214
+ });
106
215
  const states = [];
107
216
  for (const [name, entry] of timers) {
108
217
  const state = await entry.timer.captureRelocation(entry.handlerType);
@@ -112,21 +221,12 @@ class ZLinkSpotTimerRegistry {
112
221
  }
113
222
  return states;
114
223
  }
115
- restoreRelocation(states) {
116
- const byName = new Map(states.map((state) => [state.name, state]));
117
- if (byName.size !== states.length || byName.size !== this.timers.size) {
118
- throw new Error('Timer relocation inventory does not match registered handlers.');
224
+ /** Source abort: the captured timers continue from their own unchanged cursor. */
225
+ abortRelocation() {
226
+ this.frozen = false;
227
+ for (const entry of this.timers.values()) {
228
+ (0, state_lane_1.startOutsideStateLane)(() => entry.timer.resume());
119
229
  }
120
- for (const [name, entry] of this.timers) {
121
- const state = byName.get(name);
122
- if (state === undefined) {
123
- throw new Error(`Timer '${name}' is missing from relocation state.`);
124
- }
125
- entry.timer.restoreRelocation(state, entry.handlerType);
126
- }
127
- }
128
- abortRelocation(states) {
129
- this.restoreRelocation(states);
130
230
  }
131
231
  async commitRelocation() {
132
232
  await this.dispose();
@@ -136,17 +236,58 @@ class ZLinkSpotTimerRegistry {
136
236
  await this.lane.run(() => this.cancelCore(name, generation, timer));
137
237
  await timer.cancel(signal);
138
238
  }
139
- prepareAddCore(name) {
239
+ createTimer(name, generation, periodMs, options, slot, cursor) {
240
+ let callbackStarted = false;
241
+ const timer = (0, state_lane_1.startOutsideStateLane)(() => new ZLinkManagedTimer(name, periodMs, normalizeTimerOptions(options), async (tick) => {
242
+ callbackStarted = false;
243
+ const binding = slot.binding;
244
+ if (binding === undefined)
245
+ return;
246
+ const timerFlow = (0, flow_context_1.createInboundFlow)(undefined, 'Timer', this.flowCreationEnabled(), undefined);
247
+ const operation = () => {
248
+ const current = this.timers.get(name);
249
+ if (current === undefined ||
250
+ current.generation !== generation ||
251
+ current.timer !== timer) {
252
+ return undefined;
253
+ }
254
+ if (!this.executionAllowed())
255
+ return undefined;
256
+ callbackStarted = true;
257
+ return (0, flow_context_1.runWithFlow)(timerFlow, () => binding.handler.handle(binding.spot, tick));
258
+ };
259
+ if (this.executeTimer !== undefined) {
260
+ await this.executeTimer(name, operation);
261
+ }
262
+ else {
263
+ await binding.executionSerial.execute(operation);
264
+ }
265
+ }, (tick, cause, event) => slot.binding?.reportFailure?.(tick, cause, event), () => callbackStarted, this.clock, { paused: true, cursor }));
266
+ return timer;
267
+ }
268
+ prepareAddCore(name, handlerType, initializing, binding) {
269
+ if (this.frozen && !initializing) {
270
+ throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.InvalidOperation, `Timer '${name}' registration is sealed for relocation.`);
271
+ }
140
272
  const previous = this.timers.get(name);
273
+ if (initializing && previous?.restored === true) {
274
+ if (previous.handlerType !== handlerType) {
275
+ throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.InvalidOperation, `Timer '${name}' was restored with handler '${previous.handlerType}', not '${handlerType}'.`);
276
+ }
277
+ previous.slot.binding = binding;
278
+ return { kind: 'reattached', handle: previous.handle };
279
+ }
141
280
  this.timers.delete(name);
142
281
  const generation = (this.generations.get(name) ?? 0n) + 1n;
143
282
  this.generations.set(name, generation);
144
- return { previous, generation };
283
+ return { kind: 'registered', previous, generation };
145
284
  }
146
- completeAddCore(name, generation, handlerType, timer) {
147
- if (this.generations.get(name) !== generation)
285
+ completeAddCore(name, entry) {
286
+ if (this.generations.get(name) !== entry.generation)
148
287
  return false;
149
- this.timers.set(name, { generation, handlerType, timer });
288
+ this.timers.set(name, entry);
289
+ if (!this.frozen)
290
+ (0, state_lane_1.startOutsideStateLane)(() => entry.timer.resume());
150
291
  return true;
151
292
  }
152
293
  cancelCore(name, generation, timer) {
@@ -201,13 +342,21 @@ class ZLinkManagedTimer {
201
342
  pausedForRelocation = false;
202
343
  startedAtMs;
203
344
  startedAtUnixMs;
345
+ /** DeliveryIndex and ScheduledIndex of the last completed tick. */
204
346
  deliveryIndex = 0n;
205
347
  lastScheduledIndex = 0n;
348
+ /**
349
+ * The selected tick whose callback has not completed (Spot timer §1). It is
350
+ * the only pending tick a relocation captures, and a restored timer delivers
351
+ * it before it selects another tick.
352
+ */
353
+ pendingScheduledIndex;
206
354
  timeout;
207
- running = Promise.resolve();
355
+ /** The dispatch in flight, from its timer callback until `completeFireCore`. */
356
+ running;
208
357
  dispatchFailure;
209
358
  finalization;
210
- constructor(name, periodMs, options, onTick, onFailure, shouldWaitForRunningOnCancel = () => true, clock = systemTimerClock) {
359
+ constructor(name, periodMs, options, onTick, onFailure, shouldWaitForRunningOnCancel = () => true, clock = systemTimerClock, start = {}) {
211
360
  this.name = name;
212
361
  this.periodMs = periodMs;
213
362
  this.options = options;
@@ -215,8 +364,20 @@ class ZLinkManagedTimer {
215
364
  this.onFailure = onFailure;
216
365
  this.shouldWaitForRunningOnCancel = shouldWaitForRunningOnCancel;
217
366
  this.clock = clock;
218
- this.startedAtMs = clock.now();
219
- this.startedAtUnixMs = clock.utcNow();
367
+ const cursor = start.cursor;
368
+ if (cursor === undefined) {
369
+ this.startedAtMs = clock.now();
370
+ this.startedAtUnixMs = clock.utcNow();
371
+ }
372
+ else {
373
+ validateRelocationCursor(name, periodMs, cursor);
374
+ this.startedAtUnixMs = cursor.startedAtUnixMs;
375
+ this.startedAtMs = clock.now() - Math.max(0, clock.utcNow() - cursor.startedAtUnixMs);
376
+ this.deliveryIndex = cursor.deliveryIndex;
377
+ this.lastScheduledIndex = cursor.lastScheduledIndex;
378
+ this.pendingScheduledIndex = cursor.pendingTicks[0]?.scheduledIndex;
379
+ }
380
+ this.pausedForRelocation = start.paused === true;
220
381
  this.scheduleNext();
221
382
  }
222
383
  get isDisposed() {
@@ -261,51 +422,34 @@ class ZLinkManagedTimer {
261
422
  deliveryIndex: this.deliveryIndex,
262
423
  lastScheduledIndex: this.lastScheduledIndex,
263
424
  nextDueAtUnixMs: this.startedAtUnixMs + Number(this.lastScheduledIndex + 1n) * this.periodMs,
264
- pendingTicks: []
425
+ pendingTicks: this.pendingScheduledIndex === undefined
426
+ ? []
427
+ : [this.pendingTick(this.pendingScheduledIndex)]
265
428
  }));
266
429
  }
267
- restoreRelocation(state, handlerType = '') {
268
- if (this.disposed)
269
- throw new Error(`Timer '${this.name}' is disposed.`);
270
- if (state.name !== this.name ||
271
- state.handlerType !== handlerType ||
272
- state.periodMs !== this.periodMs ||
273
- state.overrunPolicy !== this.options.overrunPolicy ||
274
- state.maxCatchUpTicks !== this.options.maxCatchUpTicks ||
275
- state.stopOnUnhandledException !== this.options.stopOnUnhandledException ||
276
- !Number.isSafeInteger(state.startedAtUnixMs) ||
277
- state.deliveryIndex < 0n ||
278
- state.lastScheduledIndex < 0n ||
279
- !Number.isSafeInteger(state.nextDueAtUnixMs) ||
280
- state.nextDueAtUnixMs !==
281
- state.startedAtUnixMs + Number(state.lastScheduledIndex + 1n) * state.periodMs ||
282
- state.pendingTicks.length !== 0) {
283
- throw new Error(`Timer '${this.name}' relocation contract does not match its registration.`);
284
- }
285
- if (this.timeout !== undefined)
286
- this.clock.clearTimeout(this.timeout);
287
- this.timeout = undefined;
288
- this.startedAtUnixMs = state.startedAtUnixMs;
289
- this.startedAtMs = this.clock.now() - Math.max(0, this.clock.utcNow() - state.startedAtUnixMs);
290
- this.deliveryIndex = state.deliveryIndex;
291
- this.lastScheduledIndex = state.lastScheduledIndex;
430
+ /** Starts a timer created paused, or continues one paused by a relocation capture. */
431
+ resume() {
432
+ if (this.disposed || !this.pausedForRelocation)
433
+ return;
292
434
  this.pausedForRelocation = false;
293
435
  this.scheduleNext();
294
436
  }
295
437
  scheduleNext() {
296
- if (this.disposed || this.pausedForRelocation) {
438
+ // The dispatch in flight schedules the next tick when it completes.
439
+ if (this.disposed || this.pausedForRelocation || this.running !== undefined) {
297
440
  return;
298
441
  }
299
- const delayMs = this.options.overrunPolicy === contracts_1.ZLinkTimerOverrunPolicy.DelayNextTick
300
- ? this.periodMs
301
- : Math.max(0, Number(this.lastScheduledIndex + 1n) * this.periodMs - this.elapsedMs());
302
- this.timeout = this.clock.setTimeout(() => {
442
+ const delayMs = this.pendingScheduledIndex !== undefined
443
+ ? 0
444
+ : this.options.overrunPolicy === contracts_1.ZLinkTimerOverrunPolicy.DelayNextTick
445
+ ? this.periodMs
446
+ : Math.max(0, Number(this.lastScheduledIndex + 1n) * this.periodMs - this.elapsedMs());
447
+ this.timeout = (0, state_lane_1.startOutsideStateLane)(() => this.clock.setTimeout(() => {
303
448
  this.timeout = undefined;
304
- const execution = startOutsideStateLane(() => this.fire());
305
- this.running = execution.then(() => undefined, (cause) => this.lane.run(() => {
449
+ this.running = this.fire().then(() => undefined, (cause) => this.lane.run(() => {
306
450
  this.dispatchFailure ??= { cause };
307
451
  }));
308
- }, delayMs);
452
+ }, delayMs));
309
453
  }
310
454
  async fire() {
311
455
  const prepared = await this.lane.run(() => this.prepareFireCore());
@@ -316,12 +460,18 @@ class ZLinkManagedTimer {
316
460
  await this.onTick(prepared.tick);
317
461
  }
318
462
  catch (cause) {
463
+ // A tick whose callback had not started when a relocation captured it
464
+ // belongs to the capture: the target delivers it, so the source neither
465
+ // reports nor completes it.
466
+ const started = this.shouldWaitForRunningOnCancel();
467
+ if (!started && (await this.lane.run(() => this.pausedForRelocation)))
468
+ return;
319
469
  shouldContinue = !this.options.stopOnUnhandledException;
320
470
  await this.onFailure?.(prepared.tick, cause, shouldContinue
321
471
  ? internal_event_contracts_1.ZLinkSpotEventKind.TimerHandlerFailed
322
472
  : internal_event_contracts_1.ZLinkSpotEventKind.TimerStoppedAfterUnhandledException);
323
473
  }
324
- await this.lane.run(() => this.completeFireCore(prepared.scheduledIndex, shouldContinue));
474
+ await this.lane.run(() => this.completeFireCore(shouldContinue));
325
475
  }
326
476
  cancelCore() {
327
477
  this.disposed = true;
@@ -329,7 +479,7 @@ class ZLinkManagedTimer {
329
479
  this.timeout = undefined;
330
480
  return {
331
481
  timeout,
332
- running: this.shouldWaitForRunningOnCancel() ? this.running : Promise.resolve()
482
+ running: this.shouldWaitForRunningOnCancel() ? this.running : undefined
333
483
  };
334
484
  }
335
485
  async completeFinalization(start, finalization) {
@@ -369,34 +519,39 @@ class ZLinkManagedTimer {
369
519
  this.clock.clearTimeout(this.timeout);
370
520
  this.timeout = undefined;
371
521
  }
372
- return { running: this.shouldWaitForRunningOnCancel() ? this.running : Promise.resolve() };
522
+ return { running: this.shouldWaitForRunningOnCancel() ? this.running : undefined };
373
523
  }
374
524
  prepareFireCore() {
375
525
  if (this.disposed)
376
526
  return undefined;
377
- const scheduledIndex = this.selectScheduledIndex();
378
- const skippedTicks = scheduledIndex - this.lastScheduledIndex - 1n;
527
+ this.pendingScheduledIndex ??= this.selectScheduledIndex();
528
+ const pending = this.pendingTick(this.pendingScheduledIndex);
379
529
  const startedElapsedMs = this.elapsedMs();
380
- const scheduledElapsedMs = Number(scheduledIndex) * this.periodMs;
381
- this.deliveryIndex += 1n;
530
+ const scheduledElapsedMs = Number(pending.scheduledIndex) * this.periodMs;
382
531
  return {
383
- scheduledIndex,
384
532
  tick: {
385
533
  name: this.name,
386
- deliveryIndex: this.deliveryIndex,
387
- scheduledIndex,
534
+ deliveryIndex: pending.deliveryIndex,
535
+ scheduledIndex: pending.scheduledIndex,
388
536
  periodMs: this.periodMs,
389
- scheduledAt: new Date(this.startedAtUnixMs + scheduledElapsedMs),
537
+ scheduledAt: new Date(pending.scheduledAtUnixMs),
390
538
  startedAt: new Date(this.clock.utcNow()),
391
539
  scheduledElapsedMs,
392
540
  startedElapsedMs,
393
541
  delayMs: startedElapsedMs - scheduledElapsedMs,
394
- skippedTicks
542
+ skippedTicks: pending.skippedTicks
395
543
  }
396
544
  };
397
545
  }
398
- completeFireCore(scheduledIndex, shouldContinue) {
399
- this.lastScheduledIndex = scheduledIndex;
546
+ /** The tick info of the pending tick at `scheduledIndex` after the completed cursor. */
547
+ pendingTick(scheduledIndex) {
548
+ return relocationPendingTick(this.startedAtUnixMs, this.periodMs, this.deliveryIndex, this.lastScheduledIndex, scheduledIndex);
549
+ }
550
+ completeFireCore(shouldContinue) {
551
+ this.deliveryIndex += 1n;
552
+ this.lastScheduledIndex = this.pendingScheduledIndex;
553
+ this.pendingScheduledIndex = undefined;
554
+ this.running = undefined;
400
555
  if (!shouldContinue) {
401
556
  this.disposed = true;
402
557
  return;
@@ -428,8 +583,37 @@ class ZLinkManagedTimer {
428
583
  }
429
584
  }
430
585
  exports.ZLinkManagedTimer = ZLinkManagedTimer;
431
- function startOutsideStateLane(work) {
432
- return detachedTimerStateLaneResource.runInAsyncScope(work);
586
+ function validateRelocationCursor(name, periodMs, state) {
587
+ if (state.name !== name ||
588
+ state.periodMs !== periodMs ||
589
+ !Number.isSafeInteger(state.startedAtUnixMs) ||
590
+ state.deliveryIndex < 0n ||
591
+ state.lastScheduledIndex < 0n ||
592
+ !Number.isSafeInteger(state.nextDueAtUnixMs) ||
593
+ state.nextDueAtUnixMs !==
594
+ state.startedAtUnixMs + Number(state.lastScheduledIndex + 1n) * state.periodMs ||
595
+ state.pendingTicks.length > 1 ||
596
+ state.pendingTicks.some((pending) => {
597
+ const expected = relocationPendingTick(state.startedAtUnixMs, state.periodMs, state.deliveryIndex, state.lastScheduledIndex, pending.scheduledIndex);
598
+ return (pending.scheduledIndex <= state.lastScheduledIndex ||
599
+ pending.deliveryIndex !== expected.deliveryIndex ||
600
+ pending.scheduledAtUnixMs !== expected.scheduledAtUnixMs ||
601
+ pending.skippedTicks !== expected.skippedTicks);
602
+ })) {
603
+ throw new Error(`Timer '${name}' relocation state is invalid.`);
604
+ }
605
+ }
606
+ /**
607
+ * Spot timer §1: the tick info that follows the completed cursor. A timer holds
608
+ * at most one pending tick, so its DeliveryIndex is the next one.
609
+ */
610
+ function relocationPendingTick(startedAtUnixMs, periodMs, deliveryIndex, lastScheduledIndex, scheduledIndex) {
611
+ return {
612
+ deliveryIndex: deliveryIndex + 1n,
613
+ scheduledIndex,
614
+ scheduledAtUnixMs: startedAtUnixMs + Number(scheduledIndex) * periodMs,
615
+ skippedTicks: scheduledIndex - lastScheduledIndex - 1n
616
+ };
433
617
  }
434
618
  function createTimerDiagnostics(sourceName, spotId, isEntrySpot, timerName, handlerType, publisher) {
435
619
  if (publisher === undefined) {