@smthrs/engine-store 0.0.0-stage → 1.0.0-rc.4

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 (787) hide show
  1. package/CHANGELOG.md +247 -0
  2. package/LICENSE +21 -0
  3. package/README.md +146 -2
  4. package/dist/cjs/ArtifactGc.d.ts +235 -0
  5. package/dist/cjs/ArtifactGc.d.ts.map +1 -0
  6. package/dist/cjs/ArtifactGc.js +183 -0
  7. package/dist/cjs/ArtifactGc.js.map +7 -0
  8. package/dist/cjs/ArtifactSync.d.ts +164 -0
  9. package/dist/cjs/ArtifactSync.d.ts.map +1 -0
  10. package/dist/cjs/ArtifactSync.js +144 -0
  11. package/dist/cjs/ArtifactSync.js.map +7 -0
  12. package/dist/cjs/CacheSync.d.ts +112 -0
  13. package/dist/cjs/CacheSync.d.ts.map +1 -0
  14. package/dist/cjs/CacheSync.js +64 -0
  15. package/dist/cjs/CacheSync.js.map +7 -0
  16. package/dist/cjs/DeferredClockFold.d.ts +354 -0
  17. package/dist/cjs/DeferredClockFold.d.ts.map +1 -0
  18. package/dist/cjs/DeferredClockFold.js +335 -0
  19. package/dist/cjs/DeferredClockFold.js.map +7 -0
  20. package/dist/cjs/DisasterRecovery.d.ts +431 -0
  21. package/dist/cjs/DisasterRecovery.d.ts.map +1 -0
  22. package/dist/cjs/DisasterRecovery.js +453 -0
  23. package/dist/cjs/DisasterRecovery.js.map +7 -0
  24. package/dist/cjs/DurableEngineState.d.ts +776 -0
  25. package/dist/cjs/DurableEngineState.d.ts.map +1 -0
  26. package/dist/cjs/DurableEngineState.js +1536 -0
  27. package/dist/cjs/DurableEngineState.js.map +7 -0
  28. package/dist/cjs/EngineStore.d.ts +158 -0
  29. package/dist/cjs/EngineStore.d.ts.map +1 -0
  30. package/dist/cjs/EngineStore.js +398 -0
  31. package/dist/cjs/EngineStore.js.map +7 -0
  32. package/dist/cjs/EngineStoreMetrics.d.ts +276 -0
  33. package/dist/cjs/EngineStoreMetrics.d.ts.map +1 -0
  34. package/dist/cjs/EngineStoreMetrics.js +135 -0
  35. package/dist/cjs/EngineStoreMetrics.js.map +7 -0
  36. package/dist/cjs/Errors.d.ts +22 -0
  37. package/dist/cjs/Errors.d.ts.map +1 -0
  38. package/dist/cjs/Errors.js +39 -0
  39. package/dist/cjs/Errors.js.map +7 -0
  40. package/dist/cjs/EventTypes.d.ts +27 -0
  41. package/dist/cjs/EventTypes.d.ts.map +1 -0
  42. package/dist/cjs/EventTypes.js +37 -0
  43. package/dist/cjs/EventTypes.js.map +7 -0
  44. package/dist/cjs/ExecutionFacts.d.ts +59 -0
  45. package/dist/cjs/ExecutionFacts.d.ts.map +1 -0
  46. package/dist/cjs/ExecutionFacts.js +123 -0
  47. package/dist/cjs/ExecutionFacts.js.map +7 -0
  48. package/dist/cjs/ExecutionSnapshot.d.ts +117 -0
  49. package/dist/cjs/ExecutionSnapshot.d.ts.map +1 -0
  50. package/dist/cjs/ExecutionSnapshot.js +111 -0
  51. package/dist/cjs/ExecutionSnapshot.js.map +7 -0
  52. package/dist/cjs/Inconsistency.d.ts +154 -0
  53. package/dist/cjs/Inconsistency.d.ts.map +1 -0
  54. package/dist/cjs/Inconsistency.js +135 -0
  55. package/dist/cjs/Inconsistency.js.map +7 -0
  56. package/dist/cjs/Migrations.d.ts +56 -0
  57. package/dist/cjs/Migrations.d.ts.map +1 -0
  58. package/dist/cjs/Migrations.js +78 -0
  59. package/dist/cjs/Migrations.js.map +7 -0
  60. package/dist/cjs/OwnerIdentity.d.ts +91 -0
  61. package/dist/cjs/OwnerIdentity.d.ts.map +1 -0
  62. package/dist/cjs/OwnerIdentity.js +65 -0
  63. package/dist/cjs/OwnerIdentity.js.map +7 -0
  64. package/dist/cjs/PlanInputStore.d.ts +110 -0
  65. package/dist/cjs/PlanInputStore.d.ts.map +1 -0
  66. package/dist/cjs/PlanInputStore.js +224 -0
  67. package/dist/cjs/PlanInputStore.js.map +7 -0
  68. package/dist/cjs/PlanMergeStore.d.ts +113 -0
  69. package/dist/cjs/PlanMergeStore.d.ts.map +1 -0
  70. package/dist/cjs/PlanMergeStore.js +255 -0
  71. package/dist/cjs/PlanMergeStore.js.map +7 -0
  72. package/dist/cjs/PlanScheduler.d.ts +363 -0
  73. package/dist/cjs/PlanScheduler.d.ts.map +1 -0
  74. package/dist/cjs/PlanScheduler.js +1090 -0
  75. package/dist/cjs/PlanScheduler.js.map +7 -0
  76. package/dist/cjs/Reconciliation.d.ts +175 -0
  77. package/dist/cjs/Reconciliation.d.ts.map +1 -0
  78. package/dist/cjs/Reconciliation.js +119 -0
  79. package/dist/cjs/Reconciliation.js.map +7 -0
  80. package/dist/cjs/ReplayOnly.d.ts +91 -0
  81. package/dist/cjs/ReplayOnly.d.ts.map +1 -0
  82. package/dist/cjs/ReplayOnly.js +52 -0
  83. package/dist/cjs/ReplayOnly.js.map +7 -0
  84. package/dist/cjs/Retention.d.ts +113 -0
  85. package/dist/cjs/Retention.d.ts.map +1 -0
  86. package/dist/cjs/Retention.js +99 -0
  87. package/dist/cjs/Retention.js.map +7 -0
  88. package/dist/cjs/RunCatalogRead.d.ts +17 -0
  89. package/dist/cjs/RunCatalogRead.d.ts.map +1 -0
  90. package/dist/cjs/RunCatalogRead.js +33 -0
  91. package/dist/cjs/RunCatalogRead.js.map +7 -0
  92. package/dist/cjs/RunChangeFeed.d.ts +75 -0
  93. package/dist/cjs/RunChangeFeed.d.ts.map +1 -0
  94. package/dist/cjs/RunChangeFeed.js +96 -0
  95. package/dist/cjs/RunChangeFeed.js.map +7 -0
  96. package/dist/cjs/RunState.d.ts +116 -0
  97. package/dist/cjs/RunState.d.ts.map +1 -0
  98. package/dist/cjs/RunState.js +76 -0
  99. package/dist/cjs/RunState.js.map +7 -0
  100. package/dist/cjs/Selection.d.ts +495 -0
  101. package/dist/cjs/Selection.d.ts.map +1 -0
  102. package/dist/cjs/Selection.js +288 -0
  103. package/dist/cjs/Selection.js.map +7 -0
  104. package/dist/cjs/SelectionStore.d.ts +141 -0
  105. package/dist/cjs/SelectionStore.d.ts.map +1 -0
  106. package/dist/cjs/SelectionStore.js +229 -0
  107. package/dist/cjs/SelectionStore.js.map +7 -0
  108. package/dist/cjs/StepBoundary.d.ts +501 -0
  109. package/dist/cjs/StepBoundary.d.ts.map +1 -0
  110. package/dist/cjs/StepBoundary.js +619 -0
  111. package/dist/cjs/StepBoundary.js.map +7 -0
  112. package/dist/cjs/StepCacheFold.d.ts +148 -0
  113. package/dist/cjs/StepCacheFold.d.ts.map +1 -0
  114. package/dist/cjs/StepCacheFold.js +131 -0
  115. package/dist/cjs/StepCacheFold.js.map +7 -0
  116. package/dist/cjs/StepSandbox.d.ts +78 -0
  117. package/dist/cjs/StepSandbox.d.ts.map +1 -0
  118. package/dist/cjs/StepSandbox.js +75 -0
  119. package/dist/cjs/StepSandbox.js.map +7 -0
  120. package/dist/cjs/WakeBus.d.ts +116 -0
  121. package/dist/cjs/WakeBus.d.ts.map +1 -0
  122. package/dist/cjs/WakeBus.js +89 -0
  123. package/dist/cjs/WakeBus.js.map +7 -0
  124. package/dist/cjs/WorkspaceSandbox.d.ts +619 -0
  125. package/dist/cjs/WorkspaceSandbox.d.ts.map +1 -0
  126. package/dist/cjs/WorkspaceSandbox.js +711 -0
  127. package/dist/cjs/WorkspaceSandbox.js.map +7 -0
  128. package/dist/cjs/index.d.ts +157 -0
  129. package/dist/cjs/index.d.ts.map +1 -0
  130. package/dist/cjs/index.js +95 -0
  131. package/dist/cjs/index.js.map +7 -0
  132. package/dist/cjs/internal/ActionPersistence.d.ts +276 -0
  133. package/dist/cjs/internal/ActionPersistence.d.ts.map +1 -0
  134. package/dist/cjs/internal/ActionPersistence.js +1395 -0
  135. package/dist/cjs/internal/ActionPersistence.js.map +7 -0
  136. package/dist/cjs/internal/ArtifactRoots.d.ts +38 -0
  137. package/dist/cjs/internal/ArtifactRoots.d.ts.map +1 -0
  138. package/dist/cjs/internal/ArtifactRoots.js +89 -0
  139. package/dist/cjs/internal/ArtifactRoots.js.map +7 -0
  140. package/dist/cjs/internal/AttemptAdmission.d.ts +53 -0
  141. package/dist/cjs/internal/AttemptAdmission.d.ts.map +1 -0
  142. package/dist/cjs/internal/AttemptAdmission.js +52 -0
  143. package/dist/cjs/internal/AttemptAdmission.js.map +7 -0
  144. package/dist/cjs/internal/AttemptLifecycle.d.ts +245 -0
  145. package/dist/cjs/internal/AttemptLifecycle.d.ts.map +1 -0
  146. package/dist/cjs/internal/AttemptLifecycle.js +112 -0
  147. package/dist/cjs/internal/AttemptLifecycle.js.map +7 -0
  148. package/dist/cjs/internal/AttemptProbe.d.ts +53 -0
  149. package/dist/cjs/internal/AttemptProbe.d.ts.map +1 -0
  150. package/dist/cjs/internal/AttemptProbe.js +66 -0
  151. package/dist/cjs/internal/AttemptProbe.js.map +7 -0
  152. package/dist/cjs/internal/CacheAdmission.d.ts +79 -0
  153. package/dist/cjs/internal/CacheAdmission.d.ts.map +1 -0
  154. package/dist/cjs/internal/CacheAdmission.js +71 -0
  155. package/dist/cjs/internal/CacheAdmission.js.map +7 -0
  156. package/dist/cjs/internal/CacheAgeHistory.d.ts +27 -0
  157. package/dist/cjs/internal/CacheAgeHistory.d.ts.map +1 -0
  158. package/dist/cjs/internal/CacheAgeHistory.js +61 -0
  159. package/dist/cjs/internal/CacheAgeHistory.js.map +7 -0
  160. package/dist/cjs/internal/CacheAgeVerdicts.d.ts +15 -0
  161. package/dist/cjs/internal/CacheAgeVerdicts.d.ts.map +1 -0
  162. package/dist/cjs/internal/CacheAgeVerdicts.js +73 -0
  163. package/dist/cjs/internal/CacheAgeVerdicts.js.map +7 -0
  164. package/dist/cjs/internal/CacheOutputPolicy.d.ts +24 -0
  165. package/dist/cjs/internal/CacheOutputPolicy.d.ts.map +1 -0
  166. package/dist/cjs/internal/CacheOutputPolicy.js +75 -0
  167. package/dist/cjs/internal/CacheOutputPolicy.js.map +7 -0
  168. package/dist/cjs/internal/CachePublication.d.ts +97 -0
  169. package/dist/cjs/internal/CachePublication.d.ts.map +1 -0
  170. package/dist/cjs/internal/CachePublication.js +80 -0
  171. package/dist/cjs/internal/CachePublication.js.map +7 -0
  172. package/dist/cjs/internal/CallFacts.d.ts +15 -0
  173. package/dist/cjs/internal/CallFacts.d.ts.map +1 -0
  174. package/dist/cjs/internal/CallFacts.js +97 -0
  175. package/dist/cjs/internal/CallFacts.js.map +7 -0
  176. package/dist/cjs/internal/CopiedRecord.d.ts +61 -0
  177. package/dist/cjs/internal/CopiedRecord.d.ts.map +1 -0
  178. package/dist/cjs/internal/CopiedRecord.js +134 -0
  179. package/dist/cjs/internal/CopiedRecord.js.map +7 -0
  180. package/dist/cjs/internal/DeferredPersistence.d.ts +108 -0
  181. package/dist/cjs/internal/DeferredPersistence.d.ts.map +1 -0
  182. package/dist/cjs/internal/DeferredPersistence.js +270 -0
  183. package/dist/cjs/internal/DeferredPersistence.js.map +7 -0
  184. package/dist/cjs/internal/EffectRecords.d.ts +92 -0
  185. package/dist/cjs/internal/EffectRecords.d.ts.map +1 -0
  186. package/dist/cjs/internal/EffectRecords.js +63 -0
  187. package/dist/cjs/internal/EffectRecords.js.map +7 -0
  188. package/dist/cjs/internal/EngineJj.d.ts +30 -0
  189. package/dist/cjs/internal/EngineJj.d.ts.map +1 -0
  190. package/dist/cjs/internal/EngineJj.js +42 -0
  191. package/dist/cjs/internal/EngineJj.js.map +7 -0
  192. package/dist/cjs/internal/EngineStateSchema.d.ts +68 -0
  193. package/dist/cjs/internal/EngineStateSchema.d.ts.map +1 -0
  194. package/dist/cjs/internal/EngineStateSchema.js +58 -0
  195. package/dist/cjs/internal/EngineStateSchema.js.map +7 -0
  196. package/dist/cjs/internal/ExecutionSnapshotRead.d.ts +162 -0
  197. package/dist/cjs/internal/ExecutionSnapshotRead.d.ts.map +1 -0
  198. package/dist/cjs/internal/ExecutionSnapshotRead.js +201 -0
  199. package/dist/cjs/internal/ExecutionSnapshotRead.js.map +7 -0
  200. package/dist/cjs/internal/ExecutionSnapshotRelations.d.ts +39 -0
  201. package/dist/cjs/internal/ExecutionSnapshotRelations.d.ts.map +1 -0
  202. package/dist/cjs/internal/ExecutionSnapshotRelations.js +105 -0
  203. package/dist/cjs/internal/ExecutionSnapshotRelations.js.map +7 -0
  204. package/dist/cjs/internal/ExitEncoding.d.ts +180 -0
  205. package/dist/cjs/internal/ExitEncoding.d.ts.map +1 -0
  206. package/dist/cjs/internal/ExitEncoding.js +236 -0
  207. package/dist/cjs/internal/ExitEncoding.js.map +7 -0
  208. package/dist/cjs/internal/FileBoundarySnapshot.d.ts +14 -0
  209. package/dist/cjs/internal/FileBoundarySnapshot.d.ts.map +1 -0
  210. package/dist/cjs/internal/FileBoundarySnapshot.js +51 -0
  211. package/dist/cjs/internal/FileBoundarySnapshot.js.map +7 -0
  212. package/dist/cjs/internal/FileEnumeration.d.ts +127 -0
  213. package/dist/cjs/internal/FileEnumeration.d.ts.map +1 -0
  214. package/dist/cjs/internal/FileEnumeration.js +194 -0
  215. package/dist/cjs/internal/FileEnumeration.js.map +7 -0
  216. package/dist/cjs/internal/HostReflection.d.ts +80 -0
  217. package/dist/cjs/internal/HostReflection.d.ts.map +1 -0
  218. package/dist/cjs/internal/HostReflection.js +43 -0
  219. package/dist/cjs/internal/HostReflection.js.map +7 -0
  220. package/dist/cjs/internal/JournalRecords.d.ts +325 -0
  221. package/dist/cjs/internal/JournalRecords.d.ts.map +1 -0
  222. package/dist/cjs/internal/JournalRecords.js +122 -0
  223. package/dist/cjs/internal/JournalRecords.js.map +7 -0
  224. package/dist/cjs/internal/NodeJournal.d.ts +157 -0
  225. package/dist/cjs/internal/NodeJournal.d.ts.map +1 -0
  226. package/dist/cjs/internal/NodeJournal.js +192 -0
  227. package/dist/cjs/internal/NodeJournal.js.map +7 -0
  228. package/dist/cjs/internal/Ordering.d.ts +14 -0
  229. package/dist/cjs/internal/Ordering.d.ts.map +1 -0
  230. package/dist/cjs/internal/Ordering.js +25 -0
  231. package/dist/cjs/internal/Ordering.js.map +7 -0
  232. package/dist/cjs/internal/PlanInputs.d.ts +14 -0
  233. package/dist/cjs/internal/PlanInputs.d.ts.map +1 -0
  234. package/dist/cjs/internal/PlanInputs.js +78 -0
  235. package/dist/cjs/internal/PlanInputs.js.map +7 -0
  236. package/dist/cjs/internal/PlanMerges.d.ts +178 -0
  237. package/dist/cjs/internal/PlanMerges.d.ts.map +1 -0
  238. package/dist/cjs/internal/PlanMerges.js +125 -0
  239. package/dist/cjs/internal/PlanMerges.js.map +7 -0
  240. package/dist/cjs/internal/ProvenanceSlot.d.ts +30 -0
  241. package/dist/cjs/internal/ProvenanceSlot.d.ts.map +1 -0
  242. package/dist/cjs/internal/ProvenanceSlot.js +53 -0
  243. package/dist/cjs/internal/ProvenanceSlot.js.map +7 -0
  244. package/dist/cjs/internal/ResultEnvelope.d.ts +88 -0
  245. package/dist/cjs/internal/ResultEnvelope.d.ts.map +1 -0
  246. package/dist/cjs/internal/ResultEnvelope.js +90 -0
  247. package/dist/cjs/internal/ResultEnvelope.js.map +7 -0
  248. package/dist/cjs/internal/RetentionOps.d.ts +414 -0
  249. package/dist/cjs/internal/RetentionOps.d.ts.map +1 -0
  250. package/dist/cjs/internal/RetentionOps.js +354 -0
  251. package/dist/cjs/internal/RetentionOps.js.map +7 -0
  252. package/dist/cjs/internal/RunCatalogOps.d.ts +118 -0
  253. package/dist/cjs/internal/RunCatalogOps.d.ts.map +1 -0
  254. package/dist/cjs/internal/RunCatalogOps.js +85 -0
  255. package/dist/cjs/internal/RunCatalogOps.js.map +7 -0
  256. package/dist/cjs/internal/RunCoordinator.d.ts +78 -0
  257. package/dist/cjs/internal/RunCoordinator.d.ts.map +1 -0
  258. package/dist/cjs/internal/RunCoordinator.js +123 -0
  259. package/dist/cjs/internal/RunCoordinator.js.map +7 -0
  260. package/dist/cjs/internal/RunDriver.d.ts +192 -0
  261. package/dist/cjs/internal/RunDriver.d.ts.map +1 -0
  262. package/dist/cjs/internal/RunDriver.js +1586 -0
  263. package/dist/cjs/internal/RunDriver.js.map +7 -0
  264. package/dist/cjs/internal/RunLifecycle.d.ts +22 -0
  265. package/dist/cjs/internal/RunLifecycle.d.ts.map +1 -0
  266. package/dist/cjs/internal/RunLifecycle.js +63 -0
  267. package/dist/cjs/internal/RunLifecycle.js.map +7 -0
  268. package/dist/cjs/internal/RunListing.d.ts +78 -0
  269. package/dist/cjs/internal/RunListing.d.ts.map +1 -0
  270. package/dist/cjs/internal/RunListing.js +171 -0
  271. package/dist/cjs/internal/RunListing.js.map +7 -0
  272. package/dist/cjs/internal/RunListingError.d.ts +35 -0
  273. package/dist/cjs/internal/RunListingError.d.ts.map +1 -0
  274. package/dist/cjs/internal/RunListingError.js +47 -0
  275. package/dist/cjs/internal/RunListingError.js.map +7 -0
  276. package/dist/cjs/internal/RuntimeGraph.d.ts +73 -0
  277. package/dist/cjs/internal/RuntimeGraph.d.ts.map +1 -0
  278. package/dist/cjs/internal/RuntimeGraph.js +180 -0
  279. package/dist/cjs/internal/RuntimeGraph.js.map +7 -0
  280. package/dist/cjs/internal/SandboxedExecution.d.ts +80 -0
  281. package/dist/cjs/internal/SandboxedExecution.d.ts.map +1 -0
  282. package/dist/cjs/internal/SandboxedExecution.js +104 -0
  283. package/dist/cjs/internal/SandboxedExecution.js.map +7 -0
  284. package/dist/cjs/internal/StateTransaction.d.ts +44 -0
  285. package/dist/cjs/internal/StateTransaction.d.ts.map +1 -0
  286. package/dist/cjs/internal/StateTransaction.js +52 -0
  287. package/dist/cjs/internal/StateTransaction.js.map +7 -0
  288. package/dist/cjs/internal/StepFacts.d.ts +14 -0
  289. package/dist/cjs/internal/StepFacts.d.ts.map +1 -0
  290. package/dist/cjs/internal/StepFacts.js +58 -0
  291. package/dist/cjs/internal/StepFacts.js.map +7 -0
  292. package/dist/cjs/internal/TypedEvents.d.ts +14 -0
  293. package/dist/cjs/internal/TypedEvents.d.ts.map +1 -0
  294. package/dist/cjs/internal/TypedEvents.js +37 -0
  295. package/dist/cjs/internal/TypedEvents.js.map +7 -0
  296. package/dist/cjs/migrations/0001_initial.d.ts +17 -0
  297. package/dist/cjs/migrations/0001_initial.d.ts.map +1 -0
  298. package/dist/cjs/migrations/0001_initial.js +61 -0
  299. package/dist/cjs/migrations/0001_initial.js.map +7 -0
  300. package/dist/cjs/migrations/0002_selection_store.d.ts +15 -0
  301. package/dist/cjs/migrations/0002_selection_store.d.ts.map +1 -0
  302. package/dist/cjs/migrations/0002_selection_store.js +56 -0
  303. package/dist/cjs/migrations/0002_selection_store.js.map +7 -0
  304. package/dist/cjs/migrations/0003_plan_inputs.d.ts +13 -0
  305. package/dist/cjs/migrations/0003_plan_inputs.d.ts.map +1 -0
  306. package/dist/cjs/migrations/0003_plan_inputs.js +90 -0
  307. package/dist/cjs/migrations/0003_plan_inputs.js.map +7 -0
  308. package/dist/cjs/migrations/0004_plan_environment.d.ts +14 -0
  309. package/dist/cjs/migrations/0004_plan_environment.d.ts.map +1 -0
  310. package/dist/cjs/migrations/0004_plan_environment.js +56 -0
  311. package/dist/cjs/migrations/0004_plan_environment.js.map +7 -0
  312. package/dist/cjs/migrations/0005_plan_merges.d.ts +14 -0
  313. package/dist/cjs/migrations/0005_plan_merges.d.ts.map +1 -0
  314. package/dist/cjs/migrations/0005_plan_merges.js +82 -0
  315. package/dist/cjs/migrations/0005_plan_merges.js.map +7 -0
  316. package/dist/cjs/migrations/0006_execution_listing.d.ts +15 -0
  317. package/dist/cjs/migrations/0006_execution_listing.d.ts.map +1 -0
  318. package/dist/cjs/migrations/0006_execution_listing.js +101 -0
  319. package/dist/cjs/migrations/0006_execution_listing.js.map +7 -0
  320. package/dist/cjs/migrations/0007_run_parent_sequence.d.ts +15 -0
  321. package/dist/cjs/migrations/0007_run_parent_sequence.d.ts.map +1 -0
  322. package/dist/cjs/migrations/0007_run_parent_sequence.js +40 -0
  323. package/dist/cjs/migrations/0007_run_parent_sequence.js.map +7 -0
  324. package/dist/cjs/migrations/0008_deferred_consumption.d.ts +16 -0
  325. package/dist/cjs/migrations/0008_deferred_consumption.d.ts.map +1 -0
  326. package/dist/cjs/migrations/0008_deferred_consumption.js +45 -0
  327. package/dist/cjs/migrations/0008_deferred_consumption.js.map +7 -0
  328. package/dist/cjs/migrations/0009_deferred_clock_facts.d.ts +24 -0
  329. package/dist/cjs/migrations/0009_deferred_clock_facts.d.ts.map +1 -0
  330. package/dist/cjs/migrations/0009_deferred_clock_facts.js +141 -0
  331. package/dist/cjs/migrations/0009_deferred_clock_facts.js.map +7 -0
  332. package/dist/cjs/migrations/0010_pending_cancellation.d.ts +15 -0
  333. package/dist/cjs/migrations/0010_pending_cancellation.d.ts.map +1 -0
  334. package/dist/cjs/migrations/0010_pending_cancellation.js +41 -0
  335. package/dist/cjs/migrations/0010_pending_cancellation.js.map +7 -0
  336. package/dist/cjs/package.json +1 -0
  337. package/dist/cjs/test/TestStores.d.ts +89 -0
  338. package/dist/cjs/test/TestStores.d.ts.map +1 -0
  339. package/dist/cjs/test/TestStores.js +98 -0
  340. package/dist/cjs/test/TestStores.js.map +7 -0
  341. package/dist/esm/ArtifactGc.d.ts +235 -0
  342. package/dist/esm/ArtifactGc.d.ts.map +1 -0
  343. package/dist/esm/ArtifactGc.js +268 -0
  344. package/dist/esm/ArtifactGc.js.map +1 -0
  345. package/dist/esm/ArtifactSync.d.ts +164 -0
  346. package/dist/esm/ArtifactSync.d.ts.map +1 -0
  347. package/dist/esm/ArtifactSync.js +176 -0
  348. package/dist/esm/ArtifactSync.js.map +1 -0
  349. package/dist/esm/CacheSync.d.ts +112 -0
  350. package/dist/esm/CacheSync.d.ts.map +1 -0
  351. package/dist/esm/CacheSync.js +94 -0
  352. package/dist/esm/CacheSync.js.map +1 -0
  353. package/dist/esm/DeferredClockFold.d.ts +354 -0
  354. package/dist/esm/DeferredClockFold.d.ts.map +1 -0
  355. package/dist/esm/DeferredClockFold.js +472 -0
  356. package/dist/esm/DeferredClockFold.js.map +1 -0
  357. package/dist/esm/DisasterRecovery.d.ts +431 -0
  358. package/dist/esm/DisasterRecovery.d.ts.map +1 -0
  359. package/dist/esm/DisasterRecovery.js +523 -0
  360. package/dist/esm/DisasterRecovery.js.map +1 -0
  361. package/dist/esm/DurableEngineState.d.ts +776 -0
  362. package/dist/esm/DurableEngineState.d.ts.map +1 -0
  363. package/dist/esm/DurableEngineState.js +1648 -0
  364. package/dist/esm/DurableEngineState.js.map +1 -0
  365. package/dist/esm/EngineStore.d.ts +158 -0
  366. package/dist/esm/EngineStore.d.ts.map +1 -0
  367. package/dist/esm/EngineStore.js +403 -0
  368. package/dist/esm/EngineStore.js.map +1 -0
  369. package/dist/esm/EngineStoreMetrics.d.ts +276 -0
  370. package/dist/esm/EngineStoreMetrics.d.ts.map +1 -0
  371. package/dist/esm/EngineStoreMetrics.js +260 -0
  372. package/dist/esm/EngineStoreMetrics.js.map +1 -0
  373. package/dist/esm/Errors.d.ts +22 -0
  374. package/dist/esm/Errors.d.ts.map +1 -0
  375. package/dist/esm/Errors.js +22 -0
  376. package/dist/esm/Errors.js.map +1 -0
  377. package/dist/esm/EventTypes.d.ts +27 -0
  378. package/dist/esm/EventTypes.d.ts.map +1 -0
  379. package/dist/esm/EventTypes.js +27 -0
  380. package/dist/esm/EventTypes.js.map +1 -0
  381. package/dist/esm/ExecutionFacts.d.ts +59 -0
  382. package/dist/esm/ExecutionFacts.d.ts.map +1 -0
  383. package/dist/esm/ExecutionFacts.js +96 -0
  384. package/dist/esm/ExecutionFacts.js.map +1 -0
  385. package/dist/esm/ExecutionSnapshot.d.ts +117 -0
  386. package/dist/esm/ExecutionSnapshot.d.ts.map +1 -0
  387. package/dist/esm/ExecutionSnapshot.js +95 -0
  388. package/dist/esm/ExecutionSnapshot.js.map +1 -0
  389. package/dist/esm/Inconsistency.d.ts +154 -0
  390. package/dist/esm/Inconsistency.d.ts.map +1 -0
  391. package/dist/esm/Inconsistency.js +133 -0
  392. package/dist/esm/Inconsistency.js.map +1 -0
  393. package/dist/esm/Migrations.d.ts +56 -0
  394. package/dist/esm/Migrations.d.ts.map +1 -0
  395. package/dist/esm/Migrations.js +91 -0
  396. package/dist/esm/Migrations.js.map +1 -0
  397. package/dist/esm/OwnerIdentity.d.ts +91 -0
  398. package/dist/esm/OwnerIdentity.d.ts.map +1 -0
  399. package/dist/esm/OwnerIdentity.js +99 -0
  400. package/dist/esm/OwnerIdentity.js.map +1 -0
  401. package/dist/esm/PlanInputStore.d.ts +110 -0
  402. package/dist/esm/PlanInputStore.d.ts.map +1 -0
  403. package/dist/esm/PlanInputStore.js +207 -0
  404. package/dist/esm/PlanInputStore.js.map +1 -0
  405. package/dist/esm/PlanMergeStore.d.ts +113 -0
  406. package/dist/esm/PlanMergeStore.d.ts.map +1 -0
  407. package/dist/esm/PlanMergeStore.js +244 -0
  408. package/dist/esm/PlanMergeStore.js.map +1 -0
  409. package/dist/esm/PlanScheduler.d.ts +363 -0
  410. package/dist/esm/PlanScheduler.d.ts.map +1 -0
  411. package/dist/esm/PlanScheduler.js +1321 -0
  412. package/dist/esm/PlanScheduler.js.map +1 -0
  413. package/dist/esm/Reconciliation.d.ts +175 -0
  414. package/dist/esm/Reconciliation.d.ts.map +1 -0
  415. package/dist/esm/Reconciliation.js +175 -0
  416. package/dist/esm/Reconciliation.js.map +1 -0
  417. package/dist/esm/ReplayOnly.d.ts +91 -0
  418. package/dist/esm/ReplayOnly.d.ts.map +1 -0
  419. package/dist/esm/ReplayOnly.js +59 -0
  420. package/dist/esm/ReplayOnly.js.map +1 -0
  421. package/dist/esm/Retention.d.ts +113 -0
  422. package/dist/esm/Retention.d.ts.map +1 -0
  423. package/dist/esm/Retention.js +139 -0
  424. package/dist/esm/Retention.js.map +1 -0
  425. package/dist/esm/RunCatalogRead.d.ts +17 -0
  426. package/dist/esm/RunCatalogRead.d.ts.map +1 -0
  427. package/dist/esm/RunCatalogRead.js +17 -0
  428. package/dist/esm/RunCatalogRead.js.map +1 -0
  429. package/dist/esm/RunChangeFeed.d.ts +75 -0
  430. package/dist/esm/RunChangeFeed.d.ts.map +1 -0
  431. package/dist/esm/RunChangeFeed.js +81 -0
  432. package/dist/esm/RunChangeFeed.js.map +1 -0
  433. package/dist/esm/RunState.d.ts +116 -0
  434. package/dist/esm/RunState.d.ts.map +1 -0
  435. package/dist/esm/RunState.js +109 -0
  436. package/dist/esm/RunState.js.map +1 -0
  437. package/dist/esm/Selection.d.ts +495 -0
  438. package/dist/esm/Selection.d.ts.map +1 -0
  439. package/dist/esm/Selection.js +482 -0
  440. package/dist/esm/Selection.js.map +1 -0
  441. package/dist/esm/SelectionStore.d.ts +141 -0
  442. package/dist/esm/SelectionStore.d.ts.map +1 -0
  443. package/dist/esm/SelectionStore.js +215 -0
  444. package/dist/esm/SelectionStore.js.map +1 -0
  445. package/dist/esm/StepBoundary.d.ts +501 -0
  446. package/dist/esm/StepBoundary.d.ts.map +1 -0
  447. package/dist/esm/StepBoundary.js +919 -0
  448. package/dist/esm/StepBoundary.js.map +1 -0
  449. package/dist/esm/StepCacheFold.d.ts +148 -0
  450. package/dist/esm/StepCacheFold.d.ts.map +1 -0
  451. package/dist/esm/StepCacheFold.js +201 -0
  452. package/dist/esm/StepCacheFold.js.map +1 -0
  453. package/dist/esm/StepSandbox.d.ts +78 -0
  454. package/dist/esm/StepSandbox.d.ts.map +1 -0
  455. package/dist/esm/StepSandbox.js +70 -0
  456. package/dist/esm/StepSandbox.js.map +1 -0
  457. package/dist/esm/WakeBus.d.ts +116 -0
  458. package/dist/esm/WakeBus.d.ts.map +1 -0
  459. package/dist/esm/WakeBus.js +121 -0
  460. package/dist/esm/WakeBus.js.map +1 -0
  461. package/dist/esm/WorkspaceSandbox.d.ts +619 -0
  462. package/dist/esm/WorkspaceSandbox.d.ts.map +1 -0
  463. package/dist/esm/WorkspaceSandbox.js +985 -0
  464. package/dist/esm/WorkspaceSandbox.js.map +1 -0
  465. package/dist/esm/index.d.ts +157 -0
  466. package/dist/esm/index.d.ts.map +1 -0
  467. package/dist/esm/index.js +157 -0
  468. package/dist/esm/index.js.map +1 -0
  469. package/dist/esm/internal/ActionPersistence.d.ts +276 -0
  470. package/dist/esm/internal/ActionPersistence.d.ts.map +1 -0
  471. package/dist/esm/internal/ActionPersistence.js +2306 -0
  472. package/dist/esm/internal/ActionPersistence.js.map +1 -0
  473. package/dist/esm/internal/ArtifactRoots.d.ts +38 -0
  474. package/dist/esm/internal/ArtifactRoots.d.ts.map +1 -0
  475. package/dist/esm/internal/ArtifactRoots.js +76 -0
  476. package/dist/esm/internal/ArtifactRoots.js.map +1 -0
  477. package/dist/esm/internal/AttemptAdmission.d.ts +53 -0
  478. package/dist/esm/internal/AttemptAdmission.d.ts.map +1 -0
  479. package/dist/esm/internal/AttemptAdmission.js +52 -0
  480. package/dist/esm/internal/AttemptAdmission.js.map +1 -0
  481. package/dist/esm/internal/AttemptLifecycle.d.ts +245 -0
  482. package/dist/esm/internal/AttemptLifecycle.d.ts.map +1 -0
  483. package/dist/esm/internal/AttemptLifecycle.js +104 -0
  484. package/dist/esm/internal/AttemptLifecycle.js.map +1 -0
  485. package/dist/esm/internal/AttemptProbe.d.ts +53 -0
  486. package/dist/esm/internal/AttemptProbe.d.ts.map +1 -0
  487. package/dist/esm/internal/AttemptProbe.js +83 -0
  488. package/dist/esm/internal/AttemptProbe.js.map +1 -0
  489. package/dist/esm/internal/CacheAdmission.d.ts +79 -0
  490. package/dist/esm/internal/CacheAdmission.d.ts.map +1 -0
  491. package/dist/esm/internal/CacheAdmission.js +72 -0
  492. package/dist/esm/internal/CacheAdmission.js.map +1 -0
  493. package/dist/esm/internal/CacheAgeHistory.d.ts +27 -0
  494. package/dist/esm/internal/CacheAgeHistory.d.ts.map +1 -0
  495. package/dist/esm/internal/CacheAgeHistory.js +49 -0
  496. package/dist/esm/internal/CacheAgeHistory.js.map +1 -0
  497. package/dist/esm/internal/CacheAgeVerdicts.d.ts +15 -0
  498. package/dist/esm/internal/CacheAgeVerdicts.d.ts.map +1 -0
  499. package/dist/esm/internal/CacheAgeVerdicts.js +54 -0
  500. package/dist/esm/internal/CacheAgeVerdicts.js.map +1 -0
  501. package/dist/esm/internal/CacheOutputPolicy.d.ts +24 -0
  502. package/dist/esm/internal/CacheOutputPolicy.d.ts.map +1 -0
  503. package/dist/esm/internal/CacheOutputPolicy.js +73 -0
  504. package/dist/esm/internal/CacheOutputPolicy.js.map +1 -0
  505. package/dist/esm/internal/CachePublication.d.ts +97 -0
  506. package/dist/esm/internal/CachePublication.d.ts.map +1 -0
  507. package/dist/esm/internal/CachePublication.js +116 -0
  508. package/dist/esm/internal/CachePublication.js.map +1 -0
  509. package/dist/esm/internal/CallFacts.d.ts +15 -0
  510. package/dist/esm/internal/CallFacts.d.ts.map +1 -0
  511. package/dist/esm/internal/CallFacts.js +83 -0
  512. package/dist/esm/internal/CallFacts.js.map +1 -0
  513. package/dist/esm/internal/CopiedRecord.d.ts +61 -0
  514. package/dist/esm/internal/CopiedRecord.d.ts.map +1 -0
  515. package/dist/esm/internal/CopiedRecord.js +165 -0
  516. package/dist/esm/internal/CopiedRecord.js.map +1 -0
  517. package/dist/esm/internal/DeferredPersistence.d.ts +108 -0
  518. package/dist/esm/internal/DeferredPersistence.d.ts.map +1 -0
  519. package/dist/esm/internal/DeferredPersistence.js +240 -0
  520. package/dist/esm/internal/DeferredPersistence.js.map +1 -0
  521. package/dist/esm/internal/EffectRecords.d.ts +92 -0
  522. package/dist/esm/internal/EffectRecords.d.ts.map +1 -0
  523. package/dist/esm/internal/EffectRecords.js +94 -0
  524. package/dist/esm/internal/EffectRecords.js.map +1 -0
  525. package/dist/esm/internal/EngineJj.d.ts +30 -0
  526. package/dist/esm/internal/EngineJj.d.ts.map +1 -0
  527. package/dist/esm/internal/EngineJj.js +29 -0
  528. package/dist/esm/internal/EngineJj.js.map +1 -0
  529. package/dist/esm/internal/EngineStateSchema.d.ts +68 -0
  530. package/dist/esm/internal/EngineStateSchema.d.ts.map +1 -0
  531. package/dist/esm/internal/EngineStateSchema.js +53 -0
  532. package/dist/esm/internal/EngineStateSchema.js.map +1 -0
  533. package/dist/esm/internal/ExecutionSnapshotRead.d.ts +162 -0
  534. package/dist/esm/internal/ExecutionSnapshotRead.d.ts.map +1 -0
  535. package/dist/esm/internal/ExecutionSnapshotRead.js +218 -0
  536. package/dist/esm/internal/ExecutionSnapshotRead.js.map +1 -0
  537. package/dist/esm/internal/ExecutionSnapshotRelations.d.ts +39 -0
  538. package/dist/esm/internal/ExecutionSnapshotRelations.d.ts.map +1 -0
  539. package/dist/esm/internal/ExecutionSnapshotRelations.js +81 -0
  540. package/dist/esm/internal/ExecutionSnapshotRelations.js.map +1 -0
  541. package/dist/esm/internal/ExitEncoding.d.ts +180 -0
  542. package/dist/esm/internal/ExitEncoding.d.ts.map +1 -0
  543. package/dist/esm/internal/ExitEncoding.js +361 -0
  544. package/dist/esm/internal/ExitEncoding.js.map +1 -0
  545. package/dist/esm/internal/FileBoundarySnapshot.d.ts +14 -0
  546. package/dist/esm/internal/FileBoundarySnapshot.d.ts.map +1 -0
  547. package/dist/esm/internal/FileBoundarySnapshot.js +29 -0
  548. package/dist/esm/internal/FileBoundarySnapshot.js.map +1 -0
  549. package/dist/esm/internal/FileEnumeration.d.ts +127 -0
  550. package/dist/esm/internal/FileEnumeration.d.ts.map +1 -0
  551. package/dist/esm/internal/FileEnumeration.js +236 -0
  552. package/dist/esm/internal/FileEnumeration.js.map +1 -0
  553. package/dist/esm/internal/HostReflection.d.ts +80 -0
  554. package/dist/esm/internal/HostReflection.d.ts.map +1 -0
  555. package/dist/esm/internal/HostReflection.js +98 -0
  556. package/dist/esm/internal/HostReflection.js.map +1 -0
  557. package/dist/esm/internal/JournalRecords.d.ts +325 -0
  558. package/dist/esm/internal/JournalRecords.d.ts.map +1 -0
  559. package/dist/esm/internal/JournalRecords.js +306 -0
  560. package/dist/esm/internal/JournalRecords.js.map +1 -0
  561. package/dist/esm/internal/NodeJournal.d.ts +157 -0
  562. package/dist/esm/internal/NodeJournal.d.ts.map +1 -0
  563. package/dist/esm/internal/NodeJournal.js +298 -0
  564. package/dist/esm/internal/NodeJournal.js.map +1 -0
  565. package/dist/esm/internal/Ordering.d.ts +14 -0
  566. package/dist/esm/internal/Ordering.d.ts.map +1 -0
  567. package/dist/esm/internal/Ordering.js +14 -0
  568. package/dist/esm/internal/Ordering.js.map +1 -0
  569. package/dist/esm/internal/PlanInputs.d.ts +14 -0
  570. package/dist/esm/internal/PlanInputs.d.ts.map +1 -0
  571. package/dist/esm/internal/PlanInputs.js +57 -0
  572. package/dist/esm/internal/PlanInputs.js.map +1 -0
  573. package/dist/esm/internal/PlanMerges.d.ts +178 -0
  574. package/dist/esm/internal/PlanMerges.d.ts.map +1 -0
  575. package/dist/esm/internal/PlanMerges.js +113 -0
  576. package/dist/esm/internal/PlanMerges.js.map +1 -0
  577. package/dist/esm/internal/ProvenanceSlot.d.ts +30 -0
  578. package/dist/esm/internal/ProvenanceSlot.d.ts.map +1 -0
  579. package/dist/esm/internal/ProvenanceSlot.js +39 -0
  580. package/dist/esm/internal/ProvenanceSlot.js.map +1 -0
  581. package/dist/esm/internal/ResultEnvelope.d.ts +88 -0
  582. package/dist/esm/internal/ResultEnvelope.d.ts.map +1 -0
  583. package/dist/esm/internal/ResultEnvelope.js +83 -0
  584. package/dist/esm/internal/ResultEnvelope.js.map +1 -0
  585. package/dist/esm/internal/RetentionOps.d.ts +414 -0
  586. package/dist/esm/internal/RetentionOps.d.ts.map +1 -0
  587. package/dist/esm/internal/RetentionOps.js +576 -0
  588. package/dist/esm/internal/RetentionOps.js.map +1 -0
  589. package/dist/esm/internal/RunCatalogOps.d.ts +118 -0
  590. package/dist/esm/internal/RunCatalogOps.d.ts.map +1 -0
  591. package/dist/esm/internal/RunCatalogOps.js +120 -0
  592. package/dist/esm/internal/RunCatalogOps.js.map +1 -0
  593. package/dist/esm/internal/RunCoordinator.d.ts +78 -0
  594. package/dist/esm/internal/RunCoordinator.d.ts.map +1 -0
  595. package/dist/esm/internal/RunCoordinator.js +115 -0
  596. package/dist/esm/internal/RunCoordinator.js.map +1 -0
  597. package/dist/esm/internal/RunDriver.d.ts +192 -0
  598. package/dist/esm/internal/RunDriver.d.ts.map +1 -0
  599. package/dist/esm/internal/RunDriver.js +2334 -0
  600. package/dist/esm/internal/RunDriver.js.map +1 -0
  601. package/dist/esm/internal/RunLifecycle.d.ts +22 -0
  602. package/dist/esm/internal/RunLifecycle.d.ts.map +1 -0
  603. package/dist/esm/internal/RunLifecycle.js +49 -0
  604. package/dist/esm/internal/RunLifecycle.js.map +1 -0
  605. package/dist/esm/internal/RunListing.d.ts +78 -0
  606. package/dist/esm/internal/RunListing.d.ts.map +1 -0
  607. package/dist/esm/internal/RunListing.js +146 -0
  608. package/dist/esm/internal/RunListing.js.map +1 -0
  609. package/dist/esm/internal/RunListingError.d.ts +35 -0
  610. package/dist/esm/internal/RunListingError.d.ts.map +1 -0
  611. package/dist/esm/internal/RunListingError.js +27 -0
  612. package/dist/esm/internal/RunListingError.js.map +1 -0
  613. package/dist/esm/internal/RuntimeGraph.d.ts +73 -0
  614. package/dist/esm/internal/RuntimeGraph.d.ts.map +1 -0
  615. package/dist/esm/internal/RuntimeGraph.js +182 -0
  616. package/dist/esm/internal/RuntimeGraph.js.map +1 -0
  617. package/dist/esm/internal/SandboxedExecution.d.ts +80 -0
  618. package/dist/esm/internal/SandboxedExecution.d.ts.map +1 -0
  619. package/dist/esm/internal/SandboxedExecution.js +107 -0
  620. package/dist/esm/internal/SandboxedExecution.js.map +1 -0
  621. package/dist/esm/internal/StateTransaction.d.ts +44 -0
  622. package/dist/esm/internal/StateTransaction.d.ts.map +1 -0
  623. package/dist/esm/internal/StateTransaction.js +54 -0
  624. package/dist/esm/internal/StateTransaction.js.map +1 -0
  625. package/dist/esm/internal/StepFacts.d.ts +14 -0
  626. package/dist/esm/internal/StepFacts.d.ts.map +1 -0
  627. package/dist/esm/internal/StepFacts.js +35 -0
  628. package/dist/esm/internal/StepFacts.js.map +1 -0
  629. package/dist/esm/internal/TypedEvents.d.ts +14 -0
  630. package/dist/esm/internal/TypedEvents.d.ts.map +1 -0
  631. package/dist/esm/internal/TypedEvents.js +14 -0
  632. package/dist/esm/internal/TypedEvents.js.map +1 -0
  633. package/dist/esm/migrations/0001_initial.d.ts +17 -0
  634. package/dist/esm/migrations/0001_initial.d.ts.map +1 -0
  635. package/dist/esm/migrations/0001_initial.js +41 -0
  636. package/dist/esm/migrations/0001_initial.js.map +1 -0
  637. package/dist/esm/migrations/0002_selection_store.d.ts +15 -0
  638. package/dist/esm/migrations/0002_selection_store.d.ts.map +1 -0
  639. package/dist/esm/migrations/0002_selection_store.js +34 -0
  640. package/dist/esm/migrations/0002_selection_store.js.map +1 -0
  641. package/dist/esm/migrations/0003_plan_inputs.d.ts +13 -0
  642. package/dist/esm/migrations/0003_plan_inputs.d.ts.map +1 -0
  643. package/dist/esm/migrations/0003_plan_inputs.js +70 -0
  644. package/dist/esm/migrations/0003_plan_inputs.js.map +1 -0
  645. package/dist/esm/migrations/0004_plan_environment.d.ts +14 -0
  646. package/dist/esm/migrations/0004_plan_environment.d.ts.map +1 -0
  647. package/dist/esm/migrations/0004_plan_environment.js +33 -0
  648. package/dist/esm/migrations/0004_plan_environment.js.map +1 -0
  649. package/dist/esm/migrations/0005_plan_merges.d.ts +14 -0
  650. package/dist/esm/migrations/0005_plan_merges.d.ts.map +1 -0
  651. package/dist/esm/migrations/0005_plan_merges.js +59 -0
  652. package/dist/esm/migrations/0005_plan_merges.js.map +1 -0
  653. package/dist/esm/migrations/0006_execution_listing.d.ts +15 -0
  654. package/dist/esm/migrations/0006_execution_listing.d.ts.map +1 -0
  655. package/dist/esm/migrations/0006_execution_listing.js +81 -0
  656. package/dist/esm/migrations/0006_execution_listing.js.map +1 -0
  657. package/dist/esm/migrations/0007_run_parent_sequence.d.ts +15 -0
  658. package/dist/esm/migrations/0007_run_parent_sequence.d.ts.map +1 -0
  659. package/dist/esm/migrations/0007_run_parent_sequence.js +18 -0
  660. package/dist/esm/migrations/0007_run_parent_sequence.js.map +1 -0
  661. package/dist/esm/migrations/0008_deferred_consumption.d.ts +16 -0
  662. package/dist/esm/migrations/0008_deferred_consumption.d.ts.map +1 -0
  663. package/dist/esm/migrations/0008_deferred_consumption.js +24 -0
  664. package/dist/esm/migrations/0008_deferred_consumption.js.map +1 -0
  665. package/dist/esm/migrations/0009_deferred_clock_facts.d.ts +24 -0
  666. package/dist/esm/migrations/0009_deferred_clock_facts.d.ts.map +1 -0
  667. package/dist/esm/migrations/0009_deferred_clock_facts.js +127 -0
  668. package/dist/esm/migrations/0009_deferred_clock_facts.js.map +1 -0
  669. package/dist/esm/migrations/0010_pending_cancellation.d.ts +15 -0
  670. package/dist/esm/migrations/0010_pending_cancellation.d.ts.map +1 -0
  671. package/dist/esm/migrations/0010_pending_cancellation.js +19 -0
  672. package/dist/esm/migrations/0010_pending_cancellation.js.map +1 -0
  673. package/dist/esm/test/TestStores.d.ts +89 -0
  674. package/dist/esm/test/TestStores.d.ts.map +1 -0
  675. package/dist/esm/test/TestStores.js +103 -0
  676. package/dist/esm/test/TestStores.js.map +1 -0
  677. package/docs/README.md +113 -0
  678. package/docs/api.md +1494 -0
  679. package/docs/concepts/attempts-and-replay.md +149 -0
  680. package/docs/concepts/cache-admission.md +265 -0
  681. package/docs/concepts/call-facts.md +86 -0
  682. package/docs/concepts/durable-waits.md +175 -0
  683. package/docs/concepts/execution-facts.md +90 -0
  684. package/docs/concepts/ownership-and-fencing.md +128 -0
  685. package/docs/concepts/step-boundaries.md +148 -0
  686. package/docs/concepts/workspace-transactions.md +199 -0
  687. package/docs/event-types.md +14 -0
  688. package/docs/guides/back-up-and-restore.md +164 -0
  689. package/docs/guides/collect-unreferenced-artifacts.md +128 -0
  690. package/docs/guides/compose-a-durable-engine.md +146 -0
  691. package/docs/guides/coordinate-two-processes.md +120 -0
  692. package/docs/guides/defer-work-with-selection.md +171 -0
  693. package/docs/guides/delete-old-run-history.md +154 -0
  694. package/docs/guides/drive-a-plan.md +314 -0
  695. package/docs/guides/observe-engine-metrics.md +98 -0
  696. package/docs/guides/observe-executions.md +187 -0
  697. package/docs/guides/reclaim-runs-from-a-dead-host.md +133 -0
  698. package/docs/guides/share-a-cache-across-machines.md +134 -0
  699. package/docs/guides/testing.md +123 -0
  700. package/docs/installation.md +102 -0
  701. package/docs/quickstart.md +215 -0
  702. package/docs/troubleshooting.md +347 -0
  703. package/package.json +438 -3
  704. package/src/ArtifactGc.ts +408 -0
  705. package/src/ArtifactSync.ts +278 -0
  706. package/src/CacheSync.ts +131 -0
  707. package/src/DeferredClockFold.ts +586 -0
  708. package/src/DisasterRecovery.ts +888 -0
  709. package/src/DurableEngineState.ts +2656 -0
  710. package/src/EngineStore.ts +656 -0
  711. package/src/EngineStoreMetrics.ts +331 -0
  712. package/src/Errors.ts +28 -0
  713. package/src/EventTypes.ts +27 -0
  714. package/src/ExecutionFacts.ts +125 -0
  715. package/src/ExecutionSnapshot.ts +186 -0
  716. package/src/Inconsistency.ts +253 -0
  717. package/src/Migrations.ts +95 -0
  718. package/src/OwnerIdentity.ts +125 -0
  719. package/src/PlanInputStore.ts +292 -0
  720. package/src/PlanMergeStore.ts +330 -0
  721. package/src/PlanScheduler.ts +1806 -0
  722. package/src/Reconciliation.ts +224 -0
  723. package/src/ReplayOnly.ts +95 -0
  724. package/src/Retention.ts +214 -0
  725. package/src/RunCatalogRead.ts +27 -0
  726. package/src/RunChangeFeed.ts +125 -0
  727. package/src/RunState.ts +137 -0
  728. package/src/Selection.ts +683 -0
  729. package/src/SelectionStore.ts +353 -0
  730. package/src/StepBoundary.ts +1165 -0
  731. package/src/StepCacheFold.ts +244 -0
  732. package/src/StepSandbox.ts +110 -0
  733. package/src/WakeBus.ts +167 -0
  734. package/src/WorkspaceSandbox.ts +1604 -0
  735. package/src/index.ts +185 -0
  736. package/src/internal/ActionPersistence.ts +2687 -0
  737. package/src/internal/ArtifactRoots.ts +92 -0
  738. package/src/internal/AttemptAdmission.ts +76 -0
  739. package/src/internal/AttemptLifecycle.ts +163 -0
  740. package/src/internal/AttemptProbe.ts +90 -0
  741. package/src/internal/CacheAdmission.ts +133 -0
  742. package/src/internal/CacheAgeHistory.ts +58 -0
  743. package/src/internal/CacheAgeVerdicts.ts +61 -0
  744. package/src/internal/CacheOutputPolicy.ts +82 -0
  745. package/src/internal/CachePublication.ts +153 -0
  746. package/src/internal/CallFacts.ts +87 -0
  747. package/src/internal/CopiedRecord.ts +201 -0
  748. package/src/internal/DeferredPersistence.ts +459 -0
  749. package/src/internal/EffectRecords.ts +136 -0
  750. package/src/internal/EngineJj.ts +30 -0
  751. package/src/internal/EngineStateSchema.ts +92 -0
  752. package/src/internal/ExecutionSnapshotRead.ts +300 -0
  753. package/src/internal/ExecutionSnapshotRelations.ts +121 -0
  754. package/src/internal/ExitEncoding.ts +453 -0
  755. package/src/internal/FileBoundarySnapshot.ts +39 -0
  756. package/src/internal/FileEnumeration.ts +334 -0
  757. package/src/internal/HostReflection.ts +128 -0
  758. package/src/internal/JournalRecords.ts +396 -0
  759. package/src/internal/NodeJournal.ts +340 -0
  760. package/src/internal/Ordering.ts +14 -0
  761. package/src/internal/PlanInputs.ts +62 -0
  762. package/src/internal/PlanMerges.ts +123 -0
  763. package/src/internal/ProvenanceSlot.ts +52 -0
  764. package/src/internal/ResultEnvelope.ts +118 -0
  765. package/src/internal/RetentionOps.ts +865 -0
  766. package/src/internal/RunCatalogOps.ts +174 -0
  767. package/src/internal/RunCoordinator.ts +215 -0
  768. package/src/internal/RunDriver.ts +3154 -0
  769. package/src/internal/RunLifecycle.ts +53 -0
  770. package/src/internal/RunListing.ts +210 -0
  771. package/src/internal/RunListingError.ts +37 -0
  772. package/src/internal/RuntimeGraph.ts +253 -0
  773. package/src/internal/SandboxedExecution.ts +165 -0
  774. package/src/internal/StateTransaction.ts +71 -0
  775. package/src/internal/StepFacts.ts +36 -0
  776. package/src/internal/TypedEvents.ts +29 -0
  777. package/src/migrations/0001_initial.ts +51 -0
  778. package/src/migrations/0002_selection_store.ts +38 -0
  779. package/src/migrations/0003_plan_inputs.ts +75 -0
  780. package/src/migrations/0004_plan_environment.ts +34 -0
  781. package/src/migrations/0005_plan_merges.ts +60 -0
  782. package/src/migrations/0006_execution_listing.ts +86 -0
  783. package/src/migrations/0007_run_parent_sequence.ts +19 -0
  784. package/src/migrations/0008_deferred_consumption.ts +27 -0
  785. package/src/migrations/0009_deferred_clock_facts.ts +163 -0
  786. package/src/migrations/0010_pending_cancellation.ts +20 -0
  787. package/src/test/TestStores.ts +145 -0
@@ -0,0 +1,1648 @@
1
+ /**
2
+ * Durable deferred-completion and clock-deadline state used by the flow
3
+ * engine adapter.
4
+ *
5
+ * A parked run keeps the `suspended` status the run store admits; there is
6
+ * no `waiting` status. The waiting taxonomy lives beside it on the run row
7
+ * in the `waiting_reason`, `waiting_wake_at_ms`, `waiting_token`, and
8
+ * `waiting_request` columns, written by `park` and cleared by `wake`. See
9
+ * `docs/concepts/durable-waits.md`.
10
+ *
11
+ * @since 0.1.0
12
+ */
13
+ import * as Dialect from "@smthrs/database/Dialect";
14
+ import { afterCommit, DatabaseError, DurableWriter } from "@smthrs/database/DurableWriter";
15
+ import { contentDigest } from "@smthrs/journal/JournalEvent";
16
+ import * as Cause from "effect/Cause";
17
+ import * as Context from "effect/Context";
18
+ import * as Effect from "effect/Effect";
19
+ import * as Exit from "effect/Exit";
20
+ import * as Layer from "effect/Layer";
21
+ import * as Option from "effect/Option";
22
+ import * as Result from "effect/Result";
23
+ import * as Schema from "effect/Schema";
24
+ import * as Semaphore from "effect/Semaphore";
25
+ import * as SqlClient from "effect/unstable/sql/SqlClient";
26
+ import * as EngineStateSchema from "./internal/EngineStateSchema.js";
27
+ import { compareText } from "./internal/Ordering.js";
28
+ const pendingCancellationLimit = (limit) => Number.isSafeInteger(limit) && limit >= 0
29
+ ? Effect.void
30
+ : Effect.die(new RangeError("Pending cancellation limit must be a non-negative safe integer"));
31
+ /** JSON text carrying an arbitrary decoded value. */
32
+ const UnknownFromJsonString = Schema.fromJsonString(Schema.Unknown);
33
+ /** @private */
34
+ const NonNegativeSafeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
35
+ /**
36
+ * The durable address of a deferred result.
37
+ *
38
+ * @since 0.1.0
39
+ * @category models
40
+ */
41
+ export const DeferredAddress = Schema.Struct({
42
+ flowName: Schema.NonEmptyString,
43
+ executionId: Schema.NonEmptyString,
44
+ deferredName: Schema.NonEmptyString
45
+ });
46
+ /**
47
+ * The first durable completion recorded for a deferred.
48
+ *
49
+ * Correlation data remains opaque at this boundary. A future external-event
50
+ * layer owns its schema and authorization policy.
51
+ *
52
+ * @since 0.1.0
53
+ * @category models
54
+ */
55
+ export const DeferredRow = Schema.Struct({
56
+ ...DeferredAddress.fields,
57
+ exit: Schema.Unknown,
58
+ metadata: Schema.optionalKey(Schema.Unknown),
59
+ completedAtMs: NonNegativeSafeInt
60
+ });
61
+ /**
62
+ * The durable address of a clock.
63
+ *
64
+ * @since 0.1.0
65
+ * @category models
66
+ */
67
+ export const ClockAddress = Schema.Struct({
68
+ flowName: Schema.NonEmptyString,
69
+ executionId: Schema.NonEmptyString,
70
+ clockName: Schema.NonEmptyString
71
+ });
72
+ /**
73
+ * A durable absolute clock deadline.
74
+ *
75
+ * @since 0.1.0
76
+ * @category models
77
+ */
78
+ export const ClockRow = Schema.Struct({
79
+ ...ClockAddress.fields,
80
+ deferredName: Schema.NonEmptyString,
81
+ dueAtMs: NonNegativeSafeInt,
82
+ completedAtMs: Schema.NullOr(NonNegativeSafeInt)
83
+ });
84
+ /**
85
+ * The core wait-reason vocabulary a supervisor understands for wake policy.
86
+ *
87
+ * - `approval` — parked until a human (or policy) approves; woken by token.
88
+ * - `event` — parked on an external event / deferred completion.
89
+ * - `timer` — parked until `wakeAt`; woken by the durable clock sweep.
90
+ * - `quota` — parked on provider quota; woken at `wakeAt` when known.
91
+ * - `released` — the owning process released the run without settling it
92
+ * (shutdown, heartbeat self-interrupt; issue #39). A released row has no
93
+ * held lease and no `wakeAt`: any supervisor/sweeper MUST scan for this
94
+ * reason explicitly and re-drive the run through the claim path, or
95
+ * released runs are stranded forever (issue #67).
96
+ * - `quarantine` — parked because a SUCCEEDED attempt row's recorded
97
+ * evidence measured corrupt under the strict verdict (issue #171). The
98
+ * row cannot be evicted/re-executed like a cache row (its side effects
99
+ * already ran), so the corrupt boundary evidence is quarantined off the
100
+ * row while its durable outcome stays intact. No sweeper auto-wakes this
101
+ * reason: the strict integrity verdict remains visible until an explicit
102
+ * resume, which completes from the recorded outcome without re-execution.
103
+ *
104
+ * Left open (`string & {}`) so a plugin can park on a reason the core
105
+ * taxonomy has not named yet — the store persists whatever it is given
106
+ * rather than rejecting unknown reasons.
107
+ *
108
+ * @since 0.1.0
109
+ * @category models
110
+ */
111
+ export const WaitingReason = Schema.NonEmptyString;
112
+ /**
113
+ * The payload recorded when a run parks.
114
+ *
115
+ * `reason` and `wakeAt` earn columns because a supervisor sweeper queries
116
+ * them (`WHERE waiting_reason = 'quota' AND waiting_wake_at_ms <= ?`);
117
+ * `token` is compare-and-swap/lookup material a wake handler matches
118
+ * against.
119
+ *
120
+ * @since 0.1.0
121
+ * @category models
122
+ */
123
+ export const Waiting = Schema.Struct({
124
+ reason: WaitingReason,
125
+ wakeAt: Schema.optional(NonNegativeSafeInt),
126
+ token: Schema.optional(Schema.NonEmptyString),
127
+ /**
128
+ * What the wait declared about itself: for a `HumanTask` park, the kind of
129
+ * answer it wants, the prompt, and the attempt budget.
130
+ *
131
+ * `reason` and `token` say that a person owes the run an answer and which
132
+ * wait point holds it. Neither says what was asked, and the question lives
133
+ * in an action payload of an execution that has released its owner, so a
134
+ * reader had nothing to render but the wait's own name. This is the question
135
+ * itself, as the JSON TEXT the declaring flow wrote, stored and cleared with
136
+ * the other waiting columns.
137
+ */
138
+ request: Schema.optional(Schema.String)
139
+ });
140
+ /**
141
+ * A decoded waiting row for a parked run.
142
+ *
143
+ * @since 0.1.0
144
+ * @category models
145
+ */
146
+ export const WaitingRow = Schema.Struct({
147
+ runId: Schema.NonEmptyString,
148
+ reason: WaitingReason,
149
+ wakeAt: Schema.NullOr(NonNegativeSafeInt),
150
+ token: Schema.NullOr(Schema.NonEmptyString),
151
+ /** The question {@link Waiting} declared, absent on a park that declared none. */
152
+ request: Schema.optionalKey(Schema.Json)
153
+ });
154
+ /**
155
+ * A durable parent edge in the run DAG.
156
+ *
157
+ * The run row's `state_json` carries only the first (creating) parent; a
158
+ * diamond gives a run a second parent the row cannot express. Cycle
159
+ * detection must see every edge from every owner process and across
160
+ * restarts (issues #40/#41), so edges are persisted here. `seq` is a
161
+ * store-global insertion order used only to list a run's parents oldest
162
+ * first (and to make the cycle walk deterministic); it no longer arbitrates
163
+ * anything, so duplicate values would be harmless (issues #54/#66).
164
+ *
165
+ * @since 0.1.0
166
+ * @category models
167
+ */
168
+ export const RunParentEdge = Schema.Struct({
169
+ childId: Schema.NonEmptyString,
170
+ parentId: Schema.NonEmptyString,
171
+ seq: NonNegativeSafeInt
172
+ });
173
+ /**
174
+ * The surviving attempt rows of one action key: the earliest surviving
175
+ * row's start time and the highest attempt number contiguous from it.
176
+ *
177
+ * @since 0.1.0
178
+ * @category models
179
+ */
180
+ export const AttemptSurvivors = Schema.Struct({
181
+ /**
182
+ * The lowest surviving attempt number. Anything above 1 means the prune
183
+ * job removed a leading run of attempts; the engine store applies the
184
+ * pruned-prefix tolerance to it so both survivor paths agree (issue #96).
185
+ */
186
+ earliestAttempt: NonNegativeSafeInt,
187
+ earliestStartedAtMs: NonNegativeSafeInt,
188
+ latest: NonNegativeSafeInt
189
+ });
190
+ /**
191
+ * Recording a parent edge would close a cycle in the run DAG.
192
+ *
193
+ * Raised from inside the same transaction that inserted the edge, which is
194
+ * rolled back: a rejected edge leaves no durable trace anywhere (issues
195
+ * #54/#55/#56). `path` lists execution ids from the child back to itself
196
+ * through its would-be ancestors, matching the engine's
197
+ * `FlowCycleDetected.path` shape.
198
+ *
199
+ * @since 0.1.0
200
+ * @category errors
201
+ */
202
+ export class RunParentCycleError extends Schema.TaggedError()("@smthrs/engine-store/RunParentCycleError", {
203
+ path: Schema.Array(Schema.String)
204
+ }) {
205
+ }
206
+ /**
207
+ * A durable engine-state invariant broke: a defect (a bug), never a typed
208
+ * failure.
209
+ *
210
+ * `value_not_serializable` and `value_not_decodable` name the JSON column
211
+ * (`field`) whose value could not be written or read back.
212
+ * `deferred_completion_missing` and `run_parent_edge_missing` mean a row a
213
+ * first-writer transaction just lost to was gone when read.
214
+ *
215
+ * @since 1.0.0
216
+ * @category errors
217
+ */
218
+ export class EngineStateFault extends Schema.TaggedError()("@smthrs/engine-store/EngineStateFault", {
219
+ reason: Schema.Literals([
220
+ "value_not_serializable",
221
+ "value_not_decodable",
222
+ "deferred_completion_missing",
223
+ "run_parent_edge_missing"
224
+ ]),
225
+ field: Schema.optional(Schema.String),
226
+ cause: Schema.optional(Schema.Defect())
227
+ }) {
228
+ get message() {
229
+ switch (this.reason) {
230
+ case "value_not_serializable":
231
+ return `${this.field} must be JSON-serializable`;
232
+ case "value_not_decodable":
233
+ return `could not decode ${this.field}`;
234
+ case "deferred_completion_missing":
235
+ return "deferred completion disappeared during first-writer transaction";
236
+ case "run_parent_edge_missing":
237
+ return "run parent edge disappeared during first-writer transaction";
238
+ }
239
+ }
240
+ }
241
+ /**
242
+ * Service tag for durable deferred completions and absolute clock deadlines.
243
+ *
244
+ * @since 0.1.0
245
+ * @category services
246
+ */
247
+ export class DurableEngineState extends Context.Service()("@smthrs/engine-store/DurableEngineState") {
248
+ }
249
+ /** @private */
250
+ const deferredKey = (address) => JSON.stringify([address.flowName, address.executionId, address.deferredName]);
251
+ /** @private */
252
+ const clockKey = (address) => JSON.stringify([address.flowName, address.executionId, address.clockName]);
253
+ /** @private */
254
+ const DeferredDatabaseRow = Schema.Struct({
255
+ ...DeferredAddress.fields,
256
+ exitJson: Schema.String,
257
+ metadataJson: Schema.NullOr(Schema.String),
258
+ completedAtMs: NonNegativeSafeInt
259
+ });
260
+ /** @private */
261
+ const ClockDatabaseRow = Schema.Struct({
262
+ ...ClockAddress.fields,
263
+ deferredName: Schema.NonEmptyString,
264
+ dueAtMs: NonNegativeSafeInt,
265
+ completedAtMs: Schema.NullOr(NonNegativeSafeInt)
266
+ });
267
+ /** @private */
268
+ const WaitingDatabaseRow = Schema.Struct({
269
+ runId: Schema.NonEmptyString,
270
+ waitingReason: WaitingReason,
271
+ waitingWakeAtMs: Schema.NullOr(NonNegativeSafeInt),
272
+ waitingToken: Schema.NullOr(Schema.NonEmptyString),
273
+ /** Absent rather than null on a database written before `0004_waiting_request`. */
274
+ waitingRequest: Schema.optional(Schema.NullOr(Schema.String))
275
+ });
276
+ /**
277
+ * The declared question of a waiting row, or absence.
278
+ *
279
+ * The column is the wait's own JSON, so text that does not parse is text the
280
+ * writer never wrote: it is reported as no declared question rather than
281
+ * failing the read of a park that is otherwise intact.
282
+ */
283
+ const decodeWaitingRequest = (value) => {
284
+ if (value === null || value === undefined)
285
+ return {};
286
+ try {
287
+ return { request: JSON.parse(value) };
288
+ }
289
+ catch {
290
+ return {};
291
+ }
292
+ };
293
+ const decodeWaitingRow = (input) => decodeWaitingRowResult(input).pipe(Effect.orDie);
294
+ /** {@link decodeWaitingRow} with its parse failure left in the error channel. */
295
+ const decodeWaitingRowResult = (input) => Schema.decodeUnknownEffect(WaitingDatabaseRow)(input).pipe(Effect.map((row) => ({
296
+ runId: row.runId,
297
+ reason: row.waitingReason,
298
+ wakeAt: row.waitingWakeAtMs,
299
+ token: row.waitingToken,
300
+ ...decodeWaitingRequest(row.waitingRequest)
301
+ })));
302
+ /** @private */
303
+ const RunParentDatabaseRow = Schema.Struct({
304
+ childId: Schema.NonEmptyString,
305
+ parentId: Schema.NonEmptyString,
306
+ seq: NonNegativeSafeInt
307
+ });
308
+ const decodeRunParentEdge = (input) => decodeRunParentEdgeResult(input).pipe(Effect.orDie);
309
+ /** {@link decodeRunParentEdge} with its parse failure left in the error channel. */
310
+ const decodeRunParentEdgeResult = (input) => Schema.decodeUnknownEffect(RunParentDatabaseRow)(input);
311
+ /**
312
+ * Walks the parent chain upward from `parentId` over the durable edges,
313
+ * looking for `childId`. Returns the cycle path the new `(childId,
314
+ * parentId)` edge would close — ids from the child back to itself, matching
315
+ * the engine's `FlowCycleDetected.path` shape — or `undefined` when the
316
+ * edge is safe. A repeated id (pre-existing corrupt cycle written outside
317
+ * this API) terminates that branch instead of looping forever.
318
+ */
319
+ const findCyclePath = (childId, parentId, parentsOf) => Effect.suspend(() => {
320
+ if (parentId === childId) {
321
+ return Effect.succeed([childId]);
322
+ }
323
+ const seen = new Set([parentId]);
324
+ const walk = (current, chain) => Effect.gen(function* () {
325
+ const parents = yield* parentsOf(current);
326
+ for (const parent of parents) {
327
+ if (parent === childId)
328
+ return [...chain, parent].reverse();
329
+ if (seen.has(parent))
330
+ continue;
331
+ seen.add(parent);
332
+ const found = yield* walk(parent, [...chain, parent]);
333
+ if (found !== undefined)
334
+ return found;
335
+ }
336
+ return undefined;
337
+ });
338
+ return walk(parentId, [parentId]);
339
+ });
340
+ /** @private */
341
+ const DeferredAddressDatabaseRow = DeferredAddress;
342
+ /** The digests of a stored completion row's encoded text. */
343
+ const deferredDigest = (row) => ({
344
+ exit: contentDigest(row.exitJson),
345
+ metadata: row.metadataJson === null ? null : contentDigest(row.metadataJson)
346
+ });
347
+ /** The digests of a memory completion row, over the text the SQL store would keep. */
348
+ const memoryDigest = (row) => Effect.gen(function* () {
349
+ const exitJson = yield* encodeJson(row.exit, "exit");
350
+ const metadataJson = row.metadata === undefined ? null : yield* encodeJson(row.metadata, "metadata");
351
+ return deferredDigest({ exitJson, metadataJson });
352
+ });
353
+ const encodeJson = (value, field) => Schema.encodeEffect(UnknownFromJsonString)(value).pipe(Effect.mapError((cause) => new EngineStateFault({ reason: "value_not_serializable", field, cause })), Effect.orDie);
354
+ const decodeJson = (value, field) => Schema.decodeUnknownEffect(UnknownFromJsonString)(value).pipe(Effect.mapError((cause) => new EngineStateFault({ reason: "value_not_decodable", field, cause })), Effect.orDie);
355
+ /**
356
+ * Rehydrates Effect's JSON representation after a storage round-trip.
357
+ *
358
+ * `Exit` and `Cause` deliberately serialize as plain JSON objects. Leaving a
359
+ * failure in that form is unsafe: the success branch happens to be rebuilt by
360
+ * `Exit.map`, while a plain failure is not an Exit and the deferred's schema
361
+ * rejects it after restart. Unknown non-Exit payloads remain untouched for
362
+ * the generic durable-state contract.
363
+ */
364
+ const restoreJsonExit = (value) => {
365
+ if (typeof value !== "object" || value === null)
366
+ return value;
367
+ const record = value;
368
+ if (record["_id"] !== "Exit")
369
+ return value;
370
+ if (record["_tag"] === "Success")
371
+ return Exit.succeed(record["value"]);
372
+ if (record["_tag"] !== "Failure")
373
+ return value;
374
+ const cause = record["cause"];
375
+ if (typeof cause !== "object" || cause === null)
376
+ return value;
377
+ const failures = cause["failures"];
378
+ if (!Array.isArray(failures))
379
+ return value;
380
+ const reasons = [];
381
+ for (const failure of failures) {
382
+ if (typeof failure !== "object" || failure === null)
383
+ return value;
384
+ const reason = failure;
385
+ switch (reason["_tag"]) {
386
+ case "Fail":
387
+ reasons.push(Cause.makeFailReason(reason["error"]));
388
+ break;
389
+ case "Die":
390
+ reasons.push(Cause.makeDieReason(reason["defect"]));
391
+ break;
392
+ case "Interrupt":
393
+ reasons.push(Cause.makeInterruptReason(typeof reason["fiberId"] === "number" ? reason["fiberId"] : undefined));
394
+ break;
395
+ default:
396
+ return value;
397
+ }
398
+ }
399
+ return Exit.failCause(Cause.fromReasons(reasons));
400
+ };
401
+ const decodeDeferredRow = (input) => Schema.decodeUnknownEffect(DeferredDatabaseRow)(input).pipe(Effect.orDie, Effect.flatMap((row) => Effect.all({
402
+ exit: decodeJson(row.exitJson, "exit_json").pipe(Effect.map(restoreJsonExit)),
403
+ metadata: row.metadataJson === null
404
+ ? Effect.succeed(undefined)
405
+ : decodeJson(row.metadataJson, "metadata_json")
406
+ }).pipe(Effect.map(({ exit, metadata }) => ({
407
+ flowName: row.flowName,
408
+ executionId: row.executionId,
409
+ deferredName: row.deferredName,
410
+ exit,
411
+ ...(metadata === undefined ? {} : { metadata }),
412
+ completedAtMs: row.completedAtMs
413
+ })))));
414
+ const decodeClockRow = (input) => decodeClockRowResult(input).pipe(Effect.orDie);
415
+ /** {@link decodeClockRow} with its parse failure left in the error channel. */
416
+ const decodeClockRowResult = (input) => Schema.decodeUnknownEffect(ClockDatabaseRow)(input).pipe(Effect.map((row) => ({
417
+ flowName: row.flowName,
418
+ executionId: row.executionId,
419
+ clockName: row.clockName,
420
+ deferredName: row.deferredName,
421
+ dueAtMs: row.dueAtMs,
422
+ completedAtMs: row.completedAtMs
423
+ })));
424
+ /** The primary key of a clock row, read defensively off a row that may not decode. */
425
+ const clockRowKey = (row) => JSON.stringify([row["flowName"], row["executionId"], row["clockName"]]);
426
+ /** The primary key of a deferred completion, read the same way. */
427
+ const deferredAddressRowKey = (row) => JSON.stringify([row["flowName"], row["executionId"], row["deferredName"]]);
428
+ /** The primary key of a run-parent edge, read the same way. */
429
+ const runParentRowKey = (row) => JSON.stringify([row["childId"], row["parentId"]]);
430
+ /**
431
+ * The deepest nesting {@link Service.waitingTree} walks.
432
+ *
433
+ * A run tree is authored, not generated: `agent/run` → `coding/request` →
434
+ * `coding/Request` → `coding/PrepareWithWiki` → `coding/PreparePlan` is five,
435
+ * and the deepest composition in this repository is well inside this. The cap
436
+ * exists so a tree whose edges were corrupted outside the engine costs a
437
+ * bounded read rather than the whole table.
438
+ *
439
+ * @since 1.0.0
440
+ * @category constants
441
+ */
442
+ export const waitingTreeMaxDepth = 64;
443
+ /** The primary key of a parked run's waiting payload, read the same way. */
444
+ const waitingRowKey = (row) => JSON.stringify([row["runId"]]);
445
+ /**
446
+ * Decodes the rows one durable-state sweep read, skipping — with a
447
+ * storage-integrity warning naming the row's key — any row that will not
448
+ * decode.
449
+ *
450
+ * Decoding the batch through `Effect.orDie` made one malformed row fatal for
451
+ * every row beside it: `completedDeferreds` and `pendingClocks` are what
452
+ * `register` sweeps, so a single unreadable row anywhere in a flow's history
453
+ * killed every registration of that flow, and no run of it ever resumed again.
454
+ * The blast radius of a corrupt row must be that row. The key is logged
455
+ * because it is what an operator needs to find and repair it, and it is read
456
+ * field by field off the raw row so a row that failed to decode can still name
457
+ * itself.
458
+ *
459
+ * Every enumeration goes through here for that reason, not just the two the
460
+ * outage named: `dueClocks`, `waitingRuns`, `runParents`, and `runChildren`
461
+ * each had their own version of it — no timer in the store fires, no parked
462
+ * run is ever swept, no cycle check can read a run's ancestry, no
463
+ * cancellation reaches a child.
464
+ *
465
+ * The point reads (`deferred`, `clock`, `waiting`) deliberately stay on
466
+ * `Effect.orDie`. They answer a question about ONE row, and their callers
467
+ * read "no row" as "this never happened": silently reporting that for a
468
+ * completion or deadline that is durably recorded but unreadable would
469
+ * re-run work whose side effects already ran. There the corrupt row IS the
470
+ * blast radius, so dying is the correct-sized failure.
471
+ */
472
+ const decodeSweep = (rows, kind, keyOf, decode) => Effect.gen(function* () {
473
+ const decoded = [];
474
+ for (const row of rows) {
475
+ const result = yield* Effect.result(decode(row));
476
+ if (Result.isSuccess(result)) {
477
+ decoded.push(result.success);
478
+ continue;
479
+ }
480
+ yield* Effect.logWarning(`engine-store: skipping a malformed ${kind} row ${keyOf(row)}`, result.failure);
481
+ }
482
+ return decoded;
483
+ });
484
+ /**
485
+ * Demotes a write boundary's storage failures to defects, reason by reason.
486
+ *
487
+ * `transaction` declares the BODY's error type, and the shared writer adds
488
+ * `DatabaseError` to it. A sole storage failure is already a defect; a
489
+ * composite one used to be cast back through the declared channel, which let
490
+ * a raw `DatabaseError` surface as a typed failure of a type that never
491
+ * admits one. Re-channelling keeps the error object, its annotations, the
492
+ * other reasons and the interruptions intact while making the declared type
493
+ * true. Every other reason is passed through UNCHANGED rather than rebuilt,
494
+ * so a body failure keeps its own identity and spans.
495
+ */
496
+ const dieOnDatabaseError = (cause) => Cause.fromReasons(cause.reasons.map((reason) => Cause.isFailReason(reason) && reason.error instanceof DatabaseError
497
+ ? Cause.makeDieReason(reason.error).annotate(Cause.reasonAnnotations(reason))
498
+ // Narrowing a generic union by `instanceof` is beyond the checker, but
499
+ // the guard above is the proof: what is left is a defect, an
500
+ // interruption, or a failure whose error is not a `DatabaseError`.
501
+ : reason));
502
+ /**
503
+ * Constructs the database-backed durable-state implementation.
504
+ *
505
+ * Clock creation is fenced against the current run owner. Deferred completion
506
+ * and clock firing are external trigger admissions protected by first-writer
507
+ * and compare-and-set semantics; execution remains claim-gated by `RunStore`.
508
+ *
509
+ * @since 0.1.0
510
+ * @category constructors
511
+ */
512
+ export const make = Effect.gen(function* () {
513
+ const sql = yield* Effect.service(SqlClient.SqlClient);
514
+ const writer = yield* DurableWriter;
515
+ // Engine-store-owned storage created outside the journal migration
516
+ // (issues #40/#41/#79/#81). The statements, their rationale, and
517
+ // the dialects each is known to accept live in one machine-readable
518
+ // inventory so the pg-porting plan cannot omit them (issue #92).
519
+ yield* EngineStateSchema.apply(sql, writer);
520
+ const selectDeferred = (address) => sql `
521
+ SELECT
522
+ flow_name AS "flowName",
523
+ execution_id AS "executionId",
524
+ deferred_name AS "deferredName",
525
+ exit_json AS "exitJson",
526
+ metadata_json AS "metadataJson",
527
+ completed_at_ms AS "completedAtMs"
528
+ FROM flows_deferred_completions
529
+ WHERE flow_name = ${address.flowName}
530
+ AND execution_id = ${address.executionId}
531
+ AND deferred_name = ${address.deferredName}
532
+ `;
533
+ const selectClock = (address) => sql `
534
+ SELECT
535
+ flow_name AS "flowName",
536
+ execution_id AS "executionId",
537
+ clock_name AS "clockName",
538
+ deferred_name AS "deferredName",
539
+ due_at_ms AS "dueAtMs",
540
+ completed_at_ms AS "completedAtMs"
541
+ FROM flows_clock_deadlines
542
+ WHERE flow_name = ${address.flowName}
543
+ AND execution_id = ${address.executionId}
544
+ AND clock_name = ${address.clockName}
545
+ `;
546
+ const deferred = Effect.fn("DurableEngineState.deferred")((address) => selectDeferred(address).pipe(Effect.orDie, Effect.flatMap((rows) => rows[0] === undefined
547
+ ? Effect.succeedNone
548
+ : Effect.map(decodeDeferredRow(rows[0]), Option.some))));
549
+ const consumeDeferred = Effect.fn("DurableEngineState.consumeDeferred")((address, consumedAtMs) => writer.write(sql `
550
+ UPDATE flows_deferred_completions
551
+ SET consumed_at_ms = ${consumedAtMs}
552
+ WHERE flow_name = ${address.flowName}
553
+ AND execution_id = ${address.executionId}
554
+ AND deferred_name = ${address.deferredName}
555
+ AND consumed_at_ms IS NULL
556
+ RETURNING flow_name AS "flowName"
557
+ `).pipe(Effect.orDie, Effect.map((rows) => rows.length > 0)));
558
+ const completeDeferred = Effect.fn("DurableEngineState.completeDeferred")((row) => Effect.gen(function* () {
559
+ const exitJson = yield* encodeJson(row.exit, "exit");
560
+ const metadataJson = row.metadata === undefined
561
+ ? null
562
+ : yield* encodeJson(row.metadata, "metadata");
563
+ return yield* writer.write(Effect.gen(function* () {
564
+ const inserted = yield* sql `
565
+ INSERT INTO flows_deferred_completions (
566
+ flow_name,
567
+ execution_id,
568
+ deferred_name,
569
+ exit_json,
570
+ metadata_json,
571
+ completed_at_ms
572
+ ) VALUES (
573
+ ${row.flowName},
574
+ ${row.executionId},
575
+ ${row.deferredName},
576
+ ${exitJson},
577
+ ${metadataJson},
578
+ ${row.completedAtMs}
579
+ )
580
+ ON CONFLICT (flow_name, execution_id, deferred_name) DO NOTHING
581
+ RETURNING
582
+ flow_name AS "flowName",
583
+ execution_id AS "executionId",
584
+ deferred_name AS "deferredName",
585
+ exit_json AS "exitJson",
586
+ metadata_json AS "metadataJson",
587
+ completed_at_ms AS "completedAtMs"
588
+ `;
589
+ if (inserted[0] !== undefined) {
590
+ return {
591
+ _tag: "Completed",
592
+ row: yield* decodeDeferredRow(inserted[0]),
593
+ digest: deferredDigest(inserted[0])
594
+ };
595
+ }
596
+ const existing = yield* selectDeferred(row);
597
+ if (existing[0] === undefined) {
598
+ return yield* Effect.die(new EngineStateFault({ reason: "deferred_completion_missing" }));
599
+ }
600
+ return {
601
+ _tag: "Existing",
602
+ row: yield* decodeDeferredRow(existing[0]),
603
+ digest: deferredDigest(existing[0])
604
+ };
605
+ })).pipe(Effect.orDie);
606
+ }));
607
+ const clock = Effect.fn("DurableEngineState.clock")((address) => selectClock(address).pipe(Effect.orDie, Effect.flatMap((rows) => rows[0] === undefined
608
+ ? Effect.succeedNone
609
+ : Effect.map(decodeClockRow(rows[0]), Option.some))));
610
+ const scheduleClock = Effect.fn("DurableEngineState.scheduleClock")((row, owner) => writer.write(Effect.gen(function* () {
611
+ const inserted = yield* sql `
612
+ INSERT INTO flows_clock_deadlines (
613
+ flow_name,
614
+ execution_id,
615
+ clock_name,
616
+ deferred_name,
617
+ due_at_ms,
618
+ completed_at_ms
619
+ )
620
+ SELECT
621
+ ${row.flowName},
622
+ ${row.executionId},
623
+ ${row.clockName},
624
+ ${row.deferredName},
625
+ ${row.dueAtMs},
626
+ ${row.completedAtMs}
627
+ WHERE EXISTS (
628
+ SELECT 1
629
+ FROM flows_runs
630
+ WHERE run_id = ${row.executionId}
631
+ AND status = 'running'
632
+ AND owner_host_id = ${owner.hostId}
633
+ AND owner_pid = ${owner.pid}
634
+ AND owner_nonce = ${owner.nonce}
635
+ )
636
+ ON CONFLICT (flow_name, execution_id, clock_name) DO NOTHING
637
+ RETURNING
638
+ flow_name AS "flowName",
639
+ execution_id AS "executionId",
640
+ clock_name AS "clockName",
641
+ deferred_name AS "deferredName",
642
+ due_at_ms AS "dueAtMs",
643
+ completed_at_ms AS "completedAtMs"
644
+ `;
645
+ if (inserted[0] !== undefined) {
646
+ return {
647
+ _tag: "Scheduled",
648
+ row: yield* decodeClockRow(inserted[0])
649
+ };
650
+ }
651
+ const existing = yield* selectClock(row);
652
+ if (existing[0] !== undefined) {
653
+ return {
654
+ _tag: "Existing",
655
+ row: yield* decodeClockRow(existing[0])
656
+ };
657
+ }
658
+ return yield* Effect.interrupt;
659
+ })).pipe(Effect.orDie));
660
+ const completeClock = Effect.fn("DurableEngineState.completeClock")((address, completedAtMs) => writer.write(Effect.gen(function* () {
661
+ const updated = yield* sql `
662
+ UPDATE flows_clock_deadlines
663
+ SET completed_at_ms = ${completedAtMs}
664
+ WHERE flow_name = ${address.flowName}
665
+ AND execution_id = ${address.executionId}
666
+ AND clock_name = ${address.clockName}
667
+ AND completed_at_ms IS NULL
668
+ RETURNING
669
+ flow_name AS "flowName",
670
+ execution_id AS "executionId",
671
+ clock_name AS "clockName",
672
+ deferred_name AS "deferredName",
673
+ due_at_ms AS "dueAtMs",
674
+ completed_at_ms AS "completedAtMs"
675
+ `;
676
+ if (updated[0] !== undefined) {
677
+ return {
678
+ _tag: "Completed",
679
+ row: yield* decodeClockRow(updated[0])
680
+ };
681
+ }
682
+ const existing = yield* selectClock(address);
683
+ return existing[0] === undefined
684
+ ? { _tag: "NotFound" }
685
+ : {
686
+ _tag: "AlreadyCompleted",
687
+ row: yield* decodeClockRow(existing[0])
688
+ };
689
+ })).pipe(Effect.orDie));
690
+ const dueClocks = Effect.fn("DurableEngineState.dueClocks")((nowMs) => sql `
691
+ SELECT
692
+ flow_name AS "flowName",
693
+ execution_id AS "executionId",
694
+ clock_name AS "clockName",
695
+ deferred_name AS "deferredName",
696
+ due_at_ms AS "dueAtMs",
697
+ completed_at_ms AS "completedAtMs"
698
+ FROM flows_clock_deadlines
699
+ WHERE completed_at_ms IS NULL
700
+ AND due_at_ms <= ${nowMs}
701
+ ORDER BY due_at_ms, execution_id, clock_name
702
+ `.pipe(Effect.orDie,
703
+ // This is the whole store's due-timer sweep: dying on one unreadable
704
+ // deadline stopped every timer in every flow from firing.
705
+ Effect.flatMap((rows) => decodeSweep(rows, "clock deadline", clockRowKey, decodeClockRowResult))));
706
+ const pendingClocks = Effect.fn("DurableEngineState.pendingClocks")((scope) => (scope.executionId !== undefined
707
+ ? sql `
708
+ SELECT
709
+ flow_name AS "flowName",
710
+ execution_id AS "executionId",
711
+ clock_name AS "clockName",
712
+ deferred_name AS "deferredName",
713
+ due_at_ms AS "dueAtMs",
714
+ completed_at_ms AS "completedAtMs"
715
+ FROM flows_clock_deadlines
716
+ WHERE completed_at_ms IS NULL
717
+ AND execution_id = ${scope.executionId}
718
+ AND ${scope.flowName === undefined ? sql `1 = 1` : sql `flow_name = ${scope.flowName}`}
719
+ AND EXISTS (
720
+ SELECT 1 FROM flows_runs
721
+ WHERE flows_runs.run_id = flows_clock_deadlines.execution_id
722
+ AND flows_runs.status NOT IN ('completed', 'failed', 'cancelled')
723
+ )
724
+ ORDER BY due_at_ms, execution_id, clock_name
725
+ `
726
+ : scope.flowName !== undefined
727
+ ? sql `
728
+ SELECT
729
+ flow_name AS "flowName",
730
+ execution_id AS "executionId",
731
+ clock_name AS "clockName",
732
+ deferred_name AS "deferredName",
733
+ due_at_ms AS "dueAtMs",
734
+ completed_at_ms AS "completedAtMs"
735
+ FROM flows_clock_deadlines
736
+ WHERE completed_at_ms IS NULL
737
+ AND flow_name = ${scope.flowName}
738
+ AND EXISTS (
739
+ SELECT 1 FROM flows_runs
740
+ WHERE flows_runs.run_id = flows_clock_deadlines.execution_id
741
+ AND flows_runs.status NOT IN ('completed', 'failed', 'cancelled')
742
+ )
743
+ ORDER BY due_at_ms, execution_id, clock_name
744
+ `
745
+ : sql `
746
+ SELECT
747
+ flow_name AS "flowName",
748
+ execution_id AS "executionId",
749
+ clock_name AS "clockName",
750
+ deferred_name AS "deferredName",
751
+ due_at_ms AS "dueAtMs",
752
+ completed_at_ms AS "completedAtMs"
753
+ FROM flows_clock_deadlines
754
+ WHERE completed_at_ms IS NULL
755
+ AND EXISTS (
756
+ SELECT 1 FROM flows_runs
757
+ WHERE flows_runs.run_id = flows_clock_deadlines.execution_id
758
+ AND flows_runs.status NOT IN ('completed', 'failed', 'cancelled')
759
+ )
760
+ ORDER BY due_at_ms, execution_id, clock_name
761
+ `).pipe(Effect.orDie,
762
+ // A row that will not decode is a storage-integrity event about that
763
+ // row. Dying here made one of them fatal for the whole sweep, and so
764
+ // for `register` itself (issue B-08).
765
+ Effect.flatMap((rows) => decodeSweep(rows, "clock deadline", clockRowKey, decodeClockRowResult))));
766
+ const completedDeferreds = Effect.fn("DurableEngineState.completedDeferreds")((flowName) => sql `
767
+ SELECT
768
+ flow_name AS "flowName",
769
+ execution_id AS "executionId",
770
+ deferred_name AS "deferredName"
771
+ FROM flows_deferred_completions
772
+ WHERE flow_name = ${flowName}
773
+ AND consumed_at_ms IS NULL
774
+ AND EXISTS (
775
+ SELECT 1 FROM flows_runs
776
+ WHERE flows_runs.run_id = flows_deferred_completions.execution_id
777
+ AND flows_runs.status NOT IN ('completed', 'failed', 'cancelled')
778
+ )
779
+ ORDER BY execution_id, deferred_name
780
+ `.pipe(Effect.orDie, Effect.flatMap((rows) => decodeSweep(rows, "deferred completion", deferredAddressRowKey, (row) => Schema.decodeUnknownEffect(DeferredAddressDatabaseRow)(row)))));
781
+ const completeRunClocks = Effect.fn("DurableEngineState.completeRunClocks")((executionId, completedAtMs) => writer.write(sql `
782
+ UPDATE flows_clock_deadlines
783
+ SET completed_at_ms = ${completedAtMs}
784
+ WHERE execution_id = ${executionId}
785
+ AND completed_at_ms IS NULL
786
+ RETURNING
787
+ flow_name AS "flowName",
788
+ execution_id AS "executionId",
789
+ clock_name AS "clockName",
790
+ deferred_name AS "deferredName",
791
+ due_at_ms AS "dueAtMs",
792
+ completed_at_ms AS "completedAtMs"
793
+ `).pipe(Effect.orDie, Effect.flatMap((rows) => Effect.forEach(rows, decodeClockRow)), Effect.map((rows) => [...rows].sort((left, right) => compareText(left.flowName, right.flowName) || compareText(left.clockName, right.clockName)))));
794
+ const selectWaiting = (runId) => sql `
795
+ SELECT
796
+ run_id AS "runId",
797
+ waiting_reason AS "waitingReason",
798
+ waiting_wake_at_ms AS "waitingWakeAtMs",
799
+ waiting_token AS "waitingToken",
800
+ waiting_request AS "waitingRequest"
801
+ FROM flows_runs
802
+ WHERE run_id = ${runId}
803
+ AND waiting_reason IS NOT NULL
804
+ `;
805
+ const park = Effect.fn("DurableEngineState.park")((runId, waiting, owner) => writer.write(Effect.gen(function* () {
806
+ const updated = yield* sql `
807
+ UPDATE flows_runs
808
+ SET
809
+ waiting_reason = ${waiting.reason},
810
+ waiting_wake_at_ms = ${waiting.wakeAt ?? null},
811
+ waiting_token = ${waiting.token ?? null},
812
+ waiting_request = ${waiting.request ?? null}
813
+ WHERE run_id = ${runId}
814
+ AND owner_host_id = ${owner.hostId}
815
+ AND owner_pid = ${owner.pid}
816
+ AND owner_nonce = ${owner.nonce}
817
+ RETURNING
818
+ run_id AS "runId",
819
+ waiting_reason AS "waitingReason",
820
+ waiting_wake_at_ms AS "waitingWakeAtMs",
821
+ waiting_token AS "waitingToken",
822
+ waiting_request AS "waitingRequest"
823
+ `;
824
+ if (updated[0] === undefined) {
825
+ return { _tag: "NotFound" };
826
+ }
827
+ return { _tag: "Parked", row: yield* decodeWaitingRow(updated[0]) };
828
+ })).pipe(Effect.orDie));
829
+ const wake = Effect.fn("DurableEngineState.wake")((runId) => writer.write(Effect.gen(function* () {
830
+ const before = yield* selectWaiting(runId);
831
+ if (before[0] === undefined) {
832
+ const existing = yield* sql `
833
+ SELECT run_id AS "runId" FROM flows_runs WHERE run_id = ${runId}
834
+ `;
835
+ return existing[0] === undefined ? { _tag: "NotFound" } : { _tag: "NotWaiting" };
836
+ }
837
+ const row = yield* decodeWaitingRow(before[0]);
838
+ yield* sql `
839
+ UPDATE flows_runs
840
+ SET
841
+ waiting_reason = NULL,
842
+ waiting_wake_at_ms = NULL,
843
+ waiting_token = NULL,
844
+ waiting_request = NULL
845
+ WHERE run_id = ${runId}
846
+ AND waiting_reason IS NOT NULL
847
+ `;
848
+ return { _tag: "Woken", row };
849
+ })).pipe(Effect.orDie));
850
+ const waiting = Effect.fn("DurableEngineState.waiting")((runId) => selectWaiting(runId).pipe(Effect.orDie, Effect.flatMap((rows) => rows[0] === undefined
851
+ ? Effect.succeedNone
852
+ : Effect.map(decodeWaitingRow(rows[0]), Option.some))));
853
+ /**
854
+ * Every open wait in one run tree, the named run's own first.
855
+ *
856
+ * Walk the authoritative spawn and trampoline edges. UNION visits each
857
+ * (run, depth) pair once; the depth cap bounds even externally corrupted
858
+ * cycles. Grouping by run afterwards collapses unequal-depth DAG paths
859
+ * and orders each wait at its shortest attached distance from the root.
860
+ * Correlated edge lookups seek each parent's indexes instead of building
861
+ * an edge set from the database's entire execution history.
862
+ */
863
+ const waitingTree = Effect.fn("DurableEngineState.waitingTree")((runId, options) => sql `
864
+ WITH RECURSIVE tree(run_id, depth) AS (
865
+ SELECT run_id, 0 FROM flows_runs WHERE run_id = ${runId}
866
+ UNION
867
+ SELECT child.run_id, tree.depth + 1
868
+ FROM tree
869
+ JOIN flows_runs child ON child.run_id IN (
870
+ SELECT child_id FROM flows_run_parents WHERE parent_id = tree.run_id
871
+ UNION ALL
872
+ SELECT run_id FROM flows_runs WHERE parent_run_id = tree.run_id
873
+ )
874
+ WHERE tree.depth < ${waitingTreeMaxDepth}
875
+ AND (${options?.detached === "include" ? 1 : 0} = 1
876
+ OR child.parent_run_id = tree.run_id
877
+ OR COALESCE(${Dialect.jsonText(sql, sql `child.state_json`, "$.onParentExit")}, 'cancel') <> 'detach')
878
+ ), reachable(run_id, depth) AS (
879
+ SELECT run_id, MIN(depth) FROM tree GROUP BY run_id
880
+ )
881
+ SELECT
882
+ parked.run_id AS "runId",
883
+ parked.waiting_reason AS "waitingReason",
884
+ parked.waiting_wake_at_ms AS "waitingWakeAtMs",
885
+ parked.waiting_token AS "waitingToken",
886
+ parked.waiting_request AS "waitingRequest"
887
+ FROM reachable
888
+ JOIN flows_runs parked ON parked.run_id = reachable.run_id
889
+ WHERE parked.waiting_reason IS NOT NULL
890
+ AND parked.status NOT IN ('completed', 'failed', 'cancelled')
891
+ ORDER BY reachable.depth, parked.created_at_ms, parked.run_id
892
+ `.pipe(Effect.orDie, Effect.flatMap((rows) => decodeSweep(rows, "waiting run", waitingRowKey, decodeWaitingRowResult))));
893
+ const waitingRuns = Effect.fn("DurableEngineState.waitingRuns")((filter) => {
894
+ // `1 = 0` short-circuits the cancel predicate away when the caller did
895
+ // not ask for it, so the reason/wake filters (and the 0004 index) stay
896
+ // the leading predicates (issue #68).
897
+ const cancelRequestedOnly = filter?.cancelRequested === true ? 1 : 0;
898
+ return (filter?.reason !== undefined && filter.dueBeforeMs !== undefined
899
+ ? sql `
900
+ SELECT
901
+ run_id AS "runId",
902
+ waiting_reason AS "waitingReason",
903
+ waiting_wake_at_ms AS "waitingWakeAtMs",
904
+ waiting_token AS "waitingToken",
905
+ waiting_request AS "waitingRequest"
906
+ FROM flows_runs
907
+ WHERE waiting_reason = ${filter.reason}
908
+ AND waiting_wake_at_ms IS NOT NULL
909
+ AND waiting_wake_at_ms <= ${filter.dueBeforeMs}
910
+ AND (${cancelRequestedOnly} = 0 OR cancel_requested_at_ms IS NOT NULL)
911
+ AND status NOT IN ('completed', 'failed', 'cancelled')
912
+ ORDER BY waiting_wake_at_ms, run_id
913
+ `
914
+ : filter?.reason !== undefined
915
+ ? sql `
916
+ SELECT
917
+ run_id AS "runId",
918
+ waiting_reason AS "waitingReason",
919
+ waiting_wake_at_ms AS "waitingWakeAtMs",
920
+ waiting_token AS "waitingToken",
921
+ waiting_request AS "waitingRequest"
922
+ FROM flows_runs
923
+ WHERE waiting_reason = ${filter.reason}
924
+ AND (${cancelRequestedOnly} = 0 OR cancel_requested_at_ms IS NOT NULL)
925
+ AND status NOT IN ('completed', 'failed', 'cancelled')
926
+ ORDER BY waiting_wake_at_ms IS NULL, waiting_wake_at_ms, run_id
927
+ `
928
+ : filter?.dueBeforeMs !== undefined
929
+ ? sql `
930
+ SELECT
931
+ run_id AS "runId",
932
+ waiting_reason AS "waitingReason",
933
+ waiting_wake_at_ms AS "waitingWakeAtMs",
934
+ waiting_token AS "waitingToken",
935
+ waiting_request AS "waitingRequest"
936
+ FROM flows_runs
937
+ WHERE waiting_reason IS NOT NULL
938
+ AND waiting_wake_at_ms IS NOT NULL
939
+ AND waiting_wake_at_ms <= ${filter.dueBeforeMs}
940
+ AND (${cancelRequestedOnly} = 0 OR cancel_requested_at_ms IS NOT NULL)
941
+ AND status NOT IN ('completed', 'failed', 'cancelled')
942
+ ORDER BY waiting_wake_at_ms, run_id
943
+ `
944
+ : sql `
945
+ SELECT
946
+ run_id AS "runId",
947
+ waiting_reason AS "waitingReason",
948
+ waiting_wake_at_ms AS "waitingWakeAtMs",
949
+ waiting_token AS "waitingToken",
950
+ waiting_request AS "waitingRequest"
951
+ FROM flows_runs
952
+ WHERE waiting_reason IS NOT NULL
953
+ AND (${cancelRequestedOnly} = 0 OR cancel_requested_at_ms IS NOT NULL)
954
+ AND status NOT IN ('completed', 'failed', 'cancelled')
955
+ ORDER BY waiting_wake_at_ms IS NULL, waiting_wake_at_ms, run_id
956
+ `).pipe(Effect.orDie,
957
+ // The parked-run sweeper's only enumeration: one unreadable waiting
958
+ // payload stranded every parked run, including the ones whose
959
+ // cancellation had already been requested.
960
+ Effect.flatMap((rows) => decodeSweep(rows, "waiting run", waitingRowKey, decodeWaitingRowResult)));
961
+ });
962
+ const pendingRows = (flowName, limit, after, through, descending = false, eligibleBeforeMs) => sql `
963
+ SELECT run_id AS "runId", created_at_ms AS "createdAtMs" FROM flows_runs
964
+ ${Dialect.isPostgres(sql) ? sql `` : sql `INDEXED BY flows_runs_listing_3`}
965
+ WHERE status = 'pending'
966
+ AND ${eligibleBeforeMs === undefined ? sql `TRUE` : sql `created_at_ms < ${eligibleBeforeMs}`}
967
+ AND execution_flow = ${flowName}
968
+ AND ${after === undefined ? sql `TRUE` : sql `(
969
+ created_at_ms > ${after.createdAtMs}
970
+ OR (created_at_ms = ${after.createdAtMs} AND run_id > ${after.runId})
971
+ )`}
972
+ AND ${through === undefined ? sql `TRUE` : sql `(
973
+ created_at_ms < ${through.createdAtMs}
974
+ OR (created_at_ms = ${through.createdAtMs} AND run_id <= ${through.runId})
975
+ )`}
976
+ ORDER BY ${descending ? sql `created_at_ms DESC, run_id DESC` : sql `created_at_ms, run_id`}
977
+ LIMIT ${limit ?? (Dialect.isPostgres(sql) ? null : -1)}
978
+ `.pipe(Effect.orDie, Effect.map((rows) => rows.map((row) => ({ runId: row.runId, createdAtMs: Number(row.createdAtMs) }))));
979
+ const pendingRuns = Effect.fn("DurableEngineState.pendingRuns")((flowName, limit, after, through, eligibleBeforeMs) => pendingRows(flowName, limit, after, through, false, eligibleBeforeMs));
980
+ const pendingRunTail = Effect.fn("DurableEngineState.pendingRunTail")((flowName, eligibleBeforeMs) => pendingRows(flowName, 1, undefined, undefined, true, eligibleBeforeMs).pipe(Effect.map((rows) => Option.fromNullishOr(rows[0]))));
981
+ const pendingCancellationRows = (limit, after, through, descending = false) => pendingCancellationLimit(limit).pipe(Effect.andThen(sql `
982
+ SELECT run_id AS "runId", created_at_ms AS "createdAtMs" FROM flows_runs
983
+ ${Dialect.isPostgres(sql) ? sql `` : sql `INDEXED BY flows_runs_pending_cancel_idx`}
984
+ WHERE status = 'pending' AND cancel_requested_at_ms IS NOT NULL
985
+ AND ${after === undefined ? sql `TRUE` : sql `(created_at_ms, run_id) > (${after.createdAtMs}, ${after.runId})`}
986
+ AND ${through === undefined ? sql `TRUE` : sql `(created_at_ms, run_id) <= (${through.createdAtMs}, ${through.runId})`}
987
+ ORDER BY ${descending ? sql `created_at_ms DESC, run_id DESC` : sql `created_at_ms, run_id`}
988
+ LIMIT ${limit}
989
+ `.pipe(Effect.orDie, Effect.map((rows) => rows.map((row) => ({ runId: row.runId, createdAtMs: Number(row.createdAtMs) }))))));
990
+ const pendingCancellationRuns = Effect.fn("DurableEngineState.pendingCancellationRuns")((limit, after, through) => pendingCancellationRows(limit, after, through));
991
+ const pendingCancellationTail = Effect.fn("DurableEngineState.pendingCancellationTail")(() => pendingCancellationRows(1, undefined, undefined, true).pipe(Effect.map((rows) => Option.fromNullishOr(rows[0]))));
992
+ const staleRunningRuns = Effect.fn("DurableEngineState.staleRunningRuns")((staleBeforeMs, limit) =>
993
+ // `LIMIT -1` is SQLite's explicit "no limit"; the partial index created
994
+ // in `make` serves the predicate, so the per-tick sweep is an index
995
+ // range read instead of a full table scan (issue #79).
996
+ sql `
997
+ SELECT run_id AS "runId", heartbeat_at_ms AS "heartbeatAtMs"
998
+ FROM flows_runs
999
+ WHERE status = 'running'
1000
+ AND heartbeat_at_ms IS NOT NULL
1001
+ AND heartbeat_at_ms < ${staleBeforeMs}
1002
+ ORDER BY heartbeat_at_ms, run_id
1003
+ LIMIT ${limit ?? (Dialect.isPostgres(sql) ? null : -1)}
1004
+ `.pipe(Effect.orDie, Effect.map((rows) => rows.map((row) => ({ runId: String(row.runId), heartbeatAtMs: Number(row.heartbeatAtMs) })))));
1005
+ /**
1006
+ * One ordered range read replaces the engine store's per-attempt point
1007
+ * probes (issue #77): a fresh key costs one empty SELECT instead of 32
1008
+ * sequential gets, and a resumed key one SELECT instead of one per
1009
+ * surviving attempt. The earliest surviving row is the durable retry
1010
+ * origin (issue #69) and the highest attempt contiguous from it the
1011
+ * resumed counter (issue #59). This read is deliberately unbounded; the
1012
+ * pruned-prefix tolerance that makes it agree with the point-probe
1013
+ * fallback is applied once, by the caller, in
1014
+ * `internal/AttemptProbe.probeAttempts` (issue #96).
1015
+ */
1016
+ const attemptSurvivors = Effect.fn("DurableEngineState.attemptSurvivors")((runId, stepKeyDigest) => sql `
1017
+ SELECT attempt AS "attempt", started_at_ms AS "startedAtMs"
1018
+ FROM flows_attempts
1019
+ WHERE run_id = ${runId}
1020
+ AND step_key_digest = ${stepKeyDigest}
1021
+ ORDER BY attempt
1022
+ `.pipe(Effect.orDie, Effect.map((rows) => {
1023
+ const first = rows[0];
1024
+ if (first === undefined)
1025
+ return Option.none();
1026
+ let latest = Number(first.attempt);
1027
+ for (let index = 1; index < rows.length; index++) {
1028
+ const next = Number(rows[index].attempt);
1029
+ if (next !== latest + 1)
1030
+ break;
1031
+ latest = next;
1032
+ }
1033
+ return Option.some({
1034
+ earliestAttempt: Number(first.attempt),
1035
+ earliestStartedAtMs: Number(first.startedAtMs),
1036
+ latest
1037
+ });
1038
+ })));
1039
+ const selectRunParent = (childId, parentId) => sql `
1040
+ SELECT
1041
+ child_id AS "childId",
1042
+ parent_id AS "parentId",
1043
+ seq AS "seq"
1044
+ FROM flows_run_parents
1045
+ WHERE child_id = ${childId}
1046
+ AND parent_id = ${parentId}
1047
+ `;
1048
+ const parentIdsOf = (id) => sql `
1049
+ SELECT
1050
+ child_id AS "childId",
1051
+ parent_id AS "parentId",
1052
+ seq AS "seq"
1053
+ FROM flows_run_parents
1054
+ WHERE child_id = ${id}
1055
+ ORDER BY seq
1056
+ `.pipe(Effect.orDie, Effect.map((rows) => rows.map((row) => String(row.parentId))));
1057
+ const recordRunParent = Effect.fn("DurableEngineState.recordRunParent")((childId, parentId) => writer.write(Effect.gen(function* () {
1058
+ // MAX(seq)+1 and the insert share one write transaction, so the
1059
+ // assigned seq is a total insertion order over the store.
1060
+ const inserted = yield* sql `
1061
+ INSERT INTO flows_run_parents (child_id, parent_id, seq)
1062
+ SELECT ${childId}, ${parentId}, COALESCE(MAX(seq), 0) + 1
1063
+ FROM flows_run_parents
1064
+ WHERE TRUE
1065
+ ON CONFLICT (child_id, parent_id) DO NOTHING
1066
+ RETURNING
1067
+ child_id AS "childId",
1068
+ parent_id AS "parentId",
1069
+ seq AS "seq"
1070
+ `;
1071
+ if (inserted[0] !== undefined) {
1072
+ // The cycle check shares the insert's transaction: a hit fails the
1073
+ // effect, rolling the insert back, so a rejected edge is never
1074
+ // durable and there is no check-then-record window for another
1075
+ // writer to slip through (issues #54/#55/#56). The insert
1076
+ // precedes the walk, so the transaction holds the write lock
1077
+ // while walking: under `DurableWriter.write`'s documented contract —
1078
+ // write transactions are mutually serialized (issue #74) — of two
1079
+ // edges that jointly close a cycle, exactly the later one fails.
1080
+ // This is a contract requirement, not a SQLite artifact; a
1081
+ // backend that ran writes at READ COMMITTED would break it and is
1082
+ // excluded by the DurableWriter contract.
1083
+ const cycle = yield* findCyclePath(childId, parentId, parentIdsOf);
1084
+ if (cycle !== undefined) {
1085
+ return yield* Effect.fail(new RunParentCycleError({ path: cycle }));
1086
+ }
1087
+ return {
1088
+ _tag: "Recorded",
1089
+ edge: yield* decodeRunParentEdge(inserted[0])
1090
+ };
1091
+ }
1092
+ const existing = yield* selectRunParent(childId, parentId);
1093
+ if (existing[0] === undefined) {
1094
+ return yield* Effect.die(new EngineStateFault({ reason: "run_parent_edge_missing" }));
1095
+ }
1096
+ return {
1097
+ _tag: "Existing",
1098
+ edge: yield* decodeRunParentEdge(existing[0])
1099
+ };
1100
+ })).pipe(Effect.catch((error) => error instanceof RunParentCycleError ? Effect.fail(error) : Effect.die(error))));
1101
+ const removeRunParentsForRun = Effect.fn("DurableEngineState.removeRunParentsForRun")((runId) => writer.write(sql `
1102
+ DELETE FROM flows_run_parents
1103
+ WHERE child_id = ${runId}
1104
+ OR parent_id = ${runId}
1105
+ `).pipe(Effect.orDie, Effect.asVoid));
1106
+ // Keep state-first ordering. This gate and DurableWriter's shared permit are
1107
+ // both taken at the caller's interruptibility, so an interruptible caller can
1108
+ // still be cancelled while queued, including behind a journal-only write that
1109
+ // skips this gate.
1110
+ // A nested SQL transaction already owns the connection and bypasses this gate.
1111
+ const transactionGate = Semaphore.makeUnsafe(1);
1112
+ const transaction = (effect) => Effect.flatMap(Effect.serviceOption(sql.transactionService), (enclosing) => {
1113
+ const write = (body) => writer.write(body).pipe(Effect.catchCause((cause) => {
1114
+ // Only a sole storage failure is normalized. A composite keeps every
1115
+ // reason for the caller to diagnose, and its storage failures are
1116
+ // demoted to defects one by one rather than cast through the
1117
+ // declared error type: `transaction` promises the BODY's failures,
1118
+ // so a `DatabaseError` arriving as a typed failure would be a lie
1119
+ // the compiler could not catch. Defect identity is unchanged.
1120
+ if (cause.reasons.length === 1) {
1121
+ const reason = cause.reasons[0];
1122
+ if (Cause.isFailReason(reason) && reason.error instanceof DatabaseError) {
1123
+ return Effect.die(reason.error);
1124
+ }
1125
+ }
1126
+ return Effect.failCause(dieOnDatabaseError(cause));
1127
+ }));
1128
+ if (Option.isSome(enclosing))
1129
+ return write(effect);
1130
+ return Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
1131
+ yield* restore(transactionGate.take(1));
1132
+ let released = false;
1133
+ const release = Effect.suspend(() => {
1134
+ if (released)
1135
+ return Effect.void;
1136
+ released = true;
1137
+ return transactionGate.release(1).pipe(Effect.asVoid);
1138
+ });
1139
+ return yield* restore(write(Effect.gen(function* () {
1140
+ // Release at COMMIT, before publication can read through another
1141
+ // transaction. A failed write instead releases in ensuring below.
1142
+ yield* afterCommit(release, sql);
1143
+ return yield* effect;
1144
+ }))).pipe(Effect.ensuring(release));
1145
+ }));
1146
+ });
1147
+ const runParents = Effect.fn("DurableEngineState.runParents")((childId) => sql `
1148
+ SELECT
1149
+ child_id AS "childId",
1150
+ parent_id AS "parentId",
1151
+ seq AS "seq"
1152
+ FROM flows_run_parents
1153
+ WHERE child_id = ${childId}
1154
+ ORDER BY seq
1155
+ `.pipe(Effect.orDie,
1156
+ // One unreadable edge made a run's whole ancestry unreadable, so no
1157
+ // subflow under it could be linked at all.
1158
+ Effect.flatMap((rows) => decodeSweep(rows, "run parent", runParentRowKey, decodeRunParentEdgeResult))));
1159
+ const runChildren = Effect.fn("DurableEngineState.runChildren")((parentId) => sql `
1160
+ SELECT
1161
+ child_id AS "childId",
1162
+ parent_id AS "parentId",
1163
+ seq AS "seq"
1164
+ FROM flows_run_parents
1165
+ WHERE parent_id = ${parentId}
1166
+ ORDER BY seq
1167
+ `.pipe(Effect.orDie,
1168
+ // The cancellation cascade's only cross-process way to find a run's
1169
+ // children: one unreadable sibling edge left every child running after
1170
+ // its parent was cancelled.
1171
+ Effect.flatMap((rows) => decodeSweep(rows, "run parent", runParentRowKey, decodeRunParentEdgeResult))));
1172
+ return DurableEngineState.of({
1173
+ deferred,
1174
+ consumeDeferred,
1175
+ completeDeferred,
1176
+ clock,
1177
+ scheduleClock,
1178
+ completeClock,
1179
+ completeRunClocks,
1180
+ dueClocks,
1181
+ pendingClocks,
1182
+ completedDeferreds,
1183
+ park,
1184
+ wake,
1185
+ waiting,
1186
+ waitingTree,
1187
+ waitingRuns,
1188
+ pendingRuns,
1189
+ pendingRunTail,
1190
+ pendingCancellationRuns,
1191
+ pendingCancellationTail,
1192
+ staleRunningRuns,
1193
+ attemptSurvivors,
1194
+ recordRunParent,
1195
+ removeRunParentsForRun,
1196
+ runParents,
1197
+ runChildren,
1198
+ transaction
1199
+ });
1200
+ });
1201
+ /**
1202
+ * Provides database-backed durable engine state.
1203
+ *
1204
+ * @since 0.1.0
1205
+ * @category layers
1206
+ */
1207
+ export const layer = Layer.effect(DurableEngineState, make);
1208
+ /**
1209
+ * Constructs a deterministic in-memory durable-state implementation.
1210
+ *
1211
+ * The returned service can be shared by multiple fresh engine instances in a
1212
+ * test to model process restart over the same storage. With `runs` supplied
1213
+ * it enforces the same ownership fences as the SQL implementation and is
1214
+ * held to the same contract suite
1215
+ * (`test/contract/DurableEngineStateContract.ts`).
1216
+ *
1217
+ * @since 0.1.0
1218
+ * @category constructors
1219
+ */
1220
+ export const makeMemory = (options = {}) => {
1221
+ const deferreds = new Map();
1222
+ const consumedDeferreds = new Map();
1223
+ const clocks = new Map();
1224
+ const waitingRows = new Map();
1225
+ // childId -> (parentId -> seq); `parentSeq` mirrors the SQL MAX(seq)+1.
1226
+ const parentEdges = new Map();
1227
+ let parentSeq = 0;
1228
+ const snapshotDeferred = (row) => Schema.decodeUnknownEffect(DeferredRow)(row).pipe(Effect.orDie, Effect.flatMap((decoded) => Effect.all({
1229
+ exitJson: encodeJson(decoded.exit, "exit"),
1230
+ metadataJson: decoded.metadata === undefined
1231
+ ? Effect.succeed(null)
1232
+ : encodeJson(decoded.metadata, "metadata")
1233
+ }).pipe(Effect.flatMap(({ exitJson, metadataJson }) => decodeDeferredRow({
1234
+ flowName: decoded.flowName,
1235
+ executionId: decoded.executionId,
1236
+ deferredName: decoded.deferredName,
1237
+ exitJson,
1238
+ metadataJson,
1239
+ completedAtMs: decoded.completedAtMs
1240
+ })))));
1241
+ const snapshotClock = (row) => Schema.decodeUnknownEffect(ClockRow)(row).pipe(Effect.orDie, Effect.map((decoded) => ({ ...decoded })));
1242
+ const snapshotWaiting = (row) => ({ ...row });
1243
+ /** The synchronous twin of `findCyclePath` over the in-memory edge map. */
1244
+ const findCyclePathSync = (childId, parentId) => {
1245
+ if (parentId === childId)
1246
+ return [childId];
1247
+ const seen = new Set([parentId]);
1248
+ const walk = (current, chain) => {
1249
+ for (const parent of parentEdges.get(current)?.keys() ?? []) {
1250
+ if (parent === childId)
1251
+ return [...chain, parent].reverse();
1252
+ if (seen.has(parent))
1253
+ continue;
1254
+ seen.add(parent);
1255
+ const found = walk(parent, [...chain, parent]);
1256
+ if (found !== undefined)
1257
+ return found;
1258
+ }
1259
+ return undefined;
1260
+ };
1261
+ return walk(parentId, [parentId]);
1262
+ };
1263
+ const sameOwner = (left, right) => left.hostId === right.hostId && left.pid === right.pid && left.nonce === right.nonce;
1264
+ /** Mirrors the SQL `flows_runs` owner-match predicate for a run. */
1265
+ const runView = (runId, presented) => {
1266
+ if (options.runs === undefined) {
1267
+ return { exists: true, running: true, owned: true };
1268
+ }
1269
+ const view = options.runs(runId);
1270
+ if (Option.isNone(view)) {
1271
+ return { exists: false, running: false, owned: false };
1272
+ }
1273
+ const owned = presented !== undefined &&
1274
+ view.value.owner !== null &&
1275
+ sameOwner(view.value.owner, presented);
1276
+ return { exists: true, running: view.value.status === "running", owned };
1277
+ };
1278
+ /**
1279
+ * Mirrors the SQL sweeps' run-status join: a row whose run has settled is
1280
+ * never swept, and `Option.none()` from a supplied `runs` view means the run
1281
+ * does not exist, so its orphaned engine-state rows stay hidden. The
1282
+ * permissive default (no `runs` view) treats every run as live because a
1283
+ * standalone memory store has no run table to consult.
1284
+ */
1285
+ const isLive = (runId) => {
1286
+ if (options.runs === undefined)
1287
+ return true;
1288
+ const view = options.runs(runId);
1289
+ return Option.isSome(view) && (view.value.status === "pending" ||
1290
+ view.value.status === "running" ||
1291
+ view.value.status === "suspended");
1292
+ };
1293
+ const pendingMemoryRows = (flowName, after, through, eligibleBeforeMs, cancellationOnly = false) => Array.from(options.listRuns?.() ?? [])
1294
+ .filter(([runId, view]) => view.status === "pending" && (flowName === undefined || view.flowName === flowName) &&
1295
+ (!cancellationOnly || view.cancelRequestedAtMs != null) &&
1296
+ (eligibleBeforeMs === undefined || (view.createdAtMs ?? 0) < eligibleBeforeMs) &&
1297
+ (after === undefined || (view.createdAtMs ?? 0) > after.createdAtMs ||
1298
+ ((view.createdAtMs ?? 0) === after.createdAtMs && compareText(runId, after.runId) > 0)) &&
1299
+ (through === undefined || (view.createdAtMs ?? 0) < through.createdAtMs ||
1300
+ ((view.createdAtMs ?? 0) === through.createdAtMs && compareText(runId, through.runId) <= 0)))
1301
+ .sort(([leftId, left], [rightId, right]) => (left.createdAtMs ?? 0) - (right.createdAtMs ?? 0) || compareText(leftId, rightId))
1302
+ .map(([runId, view]) => ({ runId, createdAtMs: view.createdAtMs ?? 0 }));
1303
+ const unguarded = {
1304
+ deferred: Effect.fn("DurableEngineState.deferred")((address) => Effect.gen(function* () {
1305
+ const row = deferreds.get(deferredKey(address));
1306
+ return row === undefined ? Option.none() : Option.some(yield* snapshotDeferred(row));
1307
+ })),
1308
+ consumeDeferred: Effect.fn("DurableEngineState.consumeDeferred")((address, consumedAtMs) => Effect.sync(() => {
1309
+ const key = deferredKey(address);
1310
+ if (!deferreds.has(key) || consumedDeferreds.has(key))
1311
+ return false;
1312
+ consumedDeferreds.set(key, consumedAtMs);
1313
+ return true;
1314
+ })),
1315
+ completeDeferred: Effect.fn("DurableEngineState.completeDeferred")((row) => Effect.gen(function* () {
1316
+ const stored = yield* snapshotDeferred(row);
1317
+ const key = deferredKey(stored);
1318
+ const existing = deferreds.get(key);
1319
+ if (existing !== undefined) {
1320
+ return {
1321
+ _tag: "Existing",
1322
+ row: yield* snapshotDeferred(existing),
1323
+ digest: yield* memoryDigest(existing)
1324
+ };
1325
+ }
1326
+ deferreds.set(key, stored);
1327
+ return {
1328
+ _tag: "Completed",
1329
+ row: yield* snapshotDeferred(stored),
1330
+ digest: yield* memoryDigest(stored)
1331
+ };
1332
+ })),
1333
+ clock: Effect.fn("DurableEngineState.clock")((address) => Effect.gen(function* () {
1334
+ const row = clocks.get(clockKey(address));
1335
+ return row === undefined ? Option.none() : Option.some(yield* snapshotClock(row));
1336
+ })),
1337
+ scheduleClock: Effect.fn("DurableEngineState.scheduleClock")((row, owner) => Effect.gen(function* () {
1338
+ // Mirrors the SQL fence: creation requires the presented owner to
1339
+ // currently run the execution; a lost fence surfaces as
1340
+ // self-interruption, an existing row wins regardless.
1341
+ const stored = yield* snapshotClock(row);
1342
+ const key = clockKey(stored);
1343
+ const existing = clocks.get(key);
1344
+ if (existing !== undefined) {
1345
+ return { _tag: "Existing", row: yield* snapshotClock(existing) };
1346
+ }
1347
+ const view = runView(stored.executionId, owner);
1348
+ if (!view.exists || !view.running || !view.owned) {
1349
+ return yield* Effect.interrupt;
1350
+ }
1351
+ clocks.set(key, stored);
1352
+ return { _tag: "Scheduled", row: yield* snapshotClock(stored) };
1353
+ })),
1354
+ completeClock: Effect.fn("DurableEngineState.completeClock")((address, completedAtMs) => Effect.sync(() => {
1355
+ const key = clockKey(address);
1356
+ const existing = clocks.get(key);
1357
+ if (existing === undefined) {
1358
+ return { _tag: "NotFound" };
1359
+ }
1360
+ if (existing.completedAtMs !== null) {
1361
+ return { _tag: "AlreadyCompleted", row: { ...existing } };
1362
+ }
1363
+ const row = { ...existing, completedAtMs };
1364
+ clocks.set(key, row);
1365
+ return { _tag: "Completed", row: { ...row } };
1366
+ })),
1367
+ dueClocks: Effect.fn("DurableEngineState.dueClocks")((nowMs) => Effect.forEach(Array.from(clocks.values())
1368
+ .filter((row) => row.completedAtMs === null && row.dueAtMs <= nowMs)
1369
+ .sort((left, right) => left.dueAtMs - right.dueAtMs ||
1370
+ compareText(left.executionId, right.executionId) ||
1371
+ compareText(left.clockName, right.clockName)), snapshotClock)),
1372
+ completeRunClocks: Effect.fn("DurableEngineState.completeRunClocks")((executionId, completedAtMs) => Effect.sync(() => {
1373
+ const completed = [];
1374
+ for (const [key, row] of clocks) {
1375
+ if (row.executionId !== executionId || row.completedAtMs !== null)
1376
+ continue;
1377
+ const next = { ...row, completedAtMs };
1378
+ clocks.set(key, next);
1379
+ completed.push({ ...next });
1380
+ }
1381
+ return completed.sort((left, right) => compareText(left.flowName, right.flowName) || compareText(left.clockName, right.clockName));
1382
+ })),
1383
+ pendingClocks: Effect.fn("DurableEngineState.pendingClocks")((scope) => Effect.flatMap(Effect.sync(() => Array.from(clocks.values())
1384
+ .filter((row) => row.completedAtMs === null &&
1385
+ isLive(row.executionId) &&
1386
+ (scope.executionId === undefined || row.executionId === scope.executionId) &&
1387
+ (scope.flowName === undefined || row.flowName === scope.flowName))
1388
+ .sort((left, right) => left.dueAtMs - right.dueAtMs ||
1389
+ compareText(left.executionId, right.executionId) ||
1390
+ compareText(left.clockName, right.clockName))), (rows) => Effect.forEach(rows, snapshotClock))),
1391
+ completedDeferreds: Effect.fn("DurableEngineState.completedDeferreds")((flowName) => Effect.sync(() => Array.from(deferreds.values())
1392
+ .filter((row) => row.flowName === flowName && isLive(row.executionId) && !consumedDeferreds.has(deferredKey(row)))
1393
+ .map(({ flowName, executionId, deferredName }) => ({
1394
+ flowName,
1395
+ executionId,
1396
+ deferredName
1397
+ }))
1398
+ .sort((left, right) => compareText(left.executionId, right.executionId) ||
1399
+ compareText(left.deferredName, right.deferredName)))),
1400
+ park: Effect.fn("DurableEngineState.park")((runId, waitingPayload, owner) => Effect.sync(() => {
1401
+ // Mirrors the SQL fence: only the current owner of an existing run
1402
+ // may park it; anything else reports NotFound, exactly like the
1403
+ // owner-guarded UPDATE matching no row.
1404
+ const view = runView(runId, owner);
1405
+ if (!view.exists || !view.owned) {
1406
+ return { _tag: "NotFound" };
1407
+ }
1408
+ // The declared question is stored as JSON TEXT and read back decoded,
1409
+ // exactly as the column and its SELECT do it.
1410
+ const row = {
1411
+ runId,
1412
+ reason: waitingPayload.reason,
1413
+ wakeAt: waitingPayload.wakeAt ?? null,
1414
+ token: waitingPayload.token ?? null,
1415
+ ...decodeWaitingRequest(waitingPayload.request)
1416
+ };
1417
+ waitingRows.set(runId, row);
1418
+ return { _tag: "Parked", row: snapshotWaiting(row) };
1419
+ })),
1420
+ wake: Effect.fn("DurableEngineState.wake")((runId) => Effect.sync(() => {
1421
+ const row = waitingRows.get(runId);
1422
+ if (row === undefined) {
1423
+ // Mirrors SQL: an unknown run is NotFound, an existing unparked
1424
+ // run is NotWaiting.
1425
+ return runView(runId, undefined).exists
1426
+ ? { _tag: "NotWaiting" }
1427
+ : { _tag: "NotFound" };
1428
+ }
1429
+ waitingRows.delete(runId);
1430
+ return { _tag: "Woken", row: snapshotWaiting(row) };
1431
+ })),
1432
+ waiting: Effect.fn("DurableEngineState.waiting")((runId) => Effect.sync(() => {
1433
+ const row = waitingRows.get(runId);
1434
+ return row === undefined ? Option.none() : Option.some(snapshotWaiting(row));
1435
+ })),
1436
+ waitingTree: Effect.fn("DurableEngineState.waitingTree")((runId, walk) => Effect.sync(() => {
1437
+ // Breadth-first over recorded spawn edges: the named run first, then
1438
+ // each generation beneath it. This memory view does not model the
1439
+ // parent_run_id trampoline links that the SQL walk also follows.
1440
+ const found = [];
1441
+ const seen = new Set([runId]);
1442
+ let frontier = [runId];
1443
+ for (let depth = 0; depth <= waitingTreeMaxDepth && frontier.length > 0; depth++) {
1444
+ const next = [];
1445
+ for (const current of frontier) {
1446
+ const row = waitingRows.get(current);
1447
+ if (row !== undefined && isLive(current))
1448
+ found.push(snapshotWaiting(row));
1449
+ for (const [childId, parents] of parentEdges) {
1450
+ if (!parents.has(current) || seen.has(childId))
1451
+ continue;
1452
+ // The SQL walk skips a detached subtree; so does this one, for a
1453
+ // view that records the policy. A view that does not describes an
1454
+ // attached child, which is the default.
1455
+ const view = options.runs?.(childId);
1456
+ if (walk?.detached !== "include" && view !== undefined && Option.isSome(view) &&
1457
+ view.value.onParentExit === "detach")
1458
+ continue;
1459
+ seen.add(childId);
1460
+ next.push(childId);
1461
+ }
1462
+ }
1463
+ frontier = next;
1464
+ }
1465
+ return found;
1466
+ })),
1467
+ waitingRuns: Effect.fn("DurableEngineState.waitingRuns")((filter) => Effect.sync(() => Array.from(waitingRows.values())
1468
+ // Mirrors the SQL status predicate: a terminally closed run's
1469
+ // stale waiting row never surfaces to a sweeper (issue #28). The
1470
+ // permissive default (no `runs` view) treats every run as live.
1471
+ .filter((row) => isLive(row.runId))
1472
+ .filter((row) => filter?.reason === undefined || row.reason === filter.reason)
1473
+ .filter((row) => filter?.dueBeforeMs === undefined ||
1474
+ (row.wakeAt !== null && row.wakeAt <= filter.dueBeforeMs))
1475
+ // Mirrors the SQL cancel predicate over
1476
+ // `flows_runs.cancel_requested_at_ms` (issue #68). Without a
1477
+ // `runs` view the flag is unknowable, so the query stays
1478
+ // permissive and the sweeper's own per-row guard decides.
1479
+ .filter((row) => {
1480
+ if (filter?.cancelRequested !== true)
1481
+ return true;
1482
+ if (options.runs === undefined)
1483
+ return true;
1484
+ const view = options.runs(row.runId);
1485
+ return Option.isSome(view) && view.value.cancelRequestedAtMs != null;
1486
+ })
1487
+ .sort((left, right) => Number(left.wakeAt === null) - Number(right.wakeAt === null) ||
1488
+ (left.wakeAt ?? 0) - (right.wakeAt ?? 0) ||
1489
+ compareText(left.runId, right.runId))
1490
+ .map(snapshotWaiting))),
1491
+ pendingRuns: Effect.fn("DurableEngineState.pendingRuns")((flowName, limit, after, through, eligibleBeforeMs) => Effect.sync(() => {
1492
+ const ordered = pendingMemoryRows(flowName, after, through, eligibleBeforeMs);
1493
+ return limit === undefined ? ordered : ordered.slice(0, limit);
1494
+ })),
1495
+ pendingRunTail: Effect.fn("DurableEngineState.pendingRunTail")((flowName, eligibleBeforeMs) => Effect.sync(() => Option.fromNullishOr(pendingMemoryRows(flowName, undefined, undefined, eligibleBeforeMs).at(-1)))),
1496
+ pendingCancellationRuns: Effect.fn("DurableEngineState.pendingCancellationRuns")((limit, after, through) => pendingCancellationLimit(limit).pipe(Effect.andThen(Effect.sync(() => pendingMemoryRows(undefined, after, through, undefined, true).slice(0, limit))))),
1497
+ pendingCancellationTail: Effect.fn("DurableEngineState.pendingCancellationTail")(() => Effect.sync(() => Option.fromNullishOr(pendingMemoryRows(undefined, undefined, undefined, undefined, true).at(-1)))),
1498
+ staleRunningRuns: Effect.fn("DurableEngineState.staleRunningRuns")((staleBeforeMs, limit) => Effect.sync(() => {
1499
+ // Mirrors the SQL scan of `flows_runs`: without an enumerator there
1500
+ // is nothing to scan, so no stale rows exist.
1501
+ if (options.listRuns === undefined)
1502
+ return [];
1503
+ const stale = [];
1504
+ for (const [runId, view] of options.listRuns()) {
1505
+ const heartbeatAtMs = view.heartbeatAtMs;
1506
+ if (view.status === "running" &&
1507
+ typeof heartbeatAtMs === "number" &&
1508
+ heartbeatAtMs < staleBeforeMs) {
1509
+ stale.push({ runId, heartbeatAtMs });
1510
+ }
1511
+ }
1512
+ const ordered = stale.sort((left, right) => left.heartbeatAtMs - right.heartbeatAtMs ||
1513
+ compareText(left.runId, right.runId));
1514
+ // Mirrors the SQL LIMIT: oldest heartbeats first, capped per sweep
1515
+ // (issue #79).
1516
+ return limit === undefined ? ordered : ordered.slice(0, limit);
1517
+ })),
1518
+ recordRunParent: Effect.fn("DurableEngineState.recordRunParent")((childId, parentId) =>
1519
+ // A single synchronous step mirrors the SQL transaction: the cycle
1520
+ // check and the insert are atomic — no fiber can interleave between
1521
+ // them, and a rejected edge is never observable (issues #54/#55/#56).
1522
+ Effect.suspend(() => {
1523
+ const parents = parentEdges.get(childId) ?? new Map();
1524
+ const existing = parents.get(parentId);
1525
+ if (existing !== undefined) {
1526
+ return Effect.succeed({
1527
+ _tag: "Existing",
1528
+ edge: { childId, parentId, seq: existing }
1529
+ });
1530
+ }
1531
+ const cycle = findCyclePathSync(childId, parentId);
1532
+ if (cycle !== undefined) {
1533
+ return Effect.fail(new RunParentCycleError({ path: cycle }));
1534
+ }
1535
+ parentSeq += 1;
1536
+ parents.set(parentId, parentSeq);
1537
+ parentEdges.set(childId, parents);
1538
+ return Effect.succeed({
1539
+ _tag: "Recorded",
1540
+ edge: { childId, parentId, seq: parentSeq }
1541
+ });
1542
+ })),
1543
+ removeRunParentsForRun: Effect.fn("DurableEngineState.removeRunParentsForRun")((runId) => Effect.sync(() => {
1544
+ parentEdges.delete(runId);
1545
+ for (const [childId, parents] of parentEdges) {
1546
+ parents.delete(runId);
1547
+ if (parents.size === 0)
1548
+ parentEdges.delete(childId);
1549
+ }
1550
+ })),
1551
+ runParents: Effect.fn("DurableEngineState.runParents")((childId) => Effect.sync(() => Array.from(parentEdges.get(childId) ?? [])
1552
+ .map(([parentId, seq]) => ({ childId, parentId, seq }))
1553
+ .sort((left, right) => left.seq - right.seq))),
1554
+ runChildren: Effect.fn("DurableEngineState.runChildren")((parentId) => Effect.sync(() => {
1555
+ const edges = [];
1556
+ for (const [childId, parents] of parentEdges) {
1557
+ const seq = parents.get(parentId);
1558
+ if (seq !== undefined)
1559
+ edges.push({ childId, parentId, seq });
1560
+ }
1561
+ return edges.sort((left, right) => left.seq - right.seq);
1562
+ }))
1563
+ };
1564
+ const gate = Semaphore.makeUnsafe(1);
1565
+ const transactionDepth = new Map();
1566
+ const guard = (effect) => Effect.flatMap(Effect.fiberId, (fiberId) => (transactionDepth.get(fiberId) ?? 0) > 0 ? effect : gate.withPermit(effect));
1567
+ const restoreMap = (target, source) => {
1568
+ target.clear();
1569
+ for (const [key, value] of source)
1570
+ target.set(key, value);
1571
+ };
1572
+ const transaction = (effect, options) => Effect.flatMap(Effect.fiberId, (fiberId) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
1573
+ const nested = (transactionDepth.get(fiberId) ?? 0) > 0;
1574
+ if (!nested)
1575
+ yield* restore(gate.take(1));
1576
+ const before = {
1577
+ deferreds: new Map(deferreds),
1578
+ consumedDeferreds: new Map(consumedDeferreds),
1579
+ clocks: new Map(clocks),
1580
+ waitingRows: new Map(waitingRows),
1581
+ parentEdges: new Map([...parentEdges].map(([child, parents]) => [child, new Map(parents)])),
1582
+ parentSeq
1583
+ };
1584
+ transactionDepth.set(fiberId, (transactionDepth.get(fiberId) ?? 0) + 1);
1585
+ let committed = false;
1586
+ let closed = false;
1587
+ const close = Effect.suspend(() => {
1588
+ if (closed)
1589
+ return Effect.void;
1590
+ closed = true;
1591
+ const depth = transactionDepth.get(fiberId) - 1;
1592
+ if (depth === 0)
1593
+ transactionDepth.delete(fiberId);
1594
+ else
1595
+ transactionDepth.set(fiberId, depth);
1596
+ return nested ? Effect.void : gate.release(1).pipe(Effect.asVoid);
1597
+ });
1598
+ const commit = Effect.sync(() => {
1599
+ committed = true;
1600
+ }).pipe(Effect.andThen(close));
1601
+ return yield* Effect.sync(() => options?.onCommit(commit)).pipe(Effect.andThen(restore(effect)), Effect.catchCause((cause) => Effect.sync(() => {
1602
+ if (committed)
1603
+ return;
1604
+ restoreMap(deferreds, before.deferreds);
1605
+ restoreMap(consumedDeferreds, before.consumedDeferreds);
1606
+ restoreMap(clocks, before.clocks);
1607
+ restoreMap(waitingRows, before.waitingRows);
1608
+ restoreMap(parentEdges, before.parentEdges);
1609
+ parentSeq = before.parentSeq;
1610
+ }).pipe(Effect.andThen(Effect.failCause(cause)))), Effect.ensuring(close));
1611
+ })));
1612
+ return DurableEngineState.of({
1613
+ deferred: (address) => guard(unguarded.deferred(address)),
1614
+ consumeDeferred: (address, consumedAtMs) => guard(unguarded.consumeDeferred(address, consumedAtMs)),
1615
+ completeDeferred: (row) => guard(unguarded.completeDeferred(row)),
1616
+ clock: (address) => guard(unguarded.clock(address)),
1617
+ scheduleClock: (row, owner) => guard(unguarded.scheduleClock(row, owner)),
1618
+ completeClock: (address, completedAtMs) => guard(unguarded.completeClock(address, completedAtMs)),
1619
+ dueClocks: (nowMs) => guard(unguarded.dueClocks(nowMs)),
1620
+ completeRunClocks: (executionId, completedAtMs) => guard(unguarded.completeRunClocks(executionId, completedAtMs)),
1621
+ pendingClocks: (scope) => guard(unguarded.pendingClocks(scope)),
1622
+ completedDeferreds: (flowName) => guard(unguarded.completedDeferreds(flowName)),
1623
+ park: (runId, waiting, owner) => guard(unguarded.park(runId, waiting, owner)),
1624
+ wake: (runId) => guard(unguarded.wake(runId)),
1625
+ waiting: (runId) => guard(unguarded.waiting(runId)),
1626
+ waitingTree: (runId, options) => guard(unguarded.waitingTree(runId, options)),
1627
+ waitingRuns: (filter) => guard(unguarded.waitingRuns(filter)),
1628
+ pendingRuns: (flowName, limit, after, through, eligibleBeforeMs) => guard(unguarded.pendingRuns(flowName, limit, after, through, eligibleBeforeMs)),
1629
+ pendingRunTail: (flowName, eligibleBeforeMs) => guard(unguarded.pendingRunTail(flowName, eligibleBeforeMs)),
1630
+ pendingCancellationRuns: (limit, after, through) => guard(unguarded.pendingCancellationRuns(limit, after, through)),
1631
+ pendingCancellationTail: () => guard(unguarded.pendingCancellationTail()),
1632
+ staleRunningRuns: (staleBeforeMs, limit) => guard(unguarded.staleRunningRuns(staleBeforeMs, limit)),
1633
+ attemptSurvivors: undefined,
1634
+ recordRunParent: (childId, parentId) => guard(unguarded.recordRunParent(childId, parentId)),
1635
+ removeRunParentsForRun: (runId) => guard(unguarded.removeRunParentsForRun(runId)),
1636
+ runParents: (childId) => guard(unguarded.runParents(childId)),
1637
+ runChildren: (parentId) => guard(unguarded.runChildren(parentId)),
1638
+ transaction
1639
+ });
1640
+ };
1641
+ /**
1642
+ * Provides deterministic in-memory durable engine state.
1643
+ *
1644
+ * @since 0.1.0
1645
+ * @category layers
1646
+ */
1647
+ export const layerMemory = Layer.sync(DurableEngineState, makeMemory);
1648
+ //# sourceMappingURL=DurableEngineState.js.map