@lostgradient/weft 0.2.1 → 0.4.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 (579) hide show
  1. package/README.md +123 -43
  2. package/dist/cli/conformance.js +7 -1
  3. package/dist/cli/generated/operation-client.generated.d.ts +55 -13
  4. package/dist/cli/generated/operation-client.generated.js +3 -0
  5. package/dist/cli/help-text.d.ts +1 -1
  6. package/dist/cli/help-text.js +1 -0
  7. package/dist/cli/operation-catalog-snapshot.d.ts +8 -0
  8. package/dist/cli/operation-catalog-snapshot.js +11 -0
  9. package/dist/cli/parse-schedule-arguments.js +3 -1
  10. package/dist/cli/schedule.js +2 -1
  11. package/dist/cli/types.d.ts +1 -0
  12. package/dist/cli-main.js +80 -79
  13. package/dist/client/handle-delegation.d.ts +7 -2
  14. package/dist/client/handle-delegation.js +9 -1
  15. package/dist/client/http-client-requests.d.ts +4 -1
  16. package/dist/client/http-client-requests.js +10 -0
  17. package/dist/client/http-client.d.ts +10 -4
  18. package/dist/client/http-client.js +18 -1
  19. package/dist/client/http-request.d.ts +11 -1
  20. package/dist/client/http-request.js +17 -7
  21. package/dist/client/index.d.ts +1 -1
  22. package/dist/client/interface.d.ts +100 -4
  23. package/dist/client/local.d.ts +7 -1
  24. package/dist/client/local.js +17 -2
  25. package/dist/client/start-body.d.ts +9 -2
  26. package/dist/client/start-body.js +13 -4
  27. package/dist/core/byte-arrays.d.ts +5 -0
  28. package/dist/core/byte-arrays.js +5 -0
  29. package/dist/core/checkpoint/lifecycle.d.ts +3 -0
  30. package/dist/core/checkpoint/lifecycle.js +9 -4
  31. package/dist/core/checkpoint/serialization.js +12 -5
  32. package/dist/core/codec/extension-codec.d.ts +16 -0
  33. package/dist/core/codec/extension-codec.js +104 -8
  34. package/dist/core/codec/index.d.ts +1 -0
  35. package/dist/core/codec/index.js +1 -0
  36. package/dist/core/codec/serializer-registry.d.ts +122 -0
  37. package/dist/core/codec/serializer-registry.js +51 -0
  38. package/dist/core/context/activity-retry-state.d.ts +38 -0
  39. package/dist/core/context/activity-retry-state.js +89 -0
  40. package/dist/core/context/activity-schedule-to-close.d.ts +159 -0
  41. package/dist/core/context/activity-schedule-to-close.js +69 -0
  42. package/dist/core/context/child-workflow-pipe.d.ts +5 -5
  43. package/dist/core/context/child-workflow-pipe.js +15 -2
  44. package/dist/core/context/context-presence.d.ts +19 -0
  45. package/dist/core/context/context-presence.js +13 -0
  46. package/dist/core/context/durable-operations.d.ts +25 -0
  47. package/dist/core/context/durable-operations.js +64 -0
  48. package/dist/core/context/index.d.ts +18 -5
  49. package/dist/core/context/index.js +17 -12
  50. package/dist/core/context/internals.d.ts +29 -0
  51. package/dist/core/context/internals.js +6 -1
  52. package/dist/core/context/operation-request.d.ts +35 -0
  53. package/dist/core/context/parallel-cache-entry.d.ts +14 -5
  54. package/dist/core/context/run-operation.d.ts +21 -3
  55. package/dist/core/context/run-operation.js +56 -93
  56. package/dist/core/context/session-state.js +7 -8
  57. package/dist/core/context/speculative-child.js +2 -0
  58. package/dist/core/context/types.d.ts +15 -0
  59. package/dist/core/context/version-patching.d.ts +8 -0
  60. package/dist/core/context/version-patching.js +40 -0
  61. package/dist/core/context/workflow-logger.d.ts +98 -0
  62. package/dist/core/context/workflow-logger.js +68 -0
  63. package/dist/core/engine/activity-heartbeat-tracking.d.ts +64 -0
  64. package/dist/core/engine/activity-heartbeat-tracking.js +42 -0
  65. package/dist/core/engine/activity-per-attempt-timeout.d.ts +41 -0
  66. package/dist/core/engine/activity-per-attempt-timeout.js +36 -0
  67. package/dist/core/engine/activity-reconciliation.d.ts +1 -0
  68. package/dist/core/engine/activity-reconciliation.js +12 -1
  69. package/dist/core/engine/activity-resolution.d.ts +23 -0
  70. package/dist/core/engine/activity-resolution.js +37 -0
  71. package/dist/core/engine/aggregate.js +66 -30
  72. package/dist/core/engine/async-activity-completion.d.ts +23 -6
  73. package/dist/core/engine/async-activity-completion.js +53 -12
  74. package/dist/core/engine/attributes-tags.js +9 -4
  75. package/dist/core/engine/bulk-operations-purge.d.ts +26 -0
  76. package/dist/core/engine/bulk-operations-purge.js +38 -3
  77. package/dist/core/engine/bulk-operations-shared.d.ts +2 -0
  78. package/dist/core/engine/bulk-operations-shared.js +8 -2
  79. package/dist/core/engine/bulk-operations.d.ts +4 -1
  80. package/dist/core/engine/bulk-operations.js +235 -24
  81. package/dist/core/engine/callback-creators-bundles.d.ts +9 -0
  82. package/dist/core/engine/callback-creators-bundles.js +30 -2
  83. package/dist/core/engine/callback-creators-core.js +6 -4
  84. package/dist/core/engine/callback-creators-router.js +10 -0
  85. package/dist/core/engine/callback-creators-schedule.d.ts +2 -2
  86. package/dist/core/engine/callback-creators-schedule.js +12 -8
  87. package/dist/core/engine/candidate-read-batching.d.ts +6 -0
  88. package/dist/core/engine/candidate-read-batching.js +1 -0
  89. package/dist/core/engine/checkpoint-io.js +61 -25
  90. package/dist/core/engine/checkpoint-reads.js +3 -2
  91. package/dist/core/engine/checkpoint-replay.d.ts +20 -0
  92. package/dist/core/engine/checkpoint-replay.js +242 -0
  93. package/dist/core/engine/checkpoint-side-effects.d.ts +23 -0
  94. package/dist/core/engine/checkpoint-side-effects.js +35 -0
  95. package/dist/core/engine/child-workflow-cancellation.d.ts +10 -0
  96. package/dist/core/engine/child-workflow-cancellation.js +40 -0
  97. package/dist/core/engine/child-workflow.js +27 -4
  98. package/dist/core/engine/condition-waiters.d.ts +14 -0
  99. package/dist/core/engine/condition-waiters.js +5 -0
  100. package/dist/core/engine/construction.d.ts +3 -1
  101. package/dist/core/engine/construction.js +30 -8
  102. package/dist/core/engine/coordination-branch-executors.d.ts +70 -0
  103. package/dist/core/engine/coordination-branch-executors.js +107 -0
  104. package/dist/core/engine/deferred-consume-envelope.d.ts +59 -0
  105. package/dist/core/engine/deferred-consume-envelope.js +14 -0
  106. package/dist/core/engine/disposal.js +25 -0
  107. package/dist/core/engine/engine-create-types.d.ts +14 -18
  108. package/dist/core/engine/engine-internal-types.d.ts +38 -3
  109. package/dist/core/engine/engine-leak-warnings.d.ts +6 -0
  110. package/dist/core/engine/engine-leak-warnings.js +4 -0
  111. package/dist/core/engine/engine-runtime-helpers.d.ts +17 -0
  112. package/dist/core/engine/engine-runtime-helpers.js +26 -5
  113. package/dist/core/engine/errors.d.ts +121 -0
  114. package/dist/core/engine/errors.js +45 -1
  115. package/dist/core/engine/event-log-compaction.d.ts +8 -0
  116. package/dist/core/engine/event-log-compaction.js +20 -2
  117. package/dist/core/engine/fenced-write.d.ts +65 -0
  118. package/dist/core/engine/fenced-write.js +71 -0
  119. package/dist/core/engine/finalizer-state.d.ts +28 -0
  120. package/dist/core/engine/finalizer-state.js +16 -0
  121. package/dist/core/engine/handle-result.js +1 -1
  122. package/dist/core/engine/handles.d.ts +97 -40
  123. package/dist/core/engine/handles.js +25 -27
  124. package/dist/core/engine/index.d.ts +125 -15
  125. package/dist/core/engine/index.js +207 -11
  126. package/dist/core/engine/inline-launch-queue.d.ts +14 -0
  127. package/dist/core/engine/inline-launch-queue.js +32 -7
  128. package/dist/core/engine/inline-parking.js +3 -2
  129. package/dist/core/engine/internals.d.ts +125 -13
  130. package/dist/core/engine/lease-codec.d.ts +35 -0
  131. package/dist/core/engine/lease-codec.js +32 -0
  132. package/dist/core/engine/lease-deposition.d.ts +66 -0
  133. package/dist/core/engine/lease-deposition.js +10 -0
  134. package/dist/core/engine/lease-errors.d.ts +99 -0
  135. package/dist/core/engine/lease-errors.js +30 -0
  136. package/dist/core/engine/lease-manager.d.ts +114 -0
  137. package/dist/core/engine/lease-manager.js +135 -0
  138. package/dist/core/engine/lifecycle/fork-helpers.js +1 -7
  139. package/dist/core/engine/lifecycle/persist.js +15 -52
  140. package/dist/core/engine/lifecycle/recovered-services.d.ts +8 -6
  141. package/dist/core/engine/lifecycle/recovered-services.js +18 -3
  142. package/dist/core/engine/lifecycle/resume.js +39 -11
  143. package/dist/core/engine/lifecycle/shared.d.ts +8 -1
  144. package/dist/core/engine/lifecycle/start-batch.d.ts +1 -1
  145. package/dist/core/engine/lifecycle/start-batch.js +2 -1
  146. package/dist/core/engine/lifecycle/start-commit.d.ts +56 -0
  147. package/dist/core/engine/lifecycle/start-commit.js +69 -0
  148. package/dist/core/engine/lifecycle/start-exec.d.ts +30 -2
  149. package/dist/core/engine/lifecycle/start-exec.js +38 -0
  150. package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +58 -0
  151. package/dist/core/engine/lifecycle/start-or-signal-create.js +95 -0
  152. package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +79 -0
  153. package/dist/core/engine/lifecycle/start-or-signal-resolution.js +60 -0
  154. package/dist/core/engine/lifecycle/start-or-signal.d.ts +46 -0
  155. package/dist/core/engine/lifecycle/start-or-signal.js +71 -0
  156. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +39 -0
  157. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +28 -0
  158. package/dist/core/engine/lifecycle/start.d.ts +6 -6
  159. package/dist/core/engine/lifecycle/start.js +47 -45
  160. package/dist/core/engine/lifecycle/transition.js +17 -5
  161. package/dist/core/engine/lifecycle.d.ts +3 -2
  162. package/dist/core/engine/lifecycle.js +9 -2
  163. package/dist/core/engine/list-candidate-resolution.js +2 -2
  164. package/dist/core/engine/listing.js +10 -6
  165. package/dist/core/engine/operations-activity.d.ts +4 -11
  166. package/dist/core/engine/operations-activity.js +22 -49
  167. package/dist/core/engine/operations-coordination.d.ts +10 -0
  168. package/dist/core/engine/operations-coordination.js +43 -8
  169. package/dist/core/engine/operations-router.d.ts +6 -0
  170. package/dist/core/engine/operations-router.js +2 -0
  171. package/dist/core/engine/operations-speculate.js +6 -2
  172. package/dist/core/engine/operations-stream.js +12 -2
  173. package/dist/core/engine/operations-time.d.ts +4 -2
  174. package/dist/core/engine/operations-time.js +14 -2
  175. package/dist/core/engine/operations-wait-condition.d.ts +23 -0
  176. package/dist/core/engine/operations-wait-condition.js +62 -0
  177. package/dist/core/engine/ownership-options.d.ts +23 -0
  178. package/dist/core/engine/ownership-options.js +26 -0
  179. package/dist/core/engine/payload-size-policy.d.ts +3 -0
  180. package/dist/core/engine/payload-size-policy.js +4 -0
  181. package/dist/core/engine/pending-updates.d.ts +17 -0
  182. package/dist/core/engine/pending-updates.js +33 -11
  183. package/dist/core/engine/persisted-data-version.d.ts +5 -9
  184. package/dist/core/engine/persisted-data-version.js +4 -5
  185. package/dist/core/engine/queries.js +1 -1
  186. package/dist/core/engine/registration.d.ts +1 -0
  187. package/dist/core/engine/registration.js +18 -3
  188. package/dist/core/engine/schedule-handle.d.ts +45 -0
  189. package/dist/core/engine/schedule-handle.js +26 -0
  190. package/dist/core/engine/schedule-jitter.d.ts +5 -0
  191. package/dist/core/engine/schedule-jitter.js +10 -0
  192. package/dist/core/engine/schedule-run.d.ts +17 -0
  193. package/dist/core/engine/schedule-run.js +38 -0
  194. package/dist/core/engine/schedule-timer.js +81 -17
  195. package/dist/core/engine/schedules.d.ts +8 -5
  196. package/dist/core/engine/schedules.js +44 -19
  197. package/dist/core/engine/search-attribute-records.d.ts +4 -0
  198. package/dist/core/engine/search-attribute-records.js +17 -0
  199. package/dist/core/engine/second-instance-detector.d.ts +96 -0
  200. package/dist/core/engine/second-instance-detector.js +108 -0
  201. package/dist/core/engine/signals.d.ts +38 -0
  202. package/dist/core/engine/signals.js +55 -19
  203. package/dist/core/engine/state-utilities.d.ts +49 -2
  204. package/dist/core/engine/state-utilities.js +114 -3
  205. package/dist/core/engine/storage-io.d.ts +16 -2
  206. package/dist/core/engine/storage-io.js +26 -5
  207. package/dist/core/engine/stream-chunk-loading.d.ts +2 -0
  208. package/dist/core/engine/stream-chunk-loading.js +24 -1
  209. package/dist/core/engine/sub-operation.js +22 -3
  210. package/dist/core/engine/termination/cleanup.d.ts +28 -1
  211. package/dist/core/engine/termination/cleanup.js +44 -2
  212. package/dist/core/engine/termination/complete.js +48 -9
  213. package/dist/core/engine/termination/finalizer-activity.d.ts +53 -0
  214. package/dist/core/engine/termination/finalizer-activity.js +30 -0
  215. package/dist/core/engine/termination/finalizer-claim.d.ts +110 -0
  216. package/dist/core/engine/termination/finalizer-claim.js +80 -0
  217. package/dist/core/engine/termination/finalizer.d.ts +48 -0
  218. package/dist/core/engine/termination/finalizer.js +159 -0
  219. package/dist/core/engine/termination/suspend.d.ts +70 -0
  220. package/dist/core/engine/termination/suspend.js +41 -0
  221. package/dist/core/engine/termination.d.ts +5 -2
  222. package/dist/core/engine/termination.js +6 -0
  223. package/dist/core/engine/updates.js +5 -25
  224. package/dist/core/engine/validation/schedule.d.ts +2 -1
  225. package/dist/core/engine/validation/schedule.js +51 -2
  226. package/dist/core/engine/validation.js +54 -3
  227. package/dist/core/engine/waiting-update-response.d.ts +8 -0
  228. package/dist/core/engine/waiting-update-response.js +22 -0
  229. package/dist/core/engine/workflow-concurrency.d.ts +10 -0
  230. package/dist/core/engine/workflow-concurrency.js +136 -0
  231. package/dist/core/engine/workflow-feed.d.ts +9 -8
  232. package/dist/core/engine/workflow-feed.js +4 -1
  233. package/dist/core/engine/workflow-indexes.d.ts +9 -0
  234. package/dist/core/engine/workflow-indexes.js +10 -0
  235. package/dist/core/engine/workflow-state-stream.js +33 -13
  236. package/dist/core/engine/workflow-visibility-queries.d.ts +2 -2
  237. package/dist/core/engine-helpers.js +1 -0
  238. package/dist/core/events/activity-events.d.ts +43 -12
  239. package/dist/core/events/activity-events.js +28 -0
  240. package/dist/core/events/attribute-events.d.ts +2 -3
  241. package/dist/core/events/event-map.d.ts +19 -12
  242. package/dist/core/events/index.d.ts +1 -0
  243. package/dist/core/events/index.js +1 -0
  244. package/dist/core/events/schedule-events.d.ts +71 -0
  245. package/dist/core/events/schedule-events.js +29 -0
  246. package/dist/core/events/signal-events.d.ts +4 -6
  247. package/dist/core/events/system-events.d.ts +29 -19
  248. package/dist/core/events/system-events.js +26 -0
  249. package/dist/core/events/update-events.d.ts +6 -8
  250. package/dist/core/events/workflow-events.d.ts +108 -20
  251. package/dist/core/events/workflow-events.js +35 -0
  252. package/dist/core/failure-categories.js +5 -17
  253. package/dist/core/fault-code.d.ts +9 -3
  254. package/dist/core/fault-code.js +1 -0
  255. package/dist/core/inline-execution-strategy.context-options.d.ts +69 -0
  256. package/dist/core/inline-execution-strategy.context-options.js +56 -0
  257. package/dist/core/inline-execution-strategy.d.ts +31 -36
  258. package/dist/core/inline-execution-strategy.js +16 -27
  259. package/dist/core/list-filter-validation.d.ts +1 -1
  260. package/dist/core/list-filter-validation.js +2 -1
  261. package/dist/core/payload-size.d.ts +1 -1
  262. package/dist/core/persisted-data-incompatible-error.d.ts +9 -7
  263. package/dist/core/review/events.d.ts +6 -8
  264. package/dist/core/scheduler/scheduler-class.d.ts +10 -1
  265. package/dist/core/scheduler/scheduler-class.js +38 -11
  266. package/dist/core/scheduler/timer-batch.js +9 -1
  267. package/dist/core/scheduler/timer-sources.d.ts +1 -0
  268. package/dist/core/scheduler/timer-sources.js +11 -5
  269. package/dist/core/session-state.d.ts +0 -1
  270. package/dist/core/session-state.js +2 -2
  271. package/dist/core/start-workflow-validation.d.ts +56 -0
  272. package/dist/core/start-workflow-validation.js +30 -1
  273. package/dist/core/step-context.d.ts +10 -6
  274. package/dist/core/step-context.js +7 -15
  275. package/dist/core/types/activity-verification.d.ts +67 -0
  276. package/dist/core/types/activity-verification.js +0 -0
  277. package/dist/core/types/activity.d.ts +86 -64
  278. package/dist/core/types/bulk.d.ts +50 -9
  279. package/dist/core/types/checkpoint.d.ts +44 -8
  280. package/dist/core/types/identity.d.ts +8 -1
  281. package/dist/core/types/launch-metadata.d.ts +33 -0
  282. package/dist/core/types/launch-metadata.js +0 -0
  283. package/dist/core/types/list-options.d.ts +146 -0
  284. package/dist/core/types/list-options.js +0 -0
  285. package/dist/core/types/message-handles.d.ts +25 -0
  286. package/dist/core/types/options.d.ts +165 -215
  287. package/dist/core/types/reviews.d.ts +2 -1
  288. package/dist/core/types/schedules.d.ts +39 -3
  289. package/dist/core/types/services-resolution.d.ts +47 -0
  290. package/dist/core/types/services-resolution.js +0 -0
  291. package/dist/core/types/state.d.ts +11 -11
  292. package/dist/core/types/workflow-builder-runtime.d.ts +12 -3
  293. package/dist/core/types/workflow-builder-runtime.js +11 -2
  294. package/dist/core/types/workflow-builder.d.ts +47 -15
  295. package/dist/core/types/workflow-concurrency.d.ts +39 -0
  296. package/dist/core/types/workflow-concurrency.js +0 -0
  297. package/dist/core/types/workflow-context.d.ts +157 -14
  298. package/dist/core/types/workflow-definition.d.ts +53 -10
  299. package/dist/core/types/workflow-function.d.ts +101 -9
  300. package/dist/core/types/workflow-log.d.ts +98 -0
  301. package/dist/core/types/workflow-log.js +0 -0
  302. package/dist/core/types/workflow-registries.d.ts +14 -3
  303. package/dist/core/types/workflow-registry.d.ts +3 -0
  304. package/dist/core/types/workflow-snapshot.d.ts +29 -0
  305. package/dist/core/types/workflow-snapshot.js +0 -0
  306. package/dist/core/types.d.ts +7 -0
  307. package/dist/core/types.js +7 -0
  308. package/dist/core/versioning.d.ts +9 -39
  309. package/dist/core/versioning.js +2 -12
  310. package/dist/core/weft-error.d.ts +44 -1
  311. package/dist/core/weft-error.js +19 -1
  312. package/dist/core/worker-execution-strategy-options.d.ts +26 -0
  313. package/dist/core/worker-execution-strategy.js +40 -36
  314. package/dist/core/worker-inbound-message.d.ts +38 -0
  315. package/dist/core/worker-inbound-message.js +37 -0
  316. package/dist/core/worker-log-abuse-counter.d.ts +175 -0
  317. package/dist/core/worker-log-abuse-counter.js +107 -0
  318. package/dist/core/worker-message-helpers.d.ts +47 -0
  319. package/dist/core/worker-message-helpers.js +26 -0
  320. package/dist/core/worker-protocol-guard.js +1 -1
  321. package/dist/core/worker-protocol-log.d.ts +56 -0
  322. package/dist/core/worker-protocol-log.js +18 -0
  323. package/dist/core/worker-protocol.d.ts +23 -0
  324. package/dist/core/worker-protocol.js +12 -2
  325. package/dist/core/workflow-version-tuple.d.ts +3 -9
  326. package/dist/core/workflow-version-tuple.js +2 -3
  327. package/dist/diagnostics/doctor.js +6 -3
  328. package/dist/diagnostics/format.js +3 -8
  329. package/dist/diagnostics/types.d.ts +5 -5
  330. package/dist/diagnostics/validate.d.ts +0 -1
  331. package/dist/diagnostics/version-check.d.ts +1 -1
  332. package/dist/diagnostics/version-check.js +10 -13
  333. package/dist/index.d.ts +13 -11
  334. package/dist/index.js +39 -4
  335. package/dist/json-schema.js +3 -3
  336. package/dist/mcp/cli.js +35 -35
  337. package/dist/mcp/dispatcher.js +1 -1
  338. package/dist/mcp/http.js +16 -6
  339. package/dist/mcp/list-filter.js +2 -1
  340. package/dist/mcp/protocol.d.ts +2 -0
  341. package/dist/mcp/protocol.js +1 -1
  342. package/dist/mcp/session.d.ts +16 -0
  343. package/dist/mcp/session.js +60 -6
  344. package/dist/mcp/tools.js +73 -6
  345. package/dist/observability/index.js +2 -2
  346. package/dist/server/asyncapi-channels.js +5 -2
  347. package/dist/server/attribute-filters.d.ts +8 -3
  348. package/dist/server/attribute-filters.js +6 -1
  349. package/dist/server/authentication/api-key.d.ts +2 -1
  350. package/dist/server/authentication/api-key.js +5 -2
  351. package/dist/server/authentication/constant-time-api-key.d.ts +15 -0
  352. package/dist/server/authentication/constant-time-api-key.js +24 -0
  353. package/dist/server/authentication/index.d.ts +1 -1
  354. package/dist/server/authentication/index.js +7 -4
  355. package/dist/server/authentication/rotating-api-key-store.d.ts +5 -3
  356. package/dist/server/authentication/rotating-api-key-store.js +19 -11
  357. package/dist/server/engine-event-feed-backend.d.ts +4 -5
  358. package/dist/server/fault-to-http.js +8 -1
  359. package/dist/server/fault-to-json-rpc.js +1 -0
  360. package/dist/server/fleet-event-feed.d.ts +31 -0
  361. package/dist/server/fleet-event-feed.js +157 -0
  362. package/dist/server/handler/index.js +1 -1
  363. package/dist/server/handler/response-helpers.js +2 -1
  364. package/dist/server/handler/route-dispatch.d.ts +6 -3
  365. package/dist/server/handler/route-dispatch.js +2 -2
  366. package/dist/server/handler.js +31 -31
  367. package/dist/server/index.d.ts +32 -2
  368. package/dist/server/index.js +35 -35
  369. package/dist/server/interactive-operations.js +1 -0
  370. package/dist/server/json-rpc-transport-helpers.d.ts +1 -0
  371. package/dist/server/json-rpc-transport-helpers.js +2 -1
  372. package/dist/server/json-rpc-websocket-runtime.d.ts +11 -2
  373. package/dist/server/json-rpc-websocket-runtime.js +1 -0
  374. package/dist/server/json-rpc-websocket-subscriptions.d.ts +10 -0
  375. package/dist/server/json-rpc-websocket-subscriptions.js +29 -0
  376. package/dist/server/json-rpc-websocket-types.d.ts +22 -0
  377. package/dist/server/json-rpc-websocket-types.js +0 -0
  378. package/dist/server/json-rpc-websocket-validation.js +20 -4
  379. package/dist/server/json-rpc-websocket.d.ts +2 -43
  380. package/dist/server/json-rpc-websocket.js +57 -74
  381. package/dist/server/openapi.d.ts +2 -1
  382. package/dist/server/openapi.js +1 -3
  383. package/dist/server/openrpc-document-schema.d.ts +78 -0
  384. package/dist/server/openrpc-document-schema.js +27 -1
  385. package/dist/server/openrpc-errors.d.ts +3 -0
  386. package/dist/server/openrpc-errors.js +2 -1
  387. package/dist/server/openrpc.js +32 -0
  388. package/dist/server/operation-catalog/index.d.ts +1 -1
  389. package/dist/server/operation-catalog/pipeline-helpers.js +1 -0
  390. package/dist/server/operation-catalog/pipeline-stages.js +26 -12
  391. package/dist/server/operation-catalog/pipeline.js +8 -1
  392. package/dist/server/operation-catalog/registry.js +13 -0
  393. package/dist/server/operation-catalog/types.d.ts +20 -9
  394. package/dist/server/operation-fault.d.ts +10 -0
  395. package/dist/server/operation-fault.js +2 -0
  396. package/dist/server/operation-registry.d.ts +12 -11
  397. package/dist/server/operation-registry.js +12 -3
  398. package/dist/server/operations/aggregate-workflows.d.ts +15 -15
  399. package/dist/server/operations/async-activity.d.ts +2 -2
  400. package/dist/server/operations/async-activity.js +12 -7
  401. package/dist/server/operations/bulk-cancel-workflows.d.ts +1 -1
  402. package/dist/server/operations/bulk-cancel-workflows.js +2 -2
  403. package/dist/server/operations/bulk-delete-workflows.d.ts +1 -1
  404. package/dist/server/operations/bulk-delete-workflows.js +2 -2
  405. package/dist/server/operations/bulk-filter-helpers.d.ts +8 -6
  406. package/dist/server/operations/bulk-filter-helpers.js +54 -24
  407. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +11 -9
  408. package/dist/server/operations/bulk-mutate-workflow-tags.js +2 -2
  409. package/dist/server/operations/bulk-operation-helpers.d.ts +2 -2
  410. package/dist/server/operations/bulk-retry-failed-workflows.d.ts +7 -0
  411. package/dist/server/operations/bulk-retry-failed-workflows.js +64 -0
  412. package/dist/server/operations/bulk-signal-workflows.d.ts +11 -9
  413. package/dist/server/operations/bulk-signal-workflows.js +2 -2
  414. package/dist/server/operations/cancel-schedule.d.ts +1 -1
  415. package/dist/server/operations/create-schedule.d.ts +3 -1
  416. package/dist/server/operations/create-schedule.js +29 -11
  417. package/dist/server/operations/fleet-events-subscription.d.ts +54 -0
  418. package/dist/server/operations/fleet-events-subscription.js +99 -0
  419. package/dist/server/operations/fork-workflow.d.ts +1 -1
  420. package/dist/server/operations/fork-workflow.js +3 -2
  421. package/dist/server/operations/get-checkpoint-at.d.ts +1 -1
  422. package/dist/server/operations/get-registry.d.ts +1 -1
  423. package/dist/server/operations/get-retention-overview.d.ts +1 -1
  424. package/dist/server/operations/get-review.d.ts +1 -1
  425. package/dist/server/operations/get-schedule.d.ts +1 -1
  426. package/dist/server/operations/get-stream-chunks.d.ts +1 -1
  427. package/dist/server/operations/get-system-metrics.d.ts +2 -2
  428. package/dist/server/operations/get-task-diagnostics.d.ts +45 -6
  429. package/dist/server/operations/get-task-diagnostics.js +101 -7
  430. package/dist/server/operations/get-update-result.d.ts +1 -1
  431. package/dist/server/operations/get-workflow-attributes.d.ts +1 -1
  432. package/dist/server/operations/get-workflow-events.d.ts +1 -1
  433. package/dist/server/operations/get-workflow-result.d.ts +1 -1
  434. package/dist/server/operations/get-workflow-timeline.d.ts +1 -1
  435. package/dist/server/operations/get-workflow.d.ts +1 -1
  436. package/dist/server/operations/list-checkpoints.d.ts +1 -1
  437. package/dist/server/operations/list-reviews.d.ts +1 -1
  438. package/dist/server/operations/list-schedules.d.ts +1 -1
  439. package/dist/server/operations/list-task-queues.d.ts +2 -2
  440. package/dist/server/operations/list-workers.d.ts +2 -2
  441. package/dist/server/operations/list-workflows.d.ts +1 -1
  442. package/dist/server/operations/operation-helpers.d.ts +16 -1
  443. package/dist/server/operations/operation-helpers.js +15 -3
  444. package/dist/server/operations/pause-schedule.d.ts +1 -1
  445. package/dist/server/operations/purge-workflows.d.ts +5 -5
  446. package/dist/server/operations/purge-workflows.js +2 -2
  447. package/dist/server/operations/query-workflow.d.ts +1 -1
  448. package/dist/server/operations/query-workflow.js +3 -2
  449. package/dist/server/operations/recover-all.d.ts +1 -1
  450. package/dist/server/operations/replay-workflow.d.ts +1 -1
  451. package/dist/server/operations/resume-schedule.d.ts +1 -1
  452. package/dist/server/operations/resume-workflow.js +2 -2
  453. package/dist/server/operations/set-workflow-attributes.d.ts +1 -1
  454. package/dist/server/operations/set-workflow-attributes.js +6 -3
  455. package/dist/server/operations/signal-workflow.js +8 -3
  456. package/dist/server/operations/single-workflow-tag-mutation.js +13 -3
  457. package/dist/server/operations/start-or-signal-workflow.d.ts +44 -0
  458. package/dist/server/operations/start-or-signal-workflow.js +130 -0
  459. package/dist/server/operations/start-workflow-options.d.ts +38 -0
  460. package/dist/server/operations/start-workflow-options.js +63 -0
  461. package/dist/server/operations/start-workflow-rest-input.d.ts +14 -0
  462. package/dist/server/operations/start-workflow-rest-input.js +31 -0
  463. package/dist/server/operations/start-workflow.d.ts +1 -1
  464. package/dist/server/operations/start-workflow.js +15 -92
  465. package/dist/server/operations/storage.d.ts +6 -6
  466. package/dist/server/operations/storage.js +24 -14
  467. package/dist/server/operations/stream-workflow-sse.d.ts +1 -1
  468. package/dist/server/operations/submit-review-decision.d.ts +1 -1
  469. package/dist/server/operations/submit-review-decision.js +6 -3
  470. package/dist/server/operations/suspend-workflow.d.ts +13 -0
  471. package/dist/server/operations/suspend-workflow.js +36 -0
  472. package/dist/server/operations/update-schedule.d.ts +1 -1
  473. package/dist/server/operations/update-schedule.js +7 -4
  474. package/dist/server/operations/update-workflow.d.ts +1 -1
  475. package/dist/server/operations/update-workflow.js +7 -3
  476. package/dist/server/operations/worker-drain.d.ts +8 -8
  477. package/dist/server/operations/worker-drain.js +11 -8
  478. package/dist/server/operations/workflow-events-subscription.d.ts +7 -8
  479. package/dist/server/operations/workflow-events-subscription.js +43 -8
  480. package/dist/server/rest-binding.d.ts +21 -8
  481. package/dist/server/rest-bindings.js +24 -0
  482. package/dist/server/rest-body.d.ts +10 -0
  483. package/dist/server/rest-body.js +80 -0
  484. package/dist/server/runtime/authentication-bridge.d.ts +1 -0
  485. package/dist/server/runtime/authentication-bridge.js +33 -6
  486. package/dist/server/runtime/client-visible-events.d.ts +3 -0
  487. package/dist/server/runtime/client-visible-events.js +65 -0
  488. package/dist/server/runtime/context.d.ts +7 -0
  489. package/dist/server/runtime/event-broadcasting.d.ts +6 -0
  490. package/dist/server/runtime/event-broadcasting.js +72 -38
  491. package/dist/server/runtime/retry.d.ts +1 -0
  492. package/dist/server/runtime/retry.js +14 -0
  493. package/dist/server/runtime/shutdown.d.ts +7 -6
  494. package/dist/server/runtime/shutdown.js +6 -1
  495. package/dist/server/runtime/task-dispatch.js +5 -3
  496. package/dist/server/runtime/task-polling.d.ts +16 -2
  497. package/dist/server/runtime/task-polling.js +80 -24
  498. package/dist/server/runtime/task-reconciliation.js +9 -1
  499. package/dist/server/runtime/task-result-resolution.d.ts +15 -0
  500. package/dist/server/runtime/task-result-resolution.js +81 -0
  501. package/dist/server/runtime/websocket-stream.d.ts +20 -1
  502. package/dist/server/runtime/websocket-stream.js +173 -7
  503. package/dist/server/runtime/websocket-upgrade.js +22 -3
  504. package/dist/server/runtime/websocket-worker.d.ts +1 -1
  505. package/dist/server/runtime/websocket-worker.js +46 -30
  506. package/dist/server/serve-internals.d.ts +11 -1
  507. package/dist/server/serve-internals.js +20 -2
  508. package/dist/server/task-state.d.ts +38 -0
  509. package/dist/server/task-state.js +28 -0
  510. package/dist/server/workflow-event-feed.d.ts +36 -115
  511. package/dist/server/workflow-event-feed.js +92 -27
  512. package/dist/service-worker/index.js +31 -31
  513. package/dist/storage/auto.js +1 -1
  514. package/dist/storage/bun-sql.js +24 -0
  515. package/dist/storage/capabilities.d.ts +10 -2
  516. package/dist/storage/capabilities.js +2 -2
  517. package/dist/storage/compressed-storage.js +1 -1
  518. package/dist/storage/default-scope.d.ts +7 -4
  519. package/dist/storage/http.js +2 -2
  520. package/dist/storage/index.d.ts +81 -4
  521. package/dist/storage/indexeddb.js +1 -1
  522. package/dist/storage/interface.d.ts +189 -0
  523. package/dist/storage/interface.js +1 -1
  524. package/dist/storage/key-prefixes.d.ts +1 -1
  525. package/dist/storage/key-prefixes.js +12 -0
  526. package/dist/storage/lmdb.d.ts +4 -3
  527. package/dist/storage/lmdb.js +1 -1
  528. package/dist/storage/memory.js +1 -1
  529. package/dist/storage/neon-batch.d.ts +30 -0
  530. package/dist/storage/neon-batch.js +30 -0
  531. package/dist/storage/neon-value-mapping.d.ts +74 -0
  532. package/dist/storage/neon-value-mapping.js +23 -0
  533. package/dist/storage/neon.d.ts +124 -0
  534. package/dist/storage/neon.js +15 -0
  535. package/dist/storage/node-sqlite-loader.d.ts +71 -0
  536. package/dist/storage/node-sqlite-loader.js +41 -0
  537. package/dist/storage/node-sqlite.d.ts +1 -19
  538. package/dist/storage/node-sqlite.js +61 -32
  539. package/dist/storage/postgres-key-value-queries.d.ts +104 -0
  540. package/dist/storage/postgres-key-value-queries.js +101 -0
  541. package/dist/storage/resolve.d.ts +2 -165
  542. package/dist/storage/resolve.js +1 -1
  543. package/dist/storage/scoped-storage.js +1 -1
  544. package/dist/storage/storage-configuration.d.ts +209 -0
  545. package/dist/storage/storage-configuration.js +0 -0
  546. package/dist/storage/testing.d.ts +168 -0
  547. package/dist/storage/testing.js +2 -0
  548. package/dist/storage/text-value-store.d.ts +9 -9
  549. package/dist/storage/turso.d.ts +8 -0
  550. package/dist/storage/turso.js +2 -2
  551. package/dist/storage/typed-storage.js +1 -1
  552. package/dist/storage/web-extension.js +1 -1
  553. package/dist/testing/index.js +35 -35
  554. package/dist/version.d.ts +1 -1
  555. package/dist/version.js +1 -1
  556. package/dist/worker/index.js +9 -5
  557. package/dist/worker/long-poll.js +4 -0
  558. package/dist/worker/protocol-messages.d.ts +20 -0
  559. package/dist/worker/protocol-schemas.d.ts +32 -0
  560. package/dist/worker/protocol-schemas.js +8 -4
  561. package/dist/worker/protocol-task-result.d.ts +28 -0
  562. package/dist/worker/protocol-task-result.js +76 -0
  563. package/dist/worker/protocol.d.ts +4 -15
  564. package/dist/worker/protocol.js +1 -1
  565. package/dist/worker/registry/fair-share.d.ts +29 -0
  566. package/dist/worker/registry/fair-share.js +30 -0
  567. package/dist/worker/registry/routing.d.ts +18 -0
  568. package/dist/worker/registry/routing.js +14 -0
  569. package/dist/worker/registry/types.d.ts +7 -0
  570. package/dist/worker/registry.d.ts +16 -1
  571. package/dist/worker/registry.js +24 -36
  572. package/dist/workers/worker-replay-state.d.ts +32 -0
  573. package/dist/workers/worker-replay-state.js +35 -0
  574. package/dist/workers/worker-state-namespace.d.ts +21 -0
  575. package/dist/workers/worker-state-namespace.js +13 -0
  576. package/dist/workers/workflow-runner.d.ts +19 -15
  577. package/dist/workers/workflow-runner.js +72 -60
  578. package/dist/workers/workflow-worker-entry.js +5 -2
  579. package/package.json +21 -4
@@ -28,13 +28,19 @@ import type { InlineExecutionStrategy } from '../inline-execution-strategy.ts';
28
28
  import type { ComposedActivityInterceptor, ComposedWorkflowInterceptor, Interceptor } from '../interceptor.ts';
29
29
  import type { HumanReviewResult, ReviewCoordinator } from '../review/index.ts';
30
30
  import type { Scheduler } from '../scheduler.ts';
31
- import type { Checkpoint } from '../types.ts';
31
+ import type { Checkpoint, StartWorkflowOptions } from '../types.ts';
32
32
  import type { UpdateCoordinator } from '../updates.ts';
33
33
  import type { WorkflowVersionTuple } from '../workflow-version-tuple.ts';
34
34
  import type { PendingTimelineEntry, QueuedInlineWorkflowExecutionStart, RegistrationEntry, ResolvedOptions, TrackedWaiterKeys, WorkflowResultWaiter } from './engine-internal-types.ts';
35
- import type { ScheduleHandleEngine, WorkflowHandle, WorkflowHandleEngine } from './handles.ts';
35
+ import type { EngineCleanupIntervalDisposalTracker } from './engine-leak-warnings.ts';
36
+ import type { WorkflowHandle, WorkflowHandleEngine } from './handles.ts';
36
37
  import type { WorkflowFeedListener } from './index.ts';
37
- type EngineRuntime = WorkflowHandleEngine & ScheduleHandleEngine;
38
+ import type { LeaseManager } from './lease-manager.ts';
39
+ import type { ScheduleHandleEngine } from './schedule-handle.ts';
40
+ import type { SecondInstanceDetector } from './second-instance-detector.ts';
41
+ type EngineRuntime = WorkflowHandleEngine & ScheduleHandleEngine & {
42
+ start(type: string, input: unknown, options?: StartWorkflowOptions): Promise<WorkflowHandle>;
43
+ };
38
44
  export interface EngineInternals {
39
45
  engine: EngineRuntime;
40
46
  storage: WeftStorage;
@@ -64,6 +70,23 @@ export interface EngineInternals {
64
70
  resultResolvers: Map<string, WorkflowResultWaiter>;
65
71
  signalWaiters: Map<string, () => void>;
66
72
  signalWaitersByWorkflow: Map<string, TrackedWaiterKeys>;
73
+ /**
74
+ * In-process resolvers for inline `ctx.waitUntil` waits, keyed by `workflowId`
75
+ * ALONE — a workflow has at most one active wait-condition because its inline
76
+ * generator is suspended at exactly one yield, and the top-level-only guard in
77
+ * `executeSubOperation` rejects `waitUntil` as a `race`/`all`/`speculate`
78
+ * branch. So unlike `signalWaiters` (which need a per-workflow string-or-Set
79
+ * index because they CAN be concurrent sub-operations), this is a flat map with
80
+ * no secondary index. Calling the resolver wakes `processWaitConditionOperation`
81
+ * to re-evaluate its predicate. Never checkpointed — engine-memory state cleared
82
+ * on terminal cleanup.
83
+ *
84
+ * Note: the deadline TIMER is still keyed `cond:${workflowId}:${step}` (step is
85
+ * stable across replay, so recovery does not double-arm). Only this waiter map
86
+ * keys by `workflowId`. If `waitUntil`-in-`race`/`all`/`speculate` is ever
87
+ * supported, this keying must revert to `${workflowId}:${step}` + a Set index.
88
+ */
89
+ conditionWaiters: Map<string, () => void>;
67
90
  updateWaiters: Map<string, (payload: unknown) => void>;
68
91
  updateWaitersByWorkflow: Map<string, TrackedWaiterKeys>;
69
92
  sleepResolvers: Map<string, () => void>;
@@ -75,11 +98,15 @@ export interface EngineInternals {
75
98
  activityRegistry: ActivityRegistry;
76
99
  /**
77
100
  * Per-workflow activity registries built from
78
- * `workflow({ name }).activities({ ... }).execute(...)`. Indexed by workflow
79
- * type. Phase 3 wires lookups via `activityRegistriesByWorkflow.get(type)`
80
- * first, falling back to {@link EngineInternals.activityRegistry} so the
81
- * legacy global path keeps working until Phase 6 removes it. Each registry
82
- * is constructed from a defensive deep clone+freeze of the workflow's
101
+ * `workflow({ name }).activities({ ... }).execute(...)`, indexed by workflow
102
+ * type. Activity lookup is per-activity: it consults the workflow's
103
+ * `activityRegistriesByWorkflow.get(type)` registry first and, for any activity
104
+ * that registry does not contain, falls back to the engine-wide
105
+ * {@link EngineInternals.activityRegistry}. Both sources are first-class a
106
+ * workflow can resolve some activities from its own `activities(...)` map and
107
+ * others (shared/globally-registered) from the global registry, and a workflow
108
+ * with no per-workflow map resolves entirely from the global one. Each
109
+ * per-workflow registry is a defensive deep clone+freeze of the workflow's
83
110
  * `activities` map so post-registration mutation cannot reach the engine.
84
111
  */
85
112
  activityRegistriesByWorkflow: Map<string, ActivityRegistry>;
@@ -103,11 +130,25 @@ export interface EngineInternals {
103
130
  broadcastChannel: BroadcastChannel | null;
104
131
  pendingNestingDepth: number | undefined;
105
132
  pendingParentHeaders: Map<string, string> | undefined;
106
- pendingExecutionStateOwnerId: string | undefined;
133
+ pendingExecutionStateOwnerId: string | null | undefined;
107
134
  workflowNestingDepths: Map<string, number>;
108
135
  workflowHeaders: Map<string, Map<string, string>>;
109
136
  workflowStateWriteChains: Map<string, Promise<void>>;
110
137
  heartbeatDetails: Map<string, unknown>;
138
+ /**
139
+ * Last heartbeat payload PER ACTIVITY STEP, so a retry of a step can read the
140
+ * heartbeat its previous attempt recorded (the resumable-batch pattern). Keyed
141
+ * `workflowId -> step -> details`. This is separate from {@link heartbeatDetails}
142
+ * (which is keyed by `workflowId` alone and powers the `activityProgress` query):
143
+ * concurrent activities inside one `ctx.all` would clobber a workflow-keyed map,
144
+ * so a retry could read a sibling's heartbeat. The step is stable across attempts
145
+ * (assigned once at `stepIndex++`), so a retry reads its OWN prior heartbeat.
146
+ * Never checkpointed — held only in engine memory and cleared (by workflowId, the
147
+ * outer key) on terminal cleanup and purge, the same lifecycle as
148
+ * {@link heartbeatDetails}. Inline-execution only; worker-executed activities run
149
+ * their function out of process and never observe this.
150
+ */
151
+ lastHeartbeatDetailsByStep: Map<string, Map<number, unknown>>;
111
152
  /**
112
153
  * Per-run, non-serialized `services` value exposed to the workflow body as
113
154
  * `ctx.services`. Set at `engine.start({ services })` and re-provided on
@@ -123,17 +164,63 @@ export interface EngineInternals {
123
164
  * reloaded by `recoverAll()`. See `async-activity-completion.ts`.
124
165
  */
125
166
  pendingAsyncActivities: Map<string, import('./async-activity-completion.ts').PendingAsyncActivity>;
167
+ /**
168
+ * Completed or failed async-activity tokens that were consumed before inline
169
+ * recovery adopted the workflow generator. Replay drains these by workflow id
170
+ * when it reaches the same deterministic async-activity token again.
171
+ */
172
+ pendingAsyncActivityResolutions: Map<string, import('./async-activity-completion.ts').PendingAsyncActivityResolution[]>;
126
173
  pendingStarts: Set<string>;
127
174
  pendingScheduleCreations: Set<string>;
128
175
  workflowsNeedingTerminalCleanup: Set<string>;
129
176
  cleanupInterval: ReturnType<typeof setInterval> | null;
130
- cleanupIntervalDisposalTracker: {
131
- disposed: boolean;
132
- cleanupInterval: ReturnType<typeof setInterval> | null;
133
- } | null;
177
+ cleanupIntervalDisposalTracker: EngineCleanupIntervalDisposalTracker | null;
134
178
  retentionSweepInterval: ReturnType<typeof setInterval> | null;
135
179
  retentionSweepInFlight: Promise<void> | null;
136
180
  nextRetentionSweepAt: number | null;
181
+ /** Interval driving the best-effort second-instance detector; `null` when off. */
182
+ secondInstanceDetectionInterval: ReturnType<typeof setInterval> | null;
183
+ /** The active second-instance detector; `null` when detection is disabled. */
184
+ secondInstanceDetector: SecondInstanceDetector | null;
185
+ /**
186
+ * The active lease manager for `ownership: 'lease'`; `null` when ownership is
187
+ * `'none'`. Acquired before recovery, renewed on a heartbeat, released on
188
+ * dispose. Unlike the second-instance detector its acquire/renew errors are real
189
+ * (a failed acquire blocks recovery). Renewal loss is surfaced as a warning in
190
+ * Step 1; epoch fencing of durable writes (Step 2) is what makes it enforceable.
191
+ */
192
+ leaseManager: LeaseManager | null;
193
+ /**
194
+ * The in-flight lease acquisition, or `null` when none is running. Set while
195
+ * `#acquireLeaseIfConfigured` awaits `acquire()` (which can park for the whole
196
+ * `leaseWaitTimeout` waiting for a handoff) and cleared when it settles. Disposal
197
+ * awaits this so a dispose that races a parked acquire is a clean handoff — the
198
+ * holder this engine may take is released before `asyncDispose` resolves, rather
199
+ * than leaking until TTL on an already-disposed engine.
200
+ */
201
+ inFlightLeaseAcquire: Promise<void> | null;
202
+ /**
203
+ * Set to `true` the instant this engine is detected as deposed under
204
+ * `ownership: 'lease'` — either a fenced durable write's CAS failed against a
205
+ * newer epoch ({@link commitFencedEngineWrite}) or the lease manager reported
206
+ * `onLeaseLost('deposed')`. It is the synchronous half of the deposition halt:
207
+ * {@link commitFencedEngineWrite} short-circuits at its top on this flag, so a
208
+ * write that *starts* after detection is rejected before reaching storage,
209
+ * while writes already in flight are caught by the epoch CAS itself. Set once
210
+ * by {@link handleDeposition}, which also warns the operator and schedules a
211
+ * deferred engine teardown. Always `false` under `ownership: 'none'`.
212
+ */
213
+ deposed: boolean;
214
+ /**
215
+ * Teardown callback invoked (deferred to a later tick) when this engine is
216
+ * deposed. Set once during engine construction to the engine's own
217
+ * `disposeAfterDeposition` method. It exists as an injected field rather than a
218
+ * direct import so {@link handleDeposition} (reached from the durable-write
219
+ * helper) does not statically import `disposal.ts`, which would close an import
220
+ * cycle (`storage-io → fenced-write → lease-deposition → disposal → … →
221
+ * storage-io`). `null` until the constructor wires it.
222
+ */
223
+ tearDownAfterDeposition: (() => void) | null;
137
224
  reviewCoordinator: ReviewCoordinator;
138
225
  reviewWaiters: Map<string, (decision: HumanReviewResult) => void>;
139
226
  reviewWaitersByWorkflow: Map<string, TrackedWaiterKeys>;
@@ -144,6 +231,22 @@ export interface EngineInternals {
144
231
  workflowReviewIds: Map<string, Set<string>>;
145
232
  parkedInlineWorkflows: Set<string>;
146
233
  terminalizingWorkflows: Set<string>;
234
+ /**
235
+ * Coordinated update IDs already claimed for delivery by a pending-update
236
+ * drain, keyed by workflow. Several drain triggers (each `update()` schedules a
237
+ * `setTimeout(0)` drain; the post-advance path drains too) can fire
238
+ * near-simultaneously, and the durable consume-delete (`buildResponseOperations`
239
+ * deletes the pending key via async `storage.batch`) lags the in-memory
240
+ * `getPendingUpdates` scan — so overlapping drains would re-read and re-deliver
241
+ * the same buffered update. Each drain claims an update's id SYNCHRONOUSLY (no
242
+ * `await` between the membership check and the add) before delivering it, so a
243
+ * racing drain that scans the same id skips it. The claim persists across
244
+ * drains (unlike a per-drain guard), which is what makes delivery idempotent
245
+ * against the cross-drain race. Cleared per workflow on terminal cleanup; empty
246
+ * after a crash, which matches durable state (recovery re-delivers exactly the
247
+ * updates whose delete never committed).
248
+ */
249
+ deliveredPendingUpdateIds: Map<string, Set<string>>;
147
250
  cancelHandlersByWorkflow: Map<string, Array<() => Promise<void> | void>>;
148
251
  reviewTimerIds: Map<string, string[]>;
149
252
  pendingWebhooks: Set<AbortController>;
@@ -151,7 +254,16 @@ export interface EngineInternals {
151
254
  eventLogHeads: Map<string, Readonly<EventHeadRecord>>;
152
255
  workflowFeedListeners: Map<string, Set<WorkflowFeedListener>>;
153
256
  workflowVersionTuples: Map<string, WorkflowVersionTuple>;
257
+ /**
258
+ * Cached visibility-index watermark for query planning. `undefined` means the
259
+ * watermark has not been read yet or an in-process caller invalidated it.
260
+ * `workflowVisibilityWatermarkExpiresAt` bounds how long external maintenance
261
+ * commands can leave this process planning against a stale watermark.
262
+ */
263
+ workflowVisibilityWatermark: 'current' | 'stale' | undefined;
264
+ workflowVisibilityWatermarkExpiresAt: number | undefined;
154
265
  pendingTimelineEntries: Map<string, PendingTimelineEntry>;
266
+ pendingAtomicWorkflowCommitSideEffects: Map<string, import('./checkpoint-side-effects.ts').AtomicWorkflowCommitSideEffects>;
155
267
  }
156
268
  /**
157
269
  * Set up an empty `EngineInternals` skeleton in the WeakMap. The Engine
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Pure codecs for the two lease ownership keys (`lease:epoch` and `lease:holder`).
3
+ * Extracted from `lease-manager.ts` to keep that file under the `max-lines` ceiling;
4
+ * these functions have no engine state, so they live and test cleanly on their own.
5
+ *
6
+ * @module core/engine/lease-codec
7
+ */
8
+ /** The decoded `lease:holder` record. */
9
+ export type LeaseHolderRecord = {
10
+ holderId: string;
11
+ /** Wall-clock ms (from the engine's `getNow`) after which the lease may be stolen. */
12
+ expiresAt: number;
13
+ /** The ownership epoch this holder acquired. Mirrors `lease:epoch`. */
14
+ epoch: number;
15
+ };
16
+ /**
17
+ * Encode an 8-byte big-endian uint64 epoch. `DataView.setBigUint64` is the
18
+ * standard, overflow-safe encoder — preferred over a hand-rolled byte loop.
19
+ */
20
+ export declare function encodeEpoch(epoch: number): Uint8Array;
21
+ /**
22
+ * Decode an 8-byte big-endian uint64 epoch, or `null` when the stored value is
23
+ * not a usable epoch — not exactly 8 bytes, or outside `[1, MAX_SAFE_INTEGER)`.
24
+ * The epoch is the monotonic fencing high-water mark, so it must stay exactly
25
+ * comparable AND have room to increment: acquisition always mints `epoch + 1`, so
26
+ * `Number.MAX_SAFE_INTEGER` itself is rejected too — minting `2^53` would fail
27
+ * `Number.isSafeInteger` on the next boot and brick the lease. A value at or above
28
+ * the safe-integer ceiling (or below `1`) routes to the corruption path
29
+ * (fail-closed at boot) rather than silently re-minting an imprecise generation.
30
+ */
31
+ export declare function decodeEpoch(raw: Uint8Array): number | null;
32
+ /** Encode a holder record to its stored JSON bytes. */
33
+ export declare function encodeHolder(record: LeaseHolderRecord): Uint8Array;
34
+ /** Decode a stored holder record, tolerating any malformed/foreign value as `null`. */
35
+ export declare function decodeHolder(raw: Uint8Array): LeaseHolderRecord | null;
@@ -0,0 +1,32 @@
1
+ const textEncoder = new TextEncoder, textDecoder = new TextDecoder;
2
+ export function encodeEpoch(epoch) {
3
+ const bytes = new Uint8Array(8);
4
+ new DataView(bytes.buffer).setBigUint64(0, BigInt(epoch), !1);
5
+ return bytes;
6
+ }
7
+ export function decodeEpoch(raw) {
8
+ if (raw.byteLength !== 8)
9
+ return null;
10
+ const value = new DataView(raw.buffer, raw.byteOffset, raw.byteLength).getBigUint64(0, !1), numberValue = Number(value);
11
+ return Number.isSafeInteger(numberValue) && numberValue >= 1 && numberValue < Number.MAX_SAFE_INTEGER ? numberValue : null;
12
+ }
13
+ export function encodeHolder(record) {
14
+ return textEncoder.encode(JSON.stringify(record));
15
+ }
16
+ function isRecord(value) {
17
+ return typeof value === "object" && value !== null;
18
+ }
19
+ export function decodeHolder(raw) {
20
+ let parsed;
21
+ try {
22
+ parsed = JSON.parse(textDecoder.decode(raw));
23
+ } catch {
24
+ return null;
25
+ }
26
+ if (!isRecord(parsed))
27
+ return null;
28
+ const { holderId, expiresAt, epoch } = parsed;
29
+ if (typeof holderId !== "string" || typeof expiresAt !== "number" || !Number.isSafeInteger(expiresAt) || expiresAt < 0 || typeof epoch !== "number" || !Number.isSafeInteger(epoch) || epoch < 1)
30
+ return null;
31
+ return { holderId, expiresAt, epoch };
32
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Deposition handling for `ownership: 'lease'` Step-2 fencing (issue #470).
3
+ *
4
+ * "Deposed" means another instance now holds the ownership lease at a strictly
5
+ * newer epoch, so this instance has lost the store. Deposition is detected at two
6
+ * sites and both funnel here:
7
+ *
8
+ * - A fenced durable write's CAS fails against a newer epoch
9
+ * ({@link commitFencedEngineWrite} re-reads `lease:epoch` to disambiguate).
10
+ * - The lease manager's renewal reports `onLeaseLost('deposed')` (a successor
11
+ * stole the holder out from under an otherwise-idle engine).
12
+ *
13
+ * The renewal-loss reason `'renewal-unconfirmable'` is deliberately NOT routed
14
+ * here: it is a transient storage blip (the holder could not prove it still
15
+ * holds), and halting a healthy holder on a momentary storage hiccup would be a
16
+ * self-inflicted outage. Only a confirmed `'deposed'` triggers the halt.
17
+ *
18
+ * {@link handleDeposition} is idempotent (guarded on {@link EngineInternals.deposed})
19
+ * and does the minimum synchronously — set the flag, warn the operator — then
20
+ * schedules engine teardown on a later tick. Teardown is never run inline:
21
+ * detection happens mid-commit while a workflow generator is advancing, and
22
+ * synchronous {@link disposeEngine} clears maps that the unwinding commit and
23
+ * other in-flight workflows still touch. The flag (plus the
24
+ * {@link commitFencedEngineWrite} top short-circuit) carries the halt guarantee;
25
+ * deferring the actual dispose by a tick is safe because every write in that
26
+ * window is still fenced on the now-stale epoch and loses its CAS.
27
+ *
28
+ * This module is allow-listed for import only from `src/core/engine/**`.
29
+ */
30
+ import type { EngineInternals } from './internals.ts';
31
+ /**
32
+ * The `name` of the `process` warning emitted when an engine configured with
33
+ * `ownership: 'lease'` can no longer be sure it owns the store. The same name
34
+ * covers all three signals, so a single `process.on('warning')` handler catches
35
+ * every "this engine may no longer own the store" event:
36
+ *
37
+ * - **deposed (confirmed)** — a renewal's CAS failed (a successor stole the lease),
38
+ * or a fenced durable write was rejected because a newer epoch holds the store
39
+ * (Step 2). The engine halts.
40
+ * - **renewal-unconfirmable (transient)** — a storage error left the holder unable
41
+ * to prove it still holds within the lease window. This is NOT a confirmed
42
+ * deposition; the engine keeps running, and a later renewal or fenced write
43
+ * resolves the truth. The warning is informational so operators can investigate.
44
+ *
45
+ * Filter on this name to react to ownership-loss signals (alert, drain, restart).
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { ENGINE_LEASE_LOST_WARNING_NAME } from '@lostgradient/weft';
50
+ *
51
+ * process.on('warning', (warning) => {
52
+ * if (warning.name === ENGINE_LEASE_LOST_WARNING_NAME) {
53
+ * // This engine may no longer own the store — investigate / drain / restart.
54
+ * }
55
+ * });
56
+ * ```
57
+ */
58
+ export declare const ENGINE_LEASE_LOST_WARNING_NAME = "WeftEngineLeaseLostWarning";
59
+ /**
60
+ * React to a confirmed deposition. Idempotent: the first call sets the deposed
61
+ * flag, emits the operator warning, and schedules a deferred engine teardown;
62
+ * subsequent calls are no-ops. Returns immediately — the caller is expected to
63
+ * then throw {@link EngineDeposedError} to unwind the current commit so it does
64
+ * not advance in-memory state past a durable write that did not land.
65
+ */
66
+ export declare function handleDeposition(internals: EngineInternals): void;
@@ -0,0 +1,10 @@
1
+ export const ENGINE_LEASE_LOST_WARNING_NAME = "WeftEngineLeaseLostWarning";
2
+ export function handleDeposition(internals) {
3
+ if (internals.deposed)
4
+ return;
5
+ internals.deposed = !0;
6
+ process.emitWarning("engine deposed: a durable write was fenced out because another instance now holds this store's ownership lease at a newer epoch. This engine is halting to avoid split-brain writes. Weft supports one engine process per store; ensure your deploy hands off cleanly (graceful shutdown releases the lease) and keep infrastructure-level single-instance enforcement in place.", ENGINE_LEASE_LOST_WARNING_NAME);
7
+ const tearDown = internals.tearDownAfterDeposition;
8
+ if (tearDown !== null)
9
+ Promise.resolve().then(tearDown).catch(() => {});
10
+ }
@@ -0,0 +1,99 @@
1
+ import { WeftError } from '../weft-error.ts';
2
+ /**
3
+ * Thrown when `ownership: 'lease'` is configured and the engine cannot acquire the
4
+ * storage lease within the configured wait window — another live instance still
5
+ * holds it. Raised from the lease-acquire step, which runs both inside
6
+ * {@link Engine.create} and at the top of {@link Engine.recoverAll} (so a
7
+ * `new Engine({ ownership: 'lease' })` + `recoverAll()` boot must handle it too).
8
+ * In a rolling deploy this means the
9
+ * outgoing instance has not released the lease (or its lease has not yet expired)
10
+ * within `leaseWaitTimeout`; size that window above the outgoing instance's drain
11
+ * time and above the lease TTL so a crash (no clean release) still resolves once
12
+ * the held lease expires. Inspect `waitedMs` for how long this instance waited
13
+ * and `heldBy` for the holder id observed when it gave up (`null` if unknown).
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { EngineLeaseAcquisitionTimeoutError } from '@lostgradient/weft';
18
+ *
19
+ * function isLeaseHandoffStuck(error: unknown): boolean {
20
+ * return error instanceof EngineLeaseAcquisitionTimeoutError;
21
+ * }
22
+ * ```
23
+ */
24
+ export declare class EngineLeaseAcquisitionTimeoutError extends WeftError<'EngineLeaseAcquisitionTimeoutError'> {
25
+ readonly waitedMs: number;
26
+ readonly heldBy: string | null;
27
+ constructor(waitedMs: number, heldBy: string | null);
28
+ }
29
+ /**
30
+ * Thrown when `ownership: 'lease'` is configured but the lease keys in storage are
31
+ * corrupt. Raised from the lease-acquire step, which runs both inside
32
+ * {@link Engine.create} and at the top of {@link Engine.recoverAll} (so a
33
+ * `new Engine({ ownership: 'lease' })` + `recoverAll()` boot must handle it too) —
34
+ * the `lease:epoch` high-water mark is present
35
+ * but does not decode to a valid epoch, or a holder record exists with no epoch
36
+ * key (which the lease protocol never produces, since `release()` deletes only the
37
+ * holder and never the epoch). The lease epoch is the sole source of truth for the
38
+ * monotonic fencing generation, so a booting instance fails closed rather than
39
+ * re-minting a generation at or below the true high-water mark and risking a
40
+ * split-brain. Resolve by operator repair: delete both `lease:` keys only if you
41
+ * are certain no other instance is running, or reset `lease:epoch` above its last
42
+ * known value.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { EngineLeaseCorruptedError } from '@lostgradient/weft';
47
+ *
48
+ * function isLeaseCorrupted(error: unknown): boolean {
49
+ * return error instanceof EngineLeaseCorruptedError;
50
+ * }
51
+ * ```
52
+ */
53
+ export declare class EngineLeaseCorruptedError extends WeftError<'EngineLeaseCorruptedError'> {
54
+ constructor(detail: string);
55
+ }
56
+ /**
57
+ * Thrown by {@link Engine.start} and {@link Engine.startOrSignal} when
58
+ * `ownership: 'lease'` is configured but the engine does not yet hold the lease —
59
+ * it was constructed with `new Engine({ ownership: 'lease' })` and used to start
60
+ * work before `recoverAll()` ran, or created with `recover: false`. In lease mode
61
+ * an engine must hold the single-writer lease (and have recovered existing runs)
62
+ * before it durably writes new workflow state, or a fresh start could race an
63
+ * instance that legitimately owns the store. {@link Engine.create} acquires the
64
+ * lease and recovers for you; a direct constructor must `await engine.recoverAll()`
65
+ * first.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * import { Engine, EngineLeaseNotHeldError } from '@lostgradient/weft';
70
+ *
71
+ * const engine = new Engine({ ownership: 'lease' });
72
+ * try {
73
+ * await engine.start('ping', null);
74
+ * } catch (error) {
75
+ * if (error instanceof EngineLeaseNotHeldError) {
76
+ * await engine.recoverAll(); // acquires the lease, then retry the start
77
+ * }
78
+ * }
79
+ * ```
80
+ */
81
+ export declare class EngineLeaseNotHeldError extends WeftError<'EngineLeaseNotHeldError'> {
82
+ constructor();
83
+ }
84
+ /**
85
+ * Thrown internally on the durable-write path when `ownership: 'lease'` is
86
+ * configured and a fenced write's CAS fails because the held lease epoch is
87
+ * stale — a successor instance has taken the lease and bumped the epoch, so this
88
+ * instance has been deposed. It is the local unwind that stops the commit from
89
+ * advancing in-memory state past a durable write that did not land; the actual
90
+ * "this engine is deposed" reaction (set the `deposed` flag, warn the operator,
91
+ * tear the engine down) is driven by {@link handleDeposition} at the detection
92
+ * site, not by this error propagating — the inline strategy swallows turn
93
+ * rejections, so the throw never reaches a handler. Internal-only: it is never
94
+ * surfaced to user code (deposition reaches operators through the
95
+ * `WeftEngineLeaseLostWarning` process warning).
96
+ */
97
+ export declare class EngineDeposedError extends WeftError<'EngineDeposedError'> {
98
+ constructor();
99
+ }
@@ -0,0 +1,30 @@
1
+ import { WeftError } from "../weft-error.js";
2
+
3
+ export class EngineLeaseAcquisitionTimeoutError extends WeftError {
4
+ waitedMs;
5
+ heldBy;
6
+ constructor(waitedMs, heldBy) {
7
+ const heldClause = heldBy === null ? "" : ` (currently held by "${heldBy}")`;
8
+ super("EngineLeaseAcquisitionTimeoutError", `Could not acquire the storage ownership lease within ${waitedMs}ms${heldClause}. Another engine instance still holds it. Increase leaseWaitTimeout above the outgoing instance's drain time and the lease TTL, or ensure the previous instance releases the lease on shutdown.`);
9
+ this.waitedMs = waitedMs;
10
+ this.heldBy = heldBy;
11
+ }
12
+ }
13
+
14
+ export class EngineLeaseCorruptedError extends WeftError {
15
+ constructor(detail) {
16
+ super("EngineLeaseCorruptedError", `The ownership lease state in storage is corrupt and cannot be used safely: ${detail}. Resolve by operator repair (delete both "lease:" keys only if no other instance is running, or reset "lease:epoch" above its last known value).`);
17
+ }
18
+ }
19
+
20
+ export class EngineLeaseNotHeldError extends WeftError {
21
+ constructor() {
22
+ super("EngineLeaseNotHeldError", "ownership: 'lease' requires the engine to hold the lease before starting work. Use `Engine.create({ ownership: \"lease\" })` (which acquires the lease and recovers), or call `await engine.recoverAll()` on a directly-constructed engine before `start()`.");
23
+ }
24
+ }
25
+
26
+ export class EngineDeposedError extends WeftError {
27
+ constructor() {
28
+ super("EngineDeposedError", "Engine was deposed: a fenced durable write lost its CAS race because another instance now holds the ownership lease at a newer epoch. This engine is halting.");
29
+ }
30
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Lease-fenced single-writer ownership over a shared durable store. This is the
3
+ * opt-in `Engine.create({ ownership: 'lease' })` mechanism — a CORRECTNESS-PATH
4
+ * coordinator, NOT a best-effort smoke alarm like the second-instance detector.
5
+ * Lease outcomes are acted on, never silently dropped, but the channel differs by
6
+ * phase: a failed acquire THROWS and blocks recovery (corruption fails closed, a
7
+ * timed-out handoff raises a typed error); a renewal reports loss through
8
+ * `onLeaseLost` rather than throwing — a CAS-failed renewal means a successor took
9
+ * the lease ('deposed'), and a transient renewal storage error is tolerated until
10
+ * the lease is too close to lapsing to prove ownership ('renewal-unconfirmable').
11
+ * In Step 1 that loss is observability only (the engine warns); Step 2 will make it
12
+ * enforceable by fencing every durable write on the lease epoch.
13
+ *
14
+ * **Why a lease.** Weft's supported model is one engine process per durable
15
+ * store. Without a lease, a rolling deploy briefly runs two engines (old draining
16
+ * + new booting), both recovering and both issuing at-least-once activities. The
17
+ * lease turns that into a clean handoff: the booting instance ACQUIRES the lease
18
+ * before recovering, the draining instance RELEASES it on dispose, and the new
19
+ * instance only recovers once it owns the lease.
20
+ *
21
+ * **Two-key schema (this is load-bearing, not an optimization).** Ownership is
22
+ * tracked by two keys, never one:
23
+ *
24
+ * - `lease:epoch` — an 8-byte big-endian uint64 fencing token. It changes ONLY on
25
+ * ownership transfer (cold acquire, or a steal/re-acquire after the prior
26
+ * holder's lease lapsed), NEVER on a renewal. It is a monotonic high-water mark
27
+ * that SURVIVES release.
28
+ * - `lease:holder` — a JSON `{ holderId, expiresAt, epoch }` record renewed on
29
+ * every heartbeat (its `expiresAt` advances), so its bytes churn constantly.
30
+ *
31
+ * They are split because `conditionalBatch` compares the WHOLE stored value as
32
+ * bytes. If the epoch lived inside the churning holder record, the fencing token
33
+ * (Step 2) would change on every renewal, spuriously failing the fence and
34
+ * self-terminating healthy holders. Keeping the epoch in its own stable key lets
35
+ * a holder cache its epoch once ({@link LeaseManager.currentEpochBytes}) and use
36
+ * it unchanged as a fencing condition across many renewals.
37
+ *
38
+ * **Epoch monotonicity is the anti-split-brain invariant.** Every transfer
39
+ * conditions on BOTH the holder AND the current epoch and bumps the epoch by one;
40
+ * `release()` deletes ONLY the holder and never the epoch. This guarantees a
41
+ * deposed zombie from generation N can never see its epoch re-minted under it —
42
+ * so once Step 2 fences durable writes on the epoch, the zombie always loses.
43
+ *
44
+ * @module core/engine/lease-manager
45
+ */
46
+ import { type Storage } from '../../storage/interface.ts';
47
+ /** Why a holder lost its lease — surfaced to {@link LeaseManagerOptions.onLeaseLost}. */
48
+ export type LeaseLostReason = 'deposed' | 'renewal-unconfirmable';
49
+ /** Options for {@link createLeaseManager}. */
50
+ export type LeaseManagerOptions = {
51
+ storage: Storage;
52
+ /** This engine's unique instance id (the lease holder id). */
53
+ holderId: string;
54
+ /** Wall-clock source (ms), injected so tests can advance time deterministically. */
55
+ getNow: () => number;
56
+ /** Lease time-to-live (ms). A stolen lease becomes available `ttlMs` after its last renewal. */
57
+ ttlMs: number;
58
+ /** Renewal interval (ms). The holder re-asserts the lease this often; must be `< ttlMs`. */
59
+ renewIntervalMs: number;
60
+ /** Boot-time wait window (ms) before {@link LeaseManager.acquire} throws. */
61
+ waitTimeoutMs: number;
62
+ /** Poll interval (ms) for the acquire wait loop. */
63
+ acquirePollIntervalMs?: number;
64
+ /**
65
+ * Delay primitive for the acquire poll loop. Defaults to a real `setTimeout`.
66
+ * Injected so tests drive the loop deterministically: a test `delay` advances
67
+ * the same injected clock by the poll interval and resolves immediately, so the
68
+ * wait deadline (read from `getNow`) trips without real waiting. Mirrors the
69
+ * `getNow` injection — not test-only scaffolding.
70
+ */
71
+ delay?: (ms: number) => Promise<void>;
72
+ /**
73
+ * Called once when this holder loses the lease while running — either CAS-false
74
+ * on renewal (`'deposed'`: a successor stole it) or storage failures that make
75
+ * the holder unable to prove it still holds before the lease lapses
76
+ * (`'renewal-unconfirmable'`). In Step 1 the engine reacts by warning; Step 2
77
+ * uses this to halt fenced writes. The lease manager never throws into the
78
+ * renewal timer — it reports through this seam instead.
79
+ */
80
+ onLeaseLost?: (reason: LeaseLostReason) => void;
81
+ };
82
+ /**
83
+ * A running lease manager.
84
+ *
85
+ * - `acquire()` blocks until this instance owns the lease, then resolves; throws
86
+ * {@link EngineLeaseAcquisitionTimeoutError} on timeout. Call before recovery.
87
+ * One exception to "resolved ⇒ owned": if the manager was `stop()`ped (disposal)
88
+ * while acquire was waiting, it resolves WITHOUT owning — the engine gates
89
+ * recovery on `disposed` so a stopped-then-resolved acquire never proceeds.
90
+ * - `startRenewal()` begins the heartbeat that keeps the lease held (drives
91
+ * {@link LeaseManager.renewOnce} on an interval).
92
+ * - `renewOnce()` runs a single renewal round; exposed for tests so renewal can be
93
+ * driven deterministically with an injected clock, mirroring the detector's
94
+ * `tick()`.
95
+ * - `currentEpochBytes()` returns the held epoch as bytes for Step-2 fencing
96
+ * conditions; `null` before a successful acquire. Synchronous and stable across
97
+ * renewals.
98
+ * - `release()` best-effort relinquishes the lease (holder key only) on dispose.
99
+ */
100
+ export type LeaseManager = {
101
+ acquire(): Promise<void>;
102
+ startRenewal(): void;
103
+ renewOnce(): Promise<void>;
104
+ currentEpochBytes(): Uint8Array | null;
105
+ release(): Promise<void>;
106
+ stop(): void;
107
+ };
108
+ /**
109
+ * Create a lease manager. Does not start any timer or acquire anything itself —
110
+ * the engine drives `acquire()` at the boot gate (before recovery) and
111
+ * `startRenewal()` afterward, and clears the renewal timer through its own
112
+ * disposal path (mirroring how it owns the second-instance detector's interval).
113
+ */
114
+ export declare function createLeaseManager(options: LeaseManagerOptions): LeaseManager;