@rikalabs/akter 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +8 -0
  4. package/README.md +116 -0
  5. package/dist/actor/codecs.d.ts +77 -0
  6. package/dist/actor/codecs.js +87 -0
  7. package/dist/actor/connections.d.ts +34 -0
  8. package/dist/actor/connections.js +145 -0
  9. package/dist/actor/definition.d.ts +893 -0
  10. package/dist/actor/definition.js +147 -0
  11. package/dist/actor/descriptor.d.ts +172 -0
  12. package/dist/actor/descriptor.js +367 -0
  13. package/dist/actor/handles.d.ts +77 -0
  14. package/dist/actor/handles.js +265 -0
  15. package/dist/actor/jobs.d.ts +10 -0
  16. package/dist/actor/jobs.js +137 -0
  17. package/dist/actor/layers.d.ts +41 -0
  18. package/dist/actor/layers.js +177 -0
  19. package/dist/actor/reads.d.ts +47 -0
  20. package/dist/actor/reads.js +224 -0
  21. package/dist/actor/served.d.ts +120 -0
  22. package/dist/actor/served.js +72 -0
  23. package/dist/actor/turns.d.ts +13 -0
  24. package/dist/actor/turns.js +332 -0
  25. package/dist/actor/workflows.d.ts +16 -0
  26. package/dist/actor/workflows.js +37 -0
  27. package/dist/client/calls.d.ts +47 -0
  28. package/dist/client/calls.js +425 -0
  29. package/dist/client/clock.d.ts +56 -0
  30. package/dist/client/clock.js +119 -0
  31. package/dist/client/fleet-page.d.ts +15 -0
  32. package/dist/client/fleet-page.js +13 -0
  33. package/dist/client/fleet.d.ts +29 -0
  34. package/dist/client/fleet.js +51 -0
  35. package/dist/client/index.d.ts +17 -0
  36. package/dist/client/index.js +6 -0
  37. package/dist/client/make.d.ts +157 -0
  38. package/dist/client/make.js +221 -0
  39. package/dist/client/offline/queue.d.ts +118 -0
  40. package/dist/client/offline/queue.js +292 -0
  41. package/dist/client/offline/store.d.ts +74 -0
  42. package/dist/client/offline/store.js +78 -0
  43. package/dist/client/optimistic.d.ts +57 -0
  44. package/dist/client/optimistic.js +136 -0
  45. package/dist/client/report.d.ts +2 -0
  46. package/dist/client/report.js +8 -0
  47. package/dist/client/sessions/connection.d.ts +118 -0
  48. package/dist/client/sessions/connection.js +162 -0
  49. package/dist/client/sessions/feed.d.ts +42 -0
  50. package/dist/client/sessions/feed.js +43 -0
  51. package/dist/client/sessions/sse.d.ts +47 -0
  52. package/dist/client/sessions/sse.js +112 -0
  53. package/dist/client/sessions/stream.d.ts +28 -0
  54. package/dist/client/sessions/stream.js +35 -0
  55. package/dist/client/sessions/watch.d.ts +34 -0
  56. package/dist/client/sessions/watch.js +40 -0
  57. package/dist/client/transport.d.ts +37 -0
  58. package/dist/client/transport.js +66 -0
  59. package/dist/contexts/command.d.ts +132 -0
  60. package/dist/contexts/command.js +20 -0
  61. package/dist/contexts/connection.d.ts +68 -0
  62. package/dist/contexts/connection.js +0 -0
  63. package/dist/contexts/job.d.ts +49 -0
  64. package/dist/contexts/job.js +0 -0
  65. package/dist/contexts/workflow.d.ts +147 -0
  66. package/dist/contexts/workflow.js +22 -0
  67. package/dist/errors/actor.d.ts +200 -0
  68. package/dist/errors/actor.js +271 -0
  69. package/dist/errors/content.d.ts +19 -0
  70. package/dist/errors/content.js +14 -0
  71. package/dist/errors/database.d.ts +22 -0
  72. package/dist/errors/database.js +23 -0
  73. package/dist/errors/events.d.ts +17 -0
  74. package/dist/errors/events.js +14 -0
  75. package/dist/errors/subscription.d.ts +12 -0
  76. package/dist/errors/subscription.js +8 -0
  77. package/dist/errors/workflow.d.ts +28 -0
  78. package/dist/errors/workflow.js +17 -0
  79. package/dist/handles/actors.d.ts +17 -0
  80. package/dist/handles/actors.js +7 -0
  81. package/dist/handles/content.d.ts +59 -0
  82. package/dist/handles/content.js +36 -0
  83. package/dist/handles/intents.d.ts +164 -0
  84. package/dist/handles/intents.js +214 -0
  85. package/dist/handles/run.d.ts +31 -0
  86. package/dist/handles/run.js +21 -0
  87. package/dist/handles/workflow.d.ts +27 -0
  88. package/dist/handles/workflow.js +23 -0
  89. package/dist/identity/caller.d.ts +105 -0
  90. package/dist/identity/caller.js +68 -0
  91. package/dist/identity/child.d.ts +18 -0
  92. package/dist/identity/child.js +39 -0
  93. package/dist/identity/command.d.ts +19 -0
  94. package/dist/identity/command.js +21 -0
  95. package/dist/identity/connection.d.ts +24 -0
  96. package/dist/identity/connection.js +29 -0
  97. package/dist/identity/content.d.ts +18 -0
  98. package/dist/identity/content.js +12 -0
  99. package/dist/identity/digest.d.ts +4 -0
  100. package/dist/identity/digest.js +5 -0
  101. package/dist/identity/execution.d.ts +32 -0
  102. package/dist/identity/execution.js +63 -0
  103. package/dist/identity/mint.d.ts +51 -0
  104. package/dist/identity/mint.js +76 -0
  105. package/dist/identity/version.d.ts +2 -0
  106. package/dist/identity/version.js +3 -0
  107. package/dist/index.d.ts +159 -0
  108. package/dist/index.js +97 -0
  109. package/dist/members/blob.d.ts +43 -0
  110. package/dist/members/blob.js +29 -0
  111. package/dist/members/command.d.ts +109 -0
  112. package/dist/members/command.js +61 -0
  113. package/dist/members/connection.d.ts +55 -0
  114. package/dist/members/connection.js +49 -0
  115. package/dist/members/event.d.ts +36 -0
  116. package/dist/members/event.js +24 -0
  117. package/dist/members/job.d.ts +157 -0
  118. package/dist/members/job.js +67 -0
  119. package/dist/members/payload.d.ts +93 -0
  120. package/dist/members/payload.js +145 -0
  121. package/dist/members/reducer.d.ts +64 -0
  122. package/dist/members/reducer.js +27 -0
  123. package/dist/members/stream.d.ts +36 -0
  124. package/dist/members/stream.js +14 -0
  125. package/dist/members/subscription.d.ts +182 -0
  126. package/dist/members/subscription.js +91 -0
  127. package/dist/members/workflow.d.ts +99 -0
  128. package/dist/members/workflow.js +2 -0
  129. package/dist/policies/access.d.ts +35 -0
  130. package/dist/policies/access.js +6 -0
  131. package/dist/policies/command.d.ts +127 -0
  132. package/dist/policies/command.js +45 -0
  133. package/dist/policies/job.d.ts +28 -0
  134. package/dist/policies/job.js +60 -0
  135. package/dist/policies/schedules.d.ts +33 -0
  136. package/dist/policies/schedules.js +131 -0
  137. package/dist/protocol/frames.d.ts +66 -0
  138. package/dist/protocol/frames.js +55 -0
  139. package/dist/protocol/inspection.d.ts +807 -0
  140. package/dist/protocol/inspection.js +243 -0
  141. package/dist/protocol/wire.d.ts +184 -0
  142. package/dist/protocol/wire.js +150 -0
  143. package/dist/runtime/actors.d.ts +155 -0
  144. package/dist/runtime/actors.js +4 -0
  145. package/dist/runtime/admission.d.ts +34 -0
  146. package/dist/runtime/admission.js +72 -0
  147. package/dist/runtime/adoption/backfill.d.ts +27 -0
  148. package/dist/runtime/adoption/backfill.js +144 -0
  149. package/dist/runtime/adoption/enforce.d.ts +55 -0
  150. package/dist/runtime/adoption/enforce.js +241 -0
  151. package/dist/runtime/adoption/observe.d.ts +43 -0
  152. package/dist/runtime/adoption/observe.js +139 -0
  153. package/dist/runtime/adoption/plan.d.ts +45 -0
  154. package/dist/runtime/adoption/plan.js +192 -0
  155. package/dist/runtime/adoption/startup.d.ts +32 -0
  156. package/dist/runtime/adoption/startup.js +76 -0
  157. package/dist/runtime/adoption/status.d.ts +23 -0
  158. package/dist/runtime/adoption/status.js +47 -0
  159. package/dist/runtime/adoption/target.d.ts +33 -0
  160. package/dist/runtime/adoption/target.js +49 -0
  161. package/dist/runtime/connections/holder.d.ts +221 -0
  162. package/dist/runtime/connections/holder.js +816 -0
  163. package/dist/runtime/connections/owner.d.ts +263 -0
  164. package/dist/runtime/connections/owner.js +896 -0
  165. package/dist/runtime/connections/protocol.d.ts +441 -0
  166. package/dist/runtime/connections/protocol.js +222 -0
  167. package/dist/runtime/connections/reads.d.ts +24 -0
  168. package/dist/runtime/connections/reads.js +19 -0
  169. package/dist/runtime/connections/streams.d.ts +62 -0
  170. package/dist/runtime/connections/streams.js +128 -0
  171. package/dist/runtime/connections/transport.d.ts +40 -0
  172. package/dist/runtime/connections/transport.js +68 -0
  173. package/dist/runtime/connections/watch.d.ts +52 -0
  174. package/dist/runtime/connections/watch.js +159 -0
  175. package/dist/runtime/content/grant.d.ts +34 -0
  176. package/dist/runtime/content/grant.js +58 -0
  177. package/dist/runtime/content/store.d.ts +63 -0
  178. package/dist/runtime/content/store.js +294 -0
  179. package/dist/runtime/cron/key.d.ts +2 -0
  180. package/dist/runtime/cron/key.js +2 -0
  181. package/dist/runtime/cron/schedule.d.ts +69 -0
  182. package/dist/runtime/cron/schedule.js +144 -0
  183. package/dist/runtime/database/bounded.d.ts +43 -0
  184. package/dist/runtime/database/bounded.js +108 -0
  185. package/dist/runtime/database/connection.d.ts +8 -0
  186. package/dist/runtime/database/connection.js +18 -0
  187. package/dist/runtime/database/coordination.d.ts +19 -0
  188. package/dist/runtime/database/coordination.js +72 -0
  189. package/dist/runtime/database/flock.d.ts +10 -0
  190. package/dist/runtime/database/flock.js +60 -0
  191. package/dist/runtime/database/gate.d.ts +26 -0
  192. package/dist/runtime/database/gate.js +54 -0
  193. package/dist/runtime/database/keepalive.d.ts +11 -0
  194. package/dist/runtime/database/keepalive.js +22 -0
  195. package/dist/runtime/database/migrations.d.ts +177 -0
  196. package/dist/runtime/database/migrations.js +1018 -0
  197. package/dist/runtime/database/neki/migrations.d.ts +31 -0
  198. package/dist/runtime/database/neki/migrations.js +276 -0
  199. package/dist/runtime/database/neki/session.d.ts +23 -0
  200. package/dist/runtime/database/neki/session.js +31 -0
  201. package/dist/runtime/database/pglite.d.ts +21 -0
  202. package/dist/runtime/database/pglite.js +74 -0
  203. package/dist/runtime/database/replica.d.ts +41 -0
  204. package/dist/runtime/database/replica.js +51 -0
  205. package/dist/runtime/database/shards.d.ts +21 -0
  206. package/dist/runtime/database/shards.js +37 -0
  207. package/dist/runtime/database/snapshot.d.ts +7 -0
  208. package/dist/runtime/database/snapshot.js +7 -0
  209. package/dist/runtime/database/tenancy.d.ts +69 -0
  210. package/dist/runtime/database/tenancy.js +145 -0
  211. package/dist/runtime/database/transient.d.ts +10 -0
  212. package/dist/runtime/database/transient.js +25 -0
  213. package/dist/runtime/drain.d.ts +132 -0
  214. package/dist/runtime/drain.js +109 -0
  215. package/dist/runtime/entity/mailbox.d.ts +86 -0
  216. package/dist/runtime/entity/mailbox.js +121 -0
  217. package/dist/runtime/entity/register.d.ts +424 -0
  218. package/dist/runtime/entity/register.js +669 -0
  219. package/dist/runtime/events/append.d.ts +192 -0
  220. package/dist/runtime/events/append.js +128 -0
  221. package/dist/runtime/events/cursor.d.ts +2 -0
  222. package/dist/runtime/events/cursor.js +5 -0
  223. package/dist/runtime/events/replay.d.ts +20 -0
  224. package/dist/runtime/events/replay.js +45 -0
  225. package/dist/runtime/feeds.d.ts +26 -0
  226. package/dist/runtime/feeds.js +100 -0
  227. package/dist/runtime/fleet/checks.d.ts +17 -0
  228. package/dist/runtime/fleet/checks.js +106 -0
  229. package/dist/runtime/fleet/maintainer.d.ts +38 -0
  230. package/dist/runtime/fleet/maintainer.js +383 -0
  231. package/dist/runtime/fleet/pgoutput.d.ts +41 -0
  232. package/dist/runtime/fleet/pgoutput.js +102 -0
  233. package/dist/runtime/fleet/setup.d.ts +36 -0
  234. package/dist/runtime/fleet/setup.js +58 -0
  235. package/dist/runtime/fleet/subscribe.d.ts +42 -0
  236. package/dist/runtime/fleet/subscribe.js +147 -0
  237. package/dist/runtime/index.d.ts +66 -0
  238. package/dist/runtime/index.js +37 -0
  239. package/dist/runtime/inspector/http.d.ts +19 -0
  240. package/dist/runtime/inspector/http.js +36 -0
  241. package/dist/runtime/inspector/layer.d.ts +46 -0
  242. package/dist/runtime/inspector/layer.js +180 -0
  243. package/dist/runtime/inspector/queries.d.ts +711 -0
  244. package/dist/runtime/inspector/queries.js +494 -0
  245. package/dist/runtime/jobs/attempt.d.ts +254 -0
  246. package/dist/runtime/jobs/attempt.js +413 -0
  247. package/dist/runtime/jobs/isolation.d.ts +20 -0
  248. package/dist/runtime/jobs/isolation.js +10 -0
  249. package/dist/runtime/jobs/progress.d.ts +95 -0
  250. package/dist/runtime/jobs/progress.js +144 -0
  251. package/dist/runtime/layer.d.ts +260 -0
  252. package/dist/runtime/layer.js +876 -0
  253. package/dist/runtime/members.d.ts +381 -0
  254. package/dist/runtime/members.js +8 -0
  255. package/dist/runtime/operators/audit.d.ts +64 -0
  256. package/dist/runtime/operators/audit.js +56 -0
  257. package/dist/runtime/operators/auth.d.ts +29 -0
  258. package/dist/runtime/operators/auth.js +42 -0
  259. package/dist/runtime/operators/export.d.ts +68 -0
  260. package/dist/runtime/operators/export.js +137 -0
  261. package/dist/runtime/operators/grants.d.ts +45 -0
  262. package/dist/runtime/operators/grants.js +40 -0
  263. package/dist/runtime/operators/repair.d.ts +206 -0
  264. package/dist/runtime/operators/repair.js +226 -0
  265. package/dist/runtime/operators/routes.d.ts +35 -0
  266. package/dist/runtime/operators/routes.js +190 -0
  267. package/dist/runtime/operators/seed.d.ts +123 -0
  268. package/dist/runtime/operators/seed.js +123 -0
  269. package/dist/runtime/payloads/versions.d.ts +65 -0
  270. package/dist/runtime/payloads/versions.js +240 -0
  271. package/dist/runtime/peering/authority.d.ts +42 -0
  272. package/dist/runtime/peering/authority.js +132 -0
  273. package/dist/runtime/peering/credentials.d.ts +21 -0
  274. package/dist/runtime/peering/credentials.js +13 -0
  275. package/dist/runtime/peering/transport.d.ts +51 -0
  276. package/dist/runtime/peering/transport.js +175 -0
  277. package/dist/runtime/queries.d.ts +18 -0
  278. package/dist/runtime/queries.js +169 -0
  279. package/dist/runtime/readiness.d.ts +36 -0
  280. package/dist/runtime/readiness.js +44 -0
  281. package/dist/runtime/registration.d.ts +58 -0
  282. package/dist/runtime/registration.js +186 -0
  283. package/dist/runtime/request.d.ts +158 -0
  284. package/dist/runtime/request.js +102 -0
  285. package/dist/runtime/retry.d.ts +8 -0
  286. package/dist/runtime/retry.js +11 -0
  287. package/dist/runtime/runner.d.ts +93 -0
  288. package/dist/runtime/runner.js +122 -0
  289. package/dist/runtime/storage/codec.d.ts +39 -0
  290. package/dist/runtime/storage/codec.js +41 -0
  291. package/dist/runtime/storage/generation.d.ts +69 -0
  292. package/dist/runtime/storage/generation.js +49 -0
  293. package/dist/runtime/storage/placements.d.ts +15 -0
  294. package/dist/runtime/storage/placements.js +38 -0
  295. package/dist/runtime/storage/platform.d.ts +6 -0
  296. package/dist/runtime/storage/platform.js +9 -0
  297. package/dist/runtime/storage/retention.d.ts +73 -0
  298. package/dist/runtime/storage/retention.js +158 -0
  299. package/dist/runtime/subscriptions/identity.d.ts +31 -0
  300. package/dist/runtime/subscriptions/identity.js +45 -0
  301. package/dist/runtime/subscriptions/relay.d.ts +175 -0
  302. package/dist/runtime/subscriptions/relay.js +763 -0
  303. package/dist/runtime/subscriptions/storage.d.ts +40 -0
  304. package/dist/runtime/subscriptions/storage.js +98 -0
  305. package/dist/runtime/sweeps.d.ts +39 -0
  306. package/dist/runtime/sweeps.js +54 -0
  307. package/dist/runtime/telemetry/defects.d.ts +57 -0
  308. package/dist/runtime/telemetry/defects.js +43 -0
  309. package/dist/runtime/telemetry/metrics.d.ts +52 -0
  310. package/dist/runtime/telemetry/metrics.js +138 -0
  311. package/dist/runtime/telemetry/routes.d.ts +19 -0
  312. package/dist/runtime/telemetry/routes.js +18 -0
  313. package/dist/runtime/telemetry/sampler.d.ts +26 -0
  314. package/dist/runtime/telemetry/sampler.js +101 -0
  315. package/dist/runtime/telemetry/spans.d.ts +38 -0
  316. package/dist/runtime/telemetry/spans.js +44 -0
  317. package/dist/runtime/telemetry/usage.d.ts +52 -0
  318. package/dist/runtime/telemetry/usage.js +30 -0
  319. package/dist/runtime/topology/admission.d.ts +13 -0
  320. package/dist/runtime/topology/admission.js +36 -0
  321. package/dist/runtime/topology/locks.d.ts +56 -0
  322. package/dist/runtime/topology/locks.js +81 -0
  323. package/dist/runtime/topology/messages.d.ts +15 -0
  324. package/dist/runtime/topology/messages.js +32 -0
  325. package/dist/runtime/turn/admission.d.ts +22 -0
  326. package/dist/runtime/turn/admission.js +41 -0
  327. package/dist/runtime/turn/blobs.d.ts +38 -0
  328. package/dist/runtime/turn/blobs.js +215 -0
  329. package/dist/runtime/turn/execute.d.ts +208 -0
  330. package/dist/runtime/turn/execute.js +972 -0
  331. package/dist/runtime/turn/group.d.ts +165 -0
  332. package/dist/runtime/turn/group.js +326 -0
  333. package/dist/runtime/turn/hooks.d.ts +44 -0
  334. package/dist/runtime/turn/hooks.js +28 -0
  335. package/dist/runtime/turn/outbox.d.ts +159 -0
  336. package/dist/runtime/turn/outbox.js +269 -0
  337. package/dist/runtime/turn/pipeline.d.ts +68 -0
  338. package/dist/runtime/turn/pipeline.js +83 -0
  339. package/dist/runtime/turn/receipt.d.ts +81 -0
  340. package/dist/runtime/turn/receipt.js +32 -0
  341. package/dist/runtime/turn/relay.d.ts +179 -0
  342. package/dist/runtime/turn/relay.js +685 -0
  343. package/dist/runtime/turn/rows.d.ts +43 -0
  344. package/dist/runtime/turn/rows.js +592 -0
  345. package/dist/runtime/workflows/compatibility.d.ts +125 -0
  346. package/dist/runtime/workflows/compatibility.js +285 -0
  347. package/dist/runtime/workflows/engine.d.ts +107 -0
  348. package/dist/runtime/workflows/engine.js +826 -0
  349. package/dist/runtime/workflows/manifest.d.ts +34 -0
  350. package/dist/runtime/workflows/manifest.js +39 -0
  351. package/dist/runtime/workflows/steps.d.ts +33 -0
  352. package/dist/runtime/workflows/steps.js +152 -0
  353. package/dist/serve/api.d.ts +99 -0
  354. package/dist/serve/api.js +403 -0
  355. package/dist/serve/assertion/binding.d.ts +41 -0
  356. package/dist/serve/assertion/binding.js +92 -0
  357. package/dist/serve/assertion/verify.d.ts +93 -0
  358. package/dist/serve/assertion/verify.js +189 -0
  359. package/dist/serve/auth.d.ts +200 -0
  360. package/dist/serve/auth.js +92 -0
  361. package/dist/serve/clock.d.ts +10 -0
  362. package/dist/serve/clock.js +25 -0
  363. package/dist/serve/jwt.d.ts +65 -0
  364. package/dist/serve/jwt.js +202 -0
  365. package/dist/serve/layer.d.ts +98 -0
  366. package/dist/serve/layer.js +809 -0
  367. package/dist/serve/mcp/endpoint.d.ts +39 -0
  368. package/dist/serve/mcp/endpoint.js +187 -0
  369. package/dist/serve/mcp/tools.d.ts +37 -0
  370. package/dist/serve/mcp/tools.js +125 -0
  371. package/dist/serve/origin.d.ts +6 -0
  372. package/dist/serve/origin.js +21 -0
  373. package/dist/serve/sessions/feed.d.ts +79 -0
  374. package/dist/serve/sessions/feed.js +115 -0
  375. package/dist/serve/sessions/socket.d.ts +56 -0
  376. package/dist/serve/sessions/socket.js +212 -0
  377. package/dist/serve/sessions/sse.d.ts +27 -0
  378. package/dist/serve/sessions/sse.js +26 -0
  379. package/dist/serve/sessions/stream.d.ts +9 -0
  380. package/dist/serve/sessions/stream.js +9 -0
  381. package/dist/serve/sessions/watch.d.ts +12 -0
  382. package/dist/serve/sessions/watch.js +11 -0
  383. package/dist/serve/wire.d.ts +16 -0
  384. package/dist/serve/wire.js +50 -0
  385. package/dist/state/blob.d.ts +71 -0
  386. package/dist/state/blob.js +0 -0
  387. package/dist/state/migration.d.ts +53 -0
  388. package/dist/state/migration.js +29 -0
  389. package/dist/tables/fleet.d.ts +170 -0
  390. package/dist/tables/fleet.js +214 -0
  391. package/dist/tables/owned.d.ts +250 -0
  392. package/dist/tables/owned.js +233 -0
  393. package/dist/testing/actor-test.d.ts +360 -0
  394. package/dist/testing/actor-test.js +337 -0
  395. package/dist/testing/cluster.d.ts +93 -0
  396. package/dist/testing/cluster.js +296 -0
  397. package/dist/testing/conformance/access.d.ts +5 -0
  398. package/dist/testing/conformance/access.js +531 -0
  399. package/dist/testing/conformance/admission.d.ts +11 -0
  400. package/dist/testing/conformance/admission.js +182 -0
  401. package/dist/testing/conformance/adoption.d.ts +2 -0
  402. package/dist/testing/conformance/adoption.js +1019 -0
  403. package/dist/testing/conformance/assertions.d.ts +202 -0
  404. package/dist/testing/conformance/assertions.js +849 -0
  405. package/dist/testing/conformance/batches.d.ts +41 -0
  406. package/dist/testing/conformance/batches.js +388 -0
  407. package/dist/testing/conformance/blobs.d.ts +14 -0
  408. package/dist/testing/conformance/blobs.js +405 -0
  409. package/dist/testing/conformance/capacity.d.ts +8 -0
  410. package/dist/testing/conformance/capacity.js +433 -0
  411. package/dist/testing/conformance/client.d.ts +5 -0
  412. package/dist/testing/conformance/client.js +719 -0
  413. package/dist/testing/conformance/cold-serve.d.ts +16 -0
  414. package/dist/testing/conformance/cold-serve.js +254 -0
  415. package/dist/testing/conformance/connections/actors.d.ts +1143 -0
  416. package/dist/testing/conformance/connections/actors.js +180 -0
  417. package/dist/testing/conformance/connections/harness.d.ts +1754 -0
  418. package/dist/testing/conformance/connections/harness.js +142 -0
  419. package/dist/testing/conformance/connections/holders.d.ts +4 -0
  420. package/dist/testing/conformance/connections/holders.js +165 -0
  421. package/dist/testing/conformance/connections/lifecycle.d.ts +4 -0
  422. package/dist/testing/conformance/connections/lifecycle.js +113 -0
  423. package/dist/testing/conformance/connections/limits.d.ts +4 -0
  424. package/dist/testing/conformance/connections/limits.js +127 -0
  425. package/dist/testing/conformance/connections/reauthorization.d.ts +4 -0
  426. package/dist/testing/conformance/connections/reauthorization.js +170 -0
  427. package/dist/testing/conformance/connections/resync.d.ts +4 -0
  428. package/dist/testing/conformance/connections/resync.js +360 -0
  429. package/dist/testing/conformance/connections/takeover.d.ts +4 -0
  430. package/dist/testing/conformance/connections/takeover.js +287 -0
  431. package/dist/testing/conformance/connections.d.ts +4 -0
  432. package/dist/testing/conformance/connections.js +15 -0
  433. package/dist/testing/conformance/content-blobs.d.ts +16 -0
  434. package/dist/testing/conformance/content-blobs.js +534 -0
  435. package/dist/testing/conformance/counter.d.ts +16 -0
  436. package/dist/testing/conformance/counter.js +813 -0
  437. package/dist/testing/conformance/cron.d.ts +5 -0
  438. package/dist/testing/conformance/cron.js +665 -0
  439. package/dist/testing/conformance/drain.d.ts +26 -0
  440. package/dist/testing/conformance/drain.js +540 -0
  441. package/dist/testing/conformance/effect-control.d.ts +38 -0
  442. package/dist/testing/conformance/effect-control.js +1059 -0
  443. package/dist/testing/conformance/effects.d.ts +23 -0
  444. package/dist/testing/conformance/effects.js +432 -0
  445. package/dist/testing/conformance/events.d.ts +28 -0
  446. package/dist/testing/conformance/events.js +335 -0
  447. package/dist/testing/conformance/export.d.ts +2 -0
  448. package/dist/testing/conformance/export.js +368 -0
  449. package/dist/testing/conformance/fleet.d.ts +444 -0
  450. package/dist/testing/conformance/fleet.js +1009 -0
  451. package/dist/testing/conformance/groups.d.ts +7 -0
  452. package/dist/testing/conformance/groups.js +353 -0
  453. package/dist/testing/conformance/heap.d.ts +3 -0
  454. package/dist/testing/conformance/heap.js +149 -0
  455. package/dist/testing/conformance/http.d.ts +2809 -0
  456. package/dist/testing/conformance/http.js +1234 -0
  457. package/dist/testing/conformance/inspection-views.d.ts +8 -0
  458. package/dist/testing/conformance/inspection-views.js +272 -0
  459. package/dist/testing/conformance/inspector.d.ts +7 -0
  460. package/dist/testing/conformance/inspector.js +650 -0
  461. package/dist/testing/conformance/mint.d.ts +58 -0
  462. package/dist/testing/conformance/mint.js +692 -0
  463. package/dist/testing/conformance/multi-runner.d.ts +8 -0
  464. package/dist/testing/conformance/multi-runner.js +403 -0
  465. package/dist/testing/conformance/neki/plan.d.ts +19 -0
  466. package/dist/testing/conformance/neki/plan.js +30 -0
  467. package/dist/testing/conformance/observability.d.ts +3 -0
  468. package/dist/testing/conformance/observability.js +343 -0
  469. package/dist/testing/conformance/offline.d.ts +4 -0
  470. package/dist/testing/conformance/offline.js +474 -0
  471. package/dist/testing/conformance/operator-harness.d.ts +57 -0
  472. package/dist/testing/conformance/operator-harness.js +78 -0
  473. package/dist/testing/conformance/operator.d.ts +3 -0
  474. package/dist/testing/conformance/operator.js +379 -0
  475. package/dist/testing/conformance/outbox-cross-shard.d.ts +14 -0
  476. package/dist/testing/conformance/outbox-cross-shard.js +160 -0
  477. package/dist/testing/conformance/outbox.d.ts +36 -0
  478. package/dist/testing/conformance/outbox.js +437 -0
  479. package/dist/testing/conformance/payload-migrations.d.ts +3 -0
  480. package/dist/testing/conformance/payload-migrations.js +612 -0
  481. package/dist/testing/conformance/pipeline.d.ts +3 -0
  482. package/dist/testing/conformance/pipeline.js +1040 -0
  483. package/dist/testing/conformance/placement.d.ts +22 -0
  484. package/dist/testing/conformance/placement.js +539 -0
  485. package/dist/testing/conformance/platform.d.ts +40 -0
  486. package/dist/testing/conformance/platform.js +101 -0
  487. package/dist/testing/conformance/progress.d.ts +39 -0
  488. package/dist/testing/conformance/progress.js +666 -0
  489. package/dist/testing/conformance/properties.d.ts +6 -0
  490. package/dist/testing/conformance/properties.js +295 -0
  491. package/dist/testing/conformance/protocols.d.ts +4 -0
  492. package/dist/testing/conformance/protocols.js +618 -0
  493. package/dist/testing/conformance/provider/advertise.d.ts +21 -0
  494. package/dist/testing/conformance/provider/advertise.js +44 -0
  495. package/dist/testing/conformance/read-your-writes.d.ts +20 -0
  496. package/dist/testing/conformance/read-your-writes.js +192 -0
  497. package/dist/testing/conformance/reducers.d.ts +8 -0
  498. package/dist/testing/conformance/reducers.js +258 -0
  499. package/dist/testing/conformance/relay.d.ts +42 -0
  500. package/dist/testing/conformance/relay.js +1115 -0
  501. package/dist/testing/conformance/restore.d.ts +43 -0
  502. package/dist/testing/conformance/restore.js +341 -0
  503. package/dist/testing/conformance/retention.d.ts +14 -0
  504. package/dist/testing/conformance/retention.js +463 -0
  505. package/dist/testing/conformance/rls.d.ts +24 -0
  506. package/dist/testing/conformance/rls.js +576 -0
  507. package/dist/testing/conformance/simulation.d.ts +31 -0
  508. package/dist/testing/conformance/simulation.js +167 -0
  509. package/dist/testing/conformance/single-shard.d.ts +2 -0
  510. package/dist/testing/conformance/single-shard.js +125 -0
  511. package/dist/testing/conformance/singleton.d.ts +3 -0
  512. package/dist/testing/conformance/singleton.js +293 -0
  513. package/dist/testing/conformance/statements.d.ts +60 -0
  514. package/dist/testing/conformance/statements.js +108 -0
  515. package/dist/testing/conformance/streams.d.ts +7 -0
  516. package/dist/testing/conformance/streams.js +280 -0
  517. package/dist/testing/conformance/subscriptions/access.d.ts +4 -0
  518. package/dist/testing/conformance/subscriptions/access.js +98 -0
  519. package/dist/testing/conformance/subscriptions/actors.d.ts +4910 -0
  520. package/dist/testing/conformance/subscriptions/actors.js +372 -0
  521. package/dist/testing/conformance/subscriptions/cluster.d.ts +4 -0
  522. package/dist/testing/conformance/subscriptions/cluster.js +89 -0
  523. package/dist/testing/conformance/subscriptions/delivery.d.ts +4 -0
  524. package/dist/testing/conformance/subscriptions/delivery.js +253 -0
  525. package/dist/testing/conformance/subscriptions/deploys.d.ts +4 -0
  526. package/dist/testing/conformance/subscriptions/deploys.js +162 -0
  527. package/dist/testing/conformance/subscriptions/epochs.d.ts +4 -0
  528. package/dist/testing/conformance/subscriptions/epochs.js +169 -0
  529. package/dist/testing/conformance/subscriptions/failures.d.ts +4 -0
  530. package/dist/testing/conformance/subscriptions/failures.js +108 -0
  531. package/dist/testing/conformance/subscriptions/feeds.d.ts +4 -0
  532. package/dist/testing/conformance/subscriptions/feeds.js +218 -0
  533. package/dist/testing/conformance/subscriptions/harness.d.ts +124 -0
  534. package/dist/testing/conformance/subscriptions/harness.js +143 -0
  535. package/dist/testing/conformance/subscriptions/operator.d.ts +4 -0
  536. package/dist/testing/conformance/subscriptions/operator.js +128 -0
  537. package/dist/testing/conformance/subscriptions/retention.d.ts +4 -0
  538. package/dist/testing/conformance/subscriptions/retention.js +288 -0
  539. package/dist/testing/conformance/subscriptions/routing.d.ts +4 -0
  540. package/dist/testing/conformance/subscriptions/routing.js +179 -0
  541. package/dist/testing/conformance/subscriptions.d.ts +4 -0
  542. package/dist/testing/conformance/subscriptions.js +19 -0
  543. package/dist/testing/conformance/tables.d.ts +125 -0
  544. package/dist/testing/conformance/tables.js +664 -0
  545. package/dist/testing/conformance/transports/actors.d.ts +1907 -0
  546. package/dist/testing/conformance/transports/actors.js +163 -0
  547. package/dist/testing/conformance/transports/client.d.ts +3 -0
  548. package/dist/testing/conformance/transports/client.js +237 -0
  549. package/dist/testing/conformance/transports/feeds.d.ts +3 -0
  550. package/dist/testing/conformance/transports/feeds.js +232 -0
  551. package/dist/testing/conformance/transports/harness.d.ts +93 -0
  552. package/dist/testing/conformance/transports/harness.js +84 -0
  553. package/dist/testing/conformance/transports/streams.d.ts +3 -0
  554. package/dist/testing/conformance/transports/streams.js +96 -0
  555. package/dist/testing/conformance/transports/websocket.d.ts +3 -0
  556. package/dist/testing/conformance/transports/websocket.js +384 -0
  557. package/dist/testing/conformance/transports/wire.d.ts +141 -0
  558. package/dist/testing/conformance/transports/wire.js +204 -0
  559. package/dist/testing/conformance/transports.d.ts +3 -0
  560. package/dist/testing/conformance/transports.js +11 -0
  561. package/dist/testing/conformance/watch.d.ts +59 -0
  562. package/dist/testing/conformance/watch.js +879 -0
  563. package/dist/testing/conformance/workflow-engine.d.ts +97 -0
  564. package/dist/testing/conformance/workflow-engine.js +253 -0
  565. package/dist/testing/conformance/workflow-versions.d.ts +3 -0
  566. package/dist/testing/conformance/workflow-versions.js +545 -0
  567. package/dist/testing/conformance/workflows/access.d.ts +4 -0
  568. package/dist/testing/conformance/workflows/access.js +147 -0
  569. package/dist/testing/conformance/workflows/actors.d.ts +2317 -0
  570. package/dist/testing/conformance/workflows/actors.js +305 -0
  571. package/dist/testing/conformance/workflows/basics.d.ts +4 -0
  572. package/dist/testing/conformance/workflows/basics.js +144 -0
  573. package/dist/testing/conformance/workflows/engine.d.ts +4 -0
  574. package/dist/testing/conformance/workflows/engine.js +80 -0
  575. package/dist/testing/conformance/workflows/guards.d.ts +4 -0
  576. package/dist/testing/conformance/workflows/guards.js +172 -0
  577. package/dist/testing/conformance/workflows/harness.d.ts +14 -0
  578. package/dist/testing/conformance/workflows/harness.js +44 -0
  579. package/dist/testing/conformance/workflows/recovery.d.ts +4 -0
  580. package/dist/testing/conformance/workflows/recovery.js +181 -0
  581. package/dist/testing/conformance/workflows/starts.d.ts +4 -0
  582. package/dist/testing/conformance/workflows/starts.js +57 -0
  583. package/dist/testing/conformance/workflows/suspension.d.ts +4 -0
  584. package/dist/testing/conformance/workflows/suspension.js +106 -0
  585. package/dist/testing/conformance/workflows/waits.d.ts +4 -0
  586. package/dist/testing/conformance/workflows/waits.js +284 -0
  587. package/dist/testing/conformance/workflows.d.ts +4 -0
  588. package/dist/testing/conformance/workflows.js +19 -0
  589. package/dist/testing/conformance.d.ts +330 -0
  590. package/dist/testing/conformance.js +364 -0
  591. package/dist/testing/database.d.ts +31 -0
  592. package/dist/testing/database.js +70 -0
  593. package/dist/testing/foundation.d.ts +41 -0
  594. package/dist/testing/foundation.js +517 -0
  595. package/dist/testing/index.d.ts +20 -0
  596. package/dist/testing/index.js +12 -0
  597. package/dist/testing/property.d.ts +40 -0
  598. package/dist/testing/property.js +95 -0
  599. package/dist/testing/simulate-cluster.d.ts +112 -0
  600. package/dist/testing/simulate-cluster.js +257 -0
  601. package/dist/testing/simulate.d.ts +90 -0
  602. package/dist/testing/simulate.js +127 -0
  603. package/package.json +1 -0
@@ -0,0 +1,826 @@
1
+ import { Cause, Context, Crypto, Data, Effect, Exit, Fiber, Latch, Option, Schema, Scope, } from "effect";
2
+ import { SqlClient, SqlError } from "effect/sql";
3
+ import { Activity, Workflow as EffectWorkflow, WorkflowEngine } from "effect/workflow";
4
+ import { CallPhase, CurrentCallPhase, CurrentWorkflow, RecordedExit, StoredResult, } from "../../contexts/workflow.js";
5
+ import { ActivityOutcomeUnknown } from "../../errors/workflow.js";
6
+ import {} from "../members.js";
7
+ import { Outcome, Request } from "../request.js";
8
+ import { Due, emptyOutbox } from "../../handles/intents.js";
9
+ import { ExecutionIdOutput, INTERRUPT, RESUME, START, StartPayload, ExecutionTarget, } from "../../handles/workflow.js";
10
+ import { Caller, principal, System } from "../../identity/caller.js";
11
+ import { decodeExecutionId, encodeExecutionId } from "../../identity/execution.js";
12
+ import { bucketOf, OutboxRuntime, writeOutbox } from "../turn/outbox.js";
13
+ import { databaseTime } from "../turn/admission.js";
14
+ import { TurnHooks } from "../turn/hooks.js";
15
+ import { compress, decompress } from "../storage/codec.js";
16
+ import { actorRow, fence } from "../storage/generation.js";
17
+ import { decodeStoredManifest, markerProblem, recordedStepProblem, startVerdict, } from "./compatibility.js";
18
+ import { manifestOf, toJson } from "./manifest.js";
19
+ /** A running activity re-arms its execution's timer this far ahead, so a lost runner's work resumes. */
20
+ export const RECOVERY_MS = 30_000;
21
+ /** The outbox timer key of an execution's recovery timer. */
22
+ export const timerKey = (executionId) => `wf:${executionId}`;
23
+ const CallerJson = Schema.fromJsonString(Caller);
24
+ const encodeCaller = Schema.encodeEffect(CallerJson);
25
+ const decodeCaller = Schema.decodeEffect(CallerJson);
26
+ const encodeExecutionOutput = Schema.encodeEffect(ExecutionIdOutput);
27
+ const encodeTarget = Schema.encodeEffect(ExecutionTarget);
28
+ const decodeTarget = Schema.decodeEffect(ExecutionTarget);
29
+ const decodeStart = Schema.decodeEffect(StartPayload);
30
+ /** Dies a run whose activation no longer holds the owner's generation; nothing it wrote commits. */
31
+ class StaleRun extends Data.TaggedError("StaleRun") {
32
+ }
33
+ /** Ends a replay that reached a step it must wait for; its rows and timer are committed. */
34
+ class Suspend extends Data.TaggedError("Suspend") {
35
+ }
36
+ const isSignal = (signal) => (cause) => cause.reasons.some((reason) => Cause.isDieReason(reason) && reason.defect instanceof signal);
37
+ const suspended = isSignal(Suspend);
38
+ const stale = isSignal(StaleRun);
39
+ const success = (value) => ({
40
+ outcome: Outcome.cases.Success.make({ value }),
41
+ state: [],
42
+ complete: false,
43
+ events: [],
44
+ outbox: emptyOutbox,
45
+ });
46
+ /** Writes the execution's one keyed resume timer, replacing any pending one. */
47
+ const armTimer = Effect.fnUntraced(function* (routingKey, ref, executionId, dueAt, onBehalfOf) {
48
+ const key = timerKey(executionId);
49
+ return yield* writeOutbox(routingKey, ref, {
50
+ intents: [
51
+ {
52
+ target: ref,
53
+ command: RESUME,
54
+ payload: yield* encodeTarget({ executionId }).pipe(Effect.orDie),
55
+ caller: System.make({
56
+ source: "workflow",
57
+ ref,
58
+ onBehalfOf: Option.getOrUndefined(onBehalfOf),
59
+ }),
60
+ due: dueAt === undefined ? undefined : Due.cases.At.make({ epochMillis: dueAt }),
61
+ key,
62
+ },
63
+ ],
64
+ replaced: [key],
65
+ jobs: [],
66
+ subscriptions: [],
67
+ cancelledJobs: [],
68
+ });
69
+ });
70
+ const deleteTimer = (sql, routingKey, ref, executionId) => sql `DELETE FROM actor_outbox WHERE ${actorRow({ sql, actor: { key: routingKey, ref } })} AND timer_key = ${timerKey(executionId)}`;
71
+ /**
72
+ * Inserts an execution with its version markers inside the starting owner
73
+ * turn. A repeated start attaches: nothing is rewritten.
74
+ *
75
+ * An owner-staged start's cursor sits before the staging turn's events, so a wait
76
+ * sees them and every later owner event, including ones committed before the
77
+ * start is delivered. The run starts at once on this activation and the recovery
78
+ * timer resumes it if this runner dies first. The start manifest is restored if
79
+ * retention pruned it while a runner of an older deployment still starts
80
+ * executions under it.
81
+ */
82
+ const insertExecution = Effect.fnUntraced(function* (options) {
83
+ const sql = yield* SqlClient.SqlClient;
84
+ const { routingKey, ref, workflow, executionId } = options;
85
+ const now = yield* databaseTime;
86
+ const manifest = yield* manifestOf(ref.actor, workflow.member);
87
+ const inserted = yield* sql `
88
+ WITH x AS (INSERT INTO actor_workflow_executions (routing_key, execution_id, bucket, tenant_id, actor_type, actor_id,
89
+ workflow, workflow_key, manifest_hash, payload, caller, event_cursor, status, started_at_ms)
90
+ SELECT ${routingKey}, ${executionId}, ${bucketOf(routingKey)}, ${ref.tenant}, ${ref.actor}, ${ref.id},
91
+ ${workflow.member.tag}, ${options.key}, ${manifest.hash}, ${compress(options.payload)},
92
+ ${yield* encodeCaller(options.caller).pipe(Effect.orDie)},
93
+ COALESCE(${options.after}::bigint, g.event_sequence),
94
+ 'running', ${now}
95
+ FROM actor_generations g WHERE ${actorRow({ sql, actor: { key: routingKey, ref } })}
96
+ ON CONFLICT DO NOTHING RETURNING 1),
97
+ m AS (INSERT INTO actor_workflow_manifests (actor_type, workflow, manifest_hash, manifest, accepted_at_ms)
98
+ SELECT ${ref.actor}, ${workflow.member.tag}, ${manifest.hash}, ${toJson(manifest.manifest)}::jsonb, 0
99
+ WHERE EXISTS (SELECT 1 FROM x)
100
+ ON CONFLICT DO NOTHING)
101
+ SELECT 1 FROM x`;
102
+ if (inserted.length === 0)
103
+ return false;
104
+ const markers = Object.entries(workflow.member.versions);
105
+ if (markers.length > 0)
106
+ yield* sql `INSERT INTO actor_workflow_step ${sql.insert(markers.map(([name, range]) => ({
107
+ routing_key: routingKey,
108
+ execution_id: executionId,
109
+ tenant_id: ref.tenant,
110
+ actor_type: ref.actor,
111
+ actor_id: ref.id,
112
+ step: name,
113
+ attempt: 0,
114
+ kind: "version",
115
+ version: range.current,
116
+ started_at_ms: now,
117
+ })))}`;
118
+ yield* armTimer(routingKey, ref, executionId, now + RECOVERY_MS, principal(options.caller));
119
+ return true;
120
+ });
121
+ /**
122
+ * The reserved commands a workflow member adds to its owner: the member's own
123
+ * start, a start staged as an intent, the relay's resume, and interrupt.
124
+ *
125
+ * Interrupting a finished or unknown execution changes nothing.
126
+ */
127
+ export const workflowCommands = ({ registration, routingKeyOf, services, }) => {
128
+ const commands = new Map();
129
+ const start = (request, workflow, payload, key, after) => Effect.gen(function* () {
130
+ const executionId = yield* encodeExecutionId({
131
+ tenant: request.ref.tenant,
132
+ actor: request.ref.actor,
133
+ id: request.ref.id,
134
+ workflow: workflow.member.tag,
135
+ key,
136
+ }).pipe(Effect.orDie);
137
+ yield* insertExecution({
138
+ routingKey: routingKeyOf(request.ref),
139
+ ref: request.ref,
140
+ workflow,
141
+ executionId,
142
+ key,
143
+ payload,
144
+ caller: request.caller,
145
+ after,
146
+ });
147
+ return success(yield* encodeExecutionOutput({ value: executionId }).pipe(Effect.orDie));
148
+ }).pipe(Effect.catchIf(SqlError.isSqlError, Effect.die), Effect.provideContext(services));
149
+ for (const workflow of registration.workflows.values())
150
+ commands.set(workflow.member.tag, {
151
+ internal: false,
152
+ handler: false,
153
+ run: (request) => Effect.gen(function* () {
154
+ const key = yield* workflow.key(request.payload, request.commandId);
155
+ return yield* start(request, workflow, request.payload, key, null);
156
+ }),
157
+ });
158
+ if (registration.workflows.size === 0)
159
+ return commands;
160
+ commands.set(START, {
161
+ internal: true,
162
+ handler: false,
163
+ run: (request) => Effect.gen(function* () {
164
+ const staged = yield* decodeStart(request.payload).pipe(Effect.orDie);
165
+ const workflow = registration.workflows.get(staged.workflow);
166
+ if (workflow === undefined)
167
+ return yield* Effect.die(new Error(`Unregistered workflow ${staged.workflow}`));
168
+ return yield* start(request, workflow, staged.input, staged.key, staged.after);
169
+ }),
170
+ });
171
+ commands.set(RESUME, {
172
+ internal: true,
173
+ handler: false,
174
+ run: (request) => decodeTarget(request.payload).pipe(Effect.orDie, Effect.map(() => success('{"value":null}'))),
175
+ });
176
+ commands.set(INTERRUPT, {
177
+ internal: false,
178
+ handler: false,
179
+ run: (request) => Effect.gen(function* () {
180
+ const sql = yield* SqlClient.SqlClient;
181
+ const { executionId } = yield* decodeTarget(request.payload).pipe(Effect.orDie);
182
+ const execution = yield* decodeExecutionId(executionId).pipe(Effect.orDie);
183
+ const routingKey = routingKeyOf(request.ref);
184
+ if (execution.tenant !== request.ref.tenant ||
185
+ execution.actor !== request.ref.actor ||
186
+ execution.id !== request.ref.id)
187
+ return yield* Effect.die(new Error("Execution id names another owner"));
188
+ const [row] = yield* sql `
189
+ UPDATE actor_workflow_executions SET interrupt = true
190
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId} AND status <> 'finished'
191
+ RETURNING caller`;
192
+ if (row !== undefined) {
193
+ const caller = yield* decodeCaller(row.caller).pipe(Effect.orDie);
194
+ yield* armTimer(routingKey, request.ref, executionId, undefined, principal(caller));
195
+ }
196
+ return success('{"value":null}');
197
+ }).pipe(Effect.catchIf(SqlError.isSqlError, Effect.die), Effect.provideContext(services)),
198
+ });
199
+ return commands;
200
+ };
201
+ /** The execution a successful workflow command names, if it names one. */
202
+ export const kickedExecution = ({ request, outcome, }) => Effect.gen(function* () {
203
+ if (!Outcome.guards.Success(outcome))
204
+ return undefined;
205
+ if (request.command === RESUME || request.command === INTERRUPT)
206
+ return {
207
+ executionId: (yield* decodeTarget(request.payload)).executionId,
208
+ interrupt: request.command === INTERRUPT,
209
+ };
210
+ const started = yield* Schema.decodeEffect(ExecutionIdOutput)(outcome.value);
211
+ return { executionId: started.value, interrupt: false };
212
+ }).pipe(Effect.orDie);
213
+ const RecordedJson = Schema.fromJsonString(RecordedExit);
214
+ const ResultJson = Schema.fromJsonString(StoredResult);
215
+ const decodeRecorded = (bytes) => Schema.decodeEffect(RecordedJson)(decompress(bytes)).pipe(Effect.orDie);
216
+ const encodeRecorded = (exit) => compress(JSON.stringify(exit));
217
+ const encodeResult = (result) => compress(JSON.stringify(result));
218
+ /** A step row's key in a run's replay map; only activities have attempts past 1. */
219
+ const slot = (step, attempt) => `${attempt}/${step}`;
220
+ const callIdentity = (executionId, step, attempt, ordinal) => JSON.stringify([executionId, step, attempt, ordinal]);
221
+ /** Decodes a finished execution's stored result. */
222
+ export const decodeResult = (bytes) => Schema.decodeEffect(ResultJson)(decompress(bytes)).pipe(Effect.orDie);
223
+ /** Stable 128 bits as a version-4 UUID string, so a derived id passes command-id validation. */
224
+ const derivedUuid = (bytes) => {
225
+ const hex = Array.from(bytes.subarray(0, 16), (byte) => byte.toString(16).padStart(2, "0")).join("");
226
+ const variant = ((parseInt(hex[16], 16) & 0x3) | 0x8).toString(16);
227
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-${variant}${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
228
+ };
229
+ /**
230
+ * Runs one activation's workflow executions. Postgres holds every step; the
231
+ * live fibers here only save a replay. Each write is a short transaction that
232
+ * first checks the activation still holds the owner's generation.
233
+ *
234
+ * Compatibility: a runner leaves an execution for a compatible one when it lacks
235
+ * the workflow, its markers exclude the execution's, it lacks a recorded step or a
236
+ * step of the start manifest, or it would decode a recorded result or the payload
237
+ * differently. Once this runner's result schemas apply to the steps still to
238
+ * settle, its manifest becomes the execution's start manifest; a `newer` manifest
239
+ * is one accepted after this runner's own, as when a newer deployment starts
240
+ * executions while this runner still serves.
241
+ *
242
+ * Replay: an interrupted execution replays to its first unsettled step and stops
243
+ * there, so the compensation finalizers of completed steps run before the
244
+ * interrupt is recorded. A replay of a parked execution counts as running until it parks or
245
+ * finishes, so inspection never reports a working run as suspended. A wake that
246
+ * arrived during a pass replays the run once more unless the pass left the
247
+ * execution for another runner or lost its generation, and a pass the engine
248
+ * stopped to replay always replays. A parking step waits, on the pass's idle
249
+ * signal, until every other step of the pass has parked or finished: a parked branch would
250
+ * otherwise interrupt concurrent branches mid-step, losing a sibling's clock, wait
251
+ * or activity work and possibly replaying forever. A race branch parked on a clock
252
+ * or wait that can now settle stops the run so its replay settles it, and a
253
+ * running sibling activity reruns under the same attempt. The relay consumed the
254
+ * recovery timer, so a still-running activity needs another.
255
+ *
256
+ * Steps: only the caller and tenant are inherited from the activation, because
257
+ * steps run inside the body's fiber whose caller and tenant are the execution's
258
+ * recorded ones. Effect's workflow instance names a workflow, and compensation
259
+ * never reads more of it. Rows are keyed by step and attempt, so each
260
+ * `Activity.retry` attempt is its own row with its own exit. The pending row is
261
+ * committed before an activity runs, so a rerun after a crash reuses its attempt
262
+ * and derived ids. A clock's due time is recorded once, so a replay never moves it.
263
+ * Step writes run inside the body's fiber, where a failed statement is a defect
264
+ * and the timer resumes. A wait's `where` runs outside any lock, and the fenced
265
+ * conditional settle makes a racing timeout or second run settle once. Holding the
266
+ * generation lock, a suspend finds any event committed after a wait's scan, so its
267
+ * wake survives.
268
+ *
269
+ * Compensation: `Workflow.withCompensation` and `Workflow.addFinalizer` register
270
+ * on the run's instance scope. Only a run that records a result closes it, and a
271
+ * replay registers them again, so they run once per execution.
272
+ */
273
+ export const activationEngine = (options) => Effect.gen(function* () {
274
+ const { registration, ref, routingKey, cache, scope } = options;
275
+ const sql = yield* SqlClient.SqlClient;
276
+ const crypto = yield* Crypto.Crypto;
277
+ const { retryWindowMs } = yield* OutboxRuntime;
278
+ const services = Context.pick(SqlClient.SqlClient, Crypto.Crypto)(yield* Effect.context());
279
+ const actor = { key: routingKey, ref };
280
+ const ownerRow = actorRow({ sql, actor });
281
+ const instanceWorkflows = new Map();
282
+ const instanceWorkflow = (tag) => {
283
+ let found = instanceWorkflows.get(tag);
284
+ if (found === undefined) {
285
+ found = EffectWorkflow.make(tag, { payload: {}, idempotencyKey: () => tag });
286
+ instanceWorkflows.set(tag, found);
287
+ }
288
+ return found;
289
+ };
290
+ const live = new Map();
291
+ const fenced = (effect) => sql.withTransaction(Effect.gen(function* () {
292
+ if (!(yield* fence({ actor, cache, lock: "UPDATE" })))
293
+ return yield* Effect.die(new StaleRun());
294
+ return yield* effect;
295
+ }));
296
+ const now = databaseTime;
297
+ const startVerdicts = new Map();
298
+ /**
299
+ * The verdict on the manifest an execution started under, cached per hash
300
+ * for this activation. Unlike the startup check, it knows whether that
301
+ * manifest was accepted after this runner's own.
302
+ */
303
+ const startOf = (declared, workflow, hash) => Effect.gen(function* () {
304
+ const known = hash === declared.hash ? undefined : startVerdicts.get(hash);
305
+ if (hash === declared.hash || known !== undefined)
306
+ return known ?? startVerdict({ declared, hash, start: undefined, newer: false });
307
+ const [row] = yield* sql `
308
+ SELECT m.manifest::text AS manifest, m.accepted_at_ms > COALESCE((SELECT o.accepted_at_ms
309
+ FROM actor_workflow_manifests o WHERE o.actor_type = m.actor_type AND o.workflow = m.workflow
310
+ AND o.manifest_hash = ${declared.hash}), -1) AS newer
311
+ FROM actor_workflow_manifests m
312
+ WHERE m.actor_type = ${ref.actor} AND m.workflow = ${workflow.member.tag}
313
+ AND m.manifest_hash = ${hash}`;
314
+ const verdict = startVerdict({
315
+ declared,
316
+ hash,
317
+ start: row === undefined
318
+ ? undefined
319
+ : yield* decodeStoredManifest(row.manifest).pipe(Effect.orDie),
320
+ newer: row?.newer === true,
321
+ });
322
+ startVerdicts.set(hash, verdict);
323
+ return verdict;
324
+ });
325
+ /** An execution's recorded steps by slot and its version markers. */
326
+ const readSteps = (executionId) => Effect.gen(function* () {
327
+ const rows = yield* sql `
328
+ SELECT step, attempt, kind, exit, due_at_ms::text AS due_at_ms, wait_after::text AS wait_after,
329
+ scanned::text AS scanned, version, started_at_ms::text AS started_at_ms
330
+ FROM actor_workflow_step
331
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}
332
+ ORDER BY step, attempt`;
333
+ const steps = new Map();
334
+ const markers = new Map();
335
+ for (const row of rows)
336
+ if (row.kind === "version")
337
+ markers.set(row.step, row.version);
338
+ else
339
+ steps.set(slot(row.step, row.attempt), row);
340
+ return { steps, markers };
341
+ });
342
+ /**
343
+ * Why this runner cannot replay an execution, empty when it can, and the
344
+ * steps whose result schemas differ from its start manifest's. Every
345
+ * recorded step, settled or pending, has to be registered as the same kind.
346
+ */
347
+ const compatibility = (workflow, execution, recorded) => Effect.gen(function* () {
348
+ const declared = yield* manifestOf(ref.actor, workflow.member);
349
+ const start = yield* startOf(declared, workflow, execution.manifest_hash);
350
+ const { versions } = workflow.member;
351
+ const problems = [
352
+ ...start.problems,
353
+ ...[...new Set([...Object.keys(versions), ...recorded.markers.keys()])].flatMap((name) => markerProblem({ versions, name, recorded: recorded.markers.get(name) })),
354
+ ...[...recorded.steps.values()].flatMap((row) => recordedStepProblem({
355
+ declared,
356
+ step: row.step,
357
+ kind: row.kind,
358
+ settled: row.exit !== null,
359
+ changed: start.changed,
360
+ })),
361
+ ];
362
+ return { problems, changed: start.changed, declared };
363
+ });
364
+ /**
365
+ * Moves an execution started under an older manifest whose steps changed
366
+ * onto this runner's manifest, recording that manifest if it is new.
367
+ */
368
+ const adoptManifest = (declared, workflow, execution, executionId, changed) => execution.manifest_hash === declared.hash || changed.length === 0
369
+ ? Effect.void
370
+ : fenced(sql `
371
+ WITH m AS (INSERT INTO actor_workflow_manifests
372
+ (actor_type, workflow, manifest_hash, manifest, accepted_at_ms)
373
+ VALUES (${ref.actor}, ${workflow.member.tag}, ${declared.hash}, ${toJson(declared.manifest)}::jsonb, 0)
374
+ ON CONFLICT DO NOTHING)
375
+ UPDATE actor_workflow_executions SET manifest_hash = ${declared.hash}
376
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}
377
+ AND manifest_hash = ${execution.manifest_hash}`).pipe(Effect.asVoid);
378
+ /** Records an execution's result, then drops its steps and its timer. */
379
+ const finish = (executionId, result) => fenced(Effect.gen(function* () {
380
+ const at = yield* now;
381
+ const done = yield* sql `
382
+ UPDATE actor_workflow_executions SET status = 'finished', result = ${encodeResult(result)},
383
+ finished_at_ms = ${at}
384
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId} AND status <> 'finished'
385
+ RETURNING 1`;
386
+ if (done.length === 0)
387
+ return;
388
+ yield* sql `DELETE FROM actor_workflow_step
389
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}`;
390
+ yield* deleteTimer(sql, routingKey, ref, executionId);
391
+ })).pipe(Effect.as("finished"));
392
+ /**
393
+ * The step primitives one run of an execution records through: each step
394
+ * replays its recorded exit, or records a new one in a fenced write.
395
+ */
396
+ const executionSteps = ({ executionId, workflow, steps, pass, interrupting, eventCursor, onBehalfOf, }) => {
397
+ const registered = (step) => step.workflow === workflow.member.tag && workflow.steps.get(step.name)?.kind === step.kind
398
+ ? Effect.void
399
+ : Effect.die(new Error(`Unregistered workflow step ${step.name}`));
400
+ const recordedOf = (step, attempt = 1) => {
401
+ const row = steps.get(slot(step.name, attempt));
402
+ if (row !== undefined && row.kind !== step.kind)
403
+ return Effect.die(new Error(`Step ${step.name} was recorded as a ${row.kind}`));
404
+ return Effect.succeed(row);
405
+ };
406
+ const insertStep = (step, fields, at, attempt = 1) => sql `INSERT INTO actor_workflow_step ${sql.insert({
407
+ routing_key: routingKey,
408
+ execution_id: executionId,
409
+ tenant_id: ref.tenant,
410
+ actor_type: ref.actor,
411
+ actor_id: ref.id,
412
+ step: step.name,
413
+ attempt,
414
+ kind: step.kind,
415
+ started_at_ms: at,
416
+ ...fields,
417
+ })}`;
418
+ const settle = (step, exit, at, extra) => sql `
419
+ UPDATE actor_workflow_step SET exit = ${encodeRecorded(exit)}, settled_at_ms = ${at},
420
+ matched = ${extra?.matched ?? null}
421
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId} AND step = ${step.name}
422
+ AND attempt = ${extra?.attempt ?? 1} AND exit IS NULL
423
+ RETURNING exit`;
424
+ const readExit = (step, attempt = 1) => sql `
425
+ SELECT exit FROM actor_workflow_step WHERE routing_key = ${routingKey}
426
+ AND execution_id = ${executionId} AND step = ${step.name} AND attempt = ${attempt}`.pipe(Effect.map((found) => found[0]?.exit ?? null));
427
+ const remember = (step, row, attempt = 1) => steps.set(slot(step.name, attempt), {
428
+ step: step.name,
429
+ attempt,
430
+ kind: step.kind,
431
+ exit: null,
432
+ due_at_ms: null,
433
+ wait_after: null,
434
+ scanned: null,
435
+ version: null,
436
+ started_at_ms: "0",
437
+ ...steps.get(slot(step.name, attempt)),
438
+ ...row,
439
+ });
440
+ const shift = (delta) => Effect.sync(() => {
441
+ pass.working += delta;
442
+ if (pass.working === 0)
443
+ pass.idle.openUnsafe();
444
+ else
445
+ pass.idle.closeUnsafe();
446
+ });
447
+ const working = (effect) => Effect.acquireUseRelease(shift(1), () => effect, () => shift(-1));
448
+ /**
449
+ * Waits until no other step of the pass works. A step that just ended gets
450
+ * one scheduling turn to start its branch's next step before the pass
451
+ * counts as quiet.
452
+ */
453
+ const quiet = Effect.gen(function* () {
454
+ for (;;) {
455
+ yield* pass.idle.await;
456
+ yield* Effect.yieldNow;
457
+ if (pass.working === 0)
458
+ return;
459
+ }
460
+ });
461
+ const suspend = Effect.acquireUseRelease(shift(-1), () => quiet, () => shift(1)).pipe(Effect.andThen(Effect.die(new Suspend())));
462
+ const guarded = (effect) => effect.pipe(Effect.orDie, Effect.provideContext(services));
463
+ return {
464
+ activity: (step, run) => Effect.gen(function* () {
465
+ yield* registered(step);
466
+ const attempt = yield* Activity.CurrentAttempt;
467
+ let row = yield* recordedOf(step, attempt);
468
+ if (row?.exit !== null && row?.exit !== undefined)
469
+ return yield* decodeRecorded(row.exit);
470
+ if (interrupting)
471
+ return yield* Effect.interrupt;
472
+ if (row === undefined) {
473
+ const at = yield* now;
474
+ yield* fenced(Effect.gen(function* () {
475
+ yield* insertStep(step, {}, at, attempt);
476
+ yield* armTimer(routingKey, ref, executionId, at + RECOVERY_MS, onBehalfOf);
477
+ }));
478
+ remember(step, { started_at_ms: String(at) }, attempt);
479
+ row = steps.get(slot(step.name, attempt));
480
+ }
481
+ const issuedAt = Number(row.started_at_ms);
482
+ const expiresAt = issuedAt + retryWindowMs;
483
+ let ordinal = 0;
484
+ const nextCommandId = Effect.gen(function* () {
485
+ ordinal += 1;
486
+ if ((yield* now) + options.deliveryMs >= expiresAt)
487
+ return yield* Effect.die(ActivityOutcomeUnknown.make({ executionId, step: step.name }));
488
+ const digest = yield* crypto
489
+ .digest("SHA-256", new TextEncoder().encode(callIdentity(executionId, step.name, row.attempt, ordinal)))
490
+ .pipe(Effect.orDie);
491
+ return `v1.${issuedAt}.${expiresAt}.${derivedUuid(digest)}`;
492
+ }).pipe(Effect.catchIf(SqlError.isSqlError, Effect.die), Effect.provideContext(services));
493
+ const exit = yield* run.pipe(Effect.provideService(CurrentCallPhase, CallPhase.Activity({ nextCommandId })));
494
+ const at = yield* now;
495
+ const settled = yield* fenced(settle(step, exit, at, { attempt }));
496
+ const recorded = settled[0]?.exit ?? (yield* readExit(step, attempt));
497
+ if (recorded === null)
498
+ return yield* Effect.die(new Error("Activity exit missing"));
499
+ remember(step, { exit: recorded }, attempt);
500
+ return yield* decodeRecorded(recorded);
501
+ }).pipe(working, guarded),
502
+ sleep: (step, millis) => Effect.gen(function* () {
503
+ yield* registered(step);
504
+ const row = yield* recordedOf(step);
505
+ if (row?.exit !== null && row?.exit !== undefined)
506
+ return;
507
+ if (interrupting)
508
+ return yield* Effect.interrupt;
509
+ const at = yield* now;
510
+ let dueAt;
511
+ if (row === undefined) {
512
+ dueAt = at + millis;
513
+ yield* fenced(insertStep(step, { due_at_ms: dueAt }, at));
514
+ remember(step, { due_at_ms: String(dueAt), started_at_ms: String(at) });
515
+ }
516
+ else
517
+ dueAt = Number(row.due_at_ms);
518
+ if (at < dueAt) {
519
+ pass.parked.add(step.name);
520
+ return yield* suspend;
521
+ }
522
+ yield* fenced(settle(step, RecordedExit.cases.Success.make({ value: null }), at));
523
+ remember(step, {
524
+ exit: encodeRecorded(RecordedExit.cases.Success.make({ value: null })),
525
+ });
526
+ }).pipe(working, guarded),
527
+ wait: (step, event, matches, timeoutMs) => Effect.gen(function* () {
528
+ yield* registered(step);
529
+ let row = yield* recordedOf(step);
530
+ const settledValue = (exit) => decodeRecorded(exit).pipe(Effect.flatMap((recorded) => Schema.decodeUnknownEffect(Schema.NullOr(Schema.String))(RecordedExit.guards.Success(recorded) ? recorded.value : null).pipe(Effect.orDie)), Effect.map(Option.fromNullOr));
531
+ if (row?.exit !== null && row?.exit !== undefined)
532
+ return yield* settledValue(row.exit);
533
+ if (interrupting)
534
+ return yield* Effect.interrupt;
535
+ if (row === undefined) {
536
+ const at = yield* now;
537
+ const dueAt = timeoutMs === undefined ? null : at + timeoutMs;
538
+ const after = eventCursor.value;
539
+ yield* fenced(insertStep(step, { wait_event: event, wait_after: after, scanned: after, due_at_ms: dueAt }, at));
540
+ remember(step, {
541
+ wait_after: String(after),
542
+ scanned: String(after),
543
+ due_at_ms: dueAt === null ? null : String(dueAt),
544
+ started_at_ms: String(at),
545
+ });
546
+ row = steps.get(slot(step.name, 1));
547
+ }
548
+ let scanned = BigInt(row.scanned);
549
+ for (;;) {
550
+ const page = yield* sql `
551
+ SELECT sequence::text AS sequence, value, payload_version FROM actor_events
552
+ WHERE ${ownerRow} AND event = ${event} AND sequence > ${scanned}
553
+ ORDER BY sequence LIMIT 256`;
554
+ for (const found of page) {
555
+ const matched = yield* matches(decompress(found.value), found.payload_version);
556
+ if (Option.isNone(matched))
557
+ continue;
558
+ const value = matched.value;
559
+ const at = yield* now;
560
+ const sequence = BigInt(found.sequence);
561
+ const exit = RecordedExit.cases.Success.make({ value });
562
+ const settled = yield* fenced(Effect.gen(function* () {
563
+ const done = yield* settle(step, exit, at, { matched: sequence });
564
+ if (done.length > 0)
565
+ yield* sql `UPDATE actor_workflow_executions SET event_cursor = GREATEST(event_cursor, ${sequence})
566
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}`;
567
+ return done;
568
+ }));
569
+ if (settled.length > 0 && sequence > eventCursor.value)
570
+ eventCursor.value = sequence;
571
+ const recorded = settled[0]?.exit ?? (yield* readExit(step));
572
+ remember(step, { exit: recorded });
573
+ return yield* settledValue(recorded);
574
+ }
575
+ if (page.length < 256) {
576
+ if (page.length > 0)
577
+ scanned = BigInt(page[page.length - 1].sequence);
578
+ break;
579
+ }
580
+ scanned = BigInt(page[page.length - 1].sequence);
581
+ }
582
+ const at = yield* now;
583
+ if (row.due_at_ms !== null && at >= Number(row.due_at_ms)) {
584
+ const settled = yield* fenced(settle(step, RecordedExit.cases.Success.make({ value: null }), at));
585
+ const recorded = settled[0]?.exit ?? (yield* readExit(step));
586
+ remember(step, { exit: recorded });
587
+ return yield* settledValue(recorded);
588
+ }
589
+ if (scanned > BigInt(row.scanned)) {
590
+ yield* fenced(sql `UPDATE actor_workflow_step SET scanned = ${scanned}
591
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}
592
+ AND step = ${step.name} AND attempt = 1 AND exit IS NULL AND scanned < ${scanned}`);
593
+ remember(step, { scanned: String(scanned) });
594
+ }
595
+ pass.parked.add(step.name);
596
+ return yield* suspend;
597
+ }).pipe(working, guarded),
598
+ race: (step, run) => guarded(Effect.gen(function* () {
599
+ yield* registered(step);
600
+ const row = yield* recordedOf(step);
601
+ if (row?.exit !== null && row?.exit !== undefined)
602
+ return yield* decodeRecorded(row.exit);
603
+ if (interrupting)
604
+ return yield* Effect.interrupt;
605
+ const exit = yield* run;
606
+ const at = yield* now;
607
+ yield* fenced(insertStep(step, { exit: encodeRecorded(exit), settled_at_ms: at }, at).pipe(Effect.catchIf(SqlError.isSqlError, Effect.die)));
608
+ remember(step, { exit: encodeRecorded(exit) });
609
+ return exit;
610
+ })),
611
+ };
612
+ };
613
+ /**
614
+ * Marks a run that suspended as suspended, and re-arms its timer: at once
615
+ * when an event it waits on arrived after its scan, at its earliest due
616
+ * step otherwise, or not at all when nothing is due.
617
+ */
618
+ const park = (executionId, onBehalfOf) => Effect.gen(function* () {
619
+ yield* (yield* TurnHooks).at("beforeWorkflowSuspend", Request.make({
620
+ ref,
621
+ caller: System.make({ source: "workflow", ref }),
622
+ command: RESUME,
623
+ commandId: "",
624
+ payload: executionId,
625
+ }));
626
+ yield* fenced(Effect.gen(function* () {
627
+ const [due] = yield* sql `
628
+ SELECT min(due_at_ms)::text AS due FROM actor_workflow_step
629
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}
630
+ AND exit IS NULL AND due_at_ms IS NOT NULL`;
631
+ yield* sql `UPDATE actor_workflow_executions SET status = 'suspended'
632
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId} AND status = 'running'`;
633
+ const [unseen] = yield* sql `
634
+ SELECT EXISTS (
635
+ SELECT 1 FROM actor_workflow_step s
636
+ JOIN actor_events e ON e.routing_key = s.routing_key AND e.tenant_id = s.tenant_id
637
+ AND e.actor_type = s.actor_type AND e.actor_id = s.actor_id
638
+ AND e.event = s.wait_event AND e.sequence > s.scanned
639
+ WHERE s.routing_key = ${routingKey} AND s.execution_id = ${executionId}
640
+ AND s.kind = 'wait' AND s.exit IS NULL
641
+ ) AS found`;
642
+ if (unseen?.found === true)
643
+ yield* armTimer(routingKey, ref, executionId, undefined, onBehalfOf);
644
+ else if (due?.due === null || due === undefined)
645
+ yield* deleteTimer(sql, routingKey, ref, executionId);
646
+ else
647
+ yield* armTimer(routingKey, ref, executionId, Number(due.due), onBehalfOf);
648
+ }));
649
+ });
650
+ /**
651
+ * Runs one pass of an execution: replays it against this runner's workflow,
652
+ * then records its result, parks it, or leaves it for a compatible runner.
653
+ */
654
+ const runOnce = (executionId, pass) => Effect.gen(function* () {
655
+ const [execution] = yield* sql `
656
+ SELECT workflow, workflow_key, payload, caller, event_cursor::text AS event_cursor, status, interrupt,
657
+ manifest_hash
658
+ FROM actor_workflow_executions
659
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}`;
660
+ if (execution === undefined || execution.status === "finished")
661
+ return "finished";
662
+ const caller = yield* decodeCaller(execution.caller).pipe(Effect.orDie);
663
+ const onBehalfOf = principal(caller);
664
+ const interrupting = execution.interrupt;
665
+ const workflow = registration.workflows.get(execution.workflow);
666
+ const recorded = yield* readSteps(executionId);
667
+ const verdict = workflow === undefined ? undefined : yield* compatibility(workflow, execution, recorded);
668
+ if (workflow === undefined || verdict === undefined || verdict.problems.length > 0) {
669
+ yield* Effect.logWarning("Workflow execution incompatible with this runner; suspended").pipe(Effect.annotateLogs({
670
+ executionId,
671
+ problems: verdict?.problems ?? ["workflow not registered"],
672
+ }));
673
+ yield* fenced(armTimer(routingKey, ref, executionId, (yield* now) + RECOVERY_MS, onBehalfOf));
674
+ return "abandoned";
675
+ }
676
+ yield* adoptManifest(verdict.declared, workflow, execution, executionId, verdict.changed);
677
+ if (execution.status === "suspended")
678
+ yield* fenced(sql `UPDATE actor_workflow_executions SET status = 'running'
679
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}
680
+ AND status = 'suspended'`);
681
+ const engine = executionSteps({
682
+ executionId,
683
+ workflow,
684
+ steps: recorded.steps,
685
+ pass,
686
+ interrupting,
687
+ eventCursor: { value: BigInt(execution.event_cursor) },
688
+ onBehalfOf,
689
+ });
690
+ const instance = WorkflowEngine.WorkflowInstance.initial(instanceWorkflow(workflow.member.tag), executionId);
691
+ const exit = yield* workflow
692
+ .run(decompress(execution.payload), {
693
+ id: ref.id,
694
+ ref,
695
+ principal: onBehalfOf,
696
+ executionId,
697
+ key: execution.workflow_key,
698
+ version: (name) => Effect.succeed(recorded.markers.get(name) ?? 0),
699
+ })
700
+ .pipe(Effect.provideService(CurrentWorkflow, engine), Effect.provideService(CurrentCallPhase, CallPhase.Body()), Effect.provideService(WorkflowEngine.WorkflowInstance, instance), Effect.scoped);
701
+ const interrupted = Exit.isFailure(exit) && Cause.hasInterruptsOnly(exit.cause);
702
+ if (Exit.isFailure(exit)) {
703
+ if (stale(exit.cause) || (interrupted && !interrupting))
704
+ return "abandoned";
705
+ if (suspended(exit.cause)) {
706
+ yield* park(executionId, onBehalfOf);
707
+ return "suspended";
708
+ }
709
+ }
710
+ if (interrupted) {
711
+ yield* Scope.close(instance.scope, Exit.interrupt());
712
+ return yield* finish(executionId, StoredResult.cases.Interrupt.make({}));
713
+ }
714
+ yield* Scope.close(instance.scope, exit);
715
+ return yield* finish(executionId, yield* workflow.encodeExit(exit));
716
+ }).pipe(Effect.catchCause((cause) => stale(cause) || Cause.hasInterruptsOnly(cause)
717
+ ? Effect.succeed("abandoned")
718
+ : Effect.logWarning("Workflow run failed; its timer resumes it", cause).pipe(Effect.as("abandoned"))), Effect.annotateLogs({ actor: ref.actor, tenant: ref.tenant, id: ref.id, executionId }));
719
+ /**
720
+ * Replays the run pass by pass until a pass ends with nothing asking for
721
+ * another. The decision to stop and the run's removal happen in one step, so
722
+ * a kick either reaches this run or starts a new one.
723
+ */
724
+ const loop = (executionId, run) => Effect.gen(function* () {
725
+ for (;;) {
726
+ const pass = {
727
+ body: undefined,
728
+ parked: new Set(),
729
+ working: 0,
730
+ idle: Latch.makeUnsafe(true),
731
+ };
732
+ run.pass = pass;
733
+ const body = yield* Effect.forkChild(runOnce(executionId, pass));
734
+ pass.body = body;
735
+ const outcome = yield* Fiber.join(body).pipe(Effect.exit);
736
+ const again = yield* Effect.sync(() => {
737
+ const left = Exit.isSuccess(outcome) && outcome.value === "abandoned";
738
+ const replay = run.next === "preempt" || (run.next === "wake" && !left);
739
+ run.pass = undefined;
740
+ run.next = "end";
741
+ if (!replay)
742
+ live.delete(executionId);
743
+ return replay;
744
+ });
745
+ if (!again)
746
+ return;
747
+ }
748
+ }).pipe(Effect.ensuring(Effect.sync(() => {
749
+ if (live.get(executionId) === run)
750
+ live.delete(executionId);
751
+ })));
752
+ const settleable = (executionId, parked) => parked.size === 0
753
+ ? Effect.succeed(false)
754
+ : Effect.gen(function* () {
755
+ const at = yield* now;
756
+ const [found] = yield* sql `
757
+ SELECT EXISTS (
758
+ SELECT 1 FROM actor_workflow_step s
759
+ WHERE s.routing_key = ${routingKey} AND s.execution_id = ${executionId}
760
+ AND s.step IN ${sql.in([...parked])} AND s.exit IS NULL
761
+ AND (s.due_at_ms <= ${at}
762
+ OR (s.kind = 'wait' AND EXISTS (
763
+ SELECT 1 FROM actor_events e
764
+ WHERE e.routing_key = s.routing_key AND e.tenant_id = s.tenant_id
765
+ AND e.actor_type = s.actor_type AND e.actor_id = s.actor_id
766
+ AND e.event = s.wait_event AND e.sequence > s.scanned)))
767
+ ) AS found`;
768
+ return found?.found === true;
769
+ }).pipe(Effect.orElseSucceed(() => false));
770
+ /**
771
+ * Runs or replays an execution after a committed workflow command. A live
772
+ * run replays once more after it suspends; an interrupt stops it first.
773
+ * A pass with working steps gets its recovery timer back, since the relay
774
+ * consumed it; that write holds the generation row like `finish`, so it
775
+ * never re-arms an execution a replay already finished.
776
+ */
777
+ const kick = (executionId, interrupt) => Effect.gen(function* () {
778
+ const current = live.get(executionId);
779
+ if (current === undefined) {
780
+ const run = { pass: undefined, next: "end" };
781
+ live.set(executionId, run);
782
+ yield* loop(executionId, run).pipe(Effect.forkIn(scope));
783
+ return;
784
+ }
785
+ const pass = current.pass;
786
+ if (current.next === "end")
787
+ current.next = "wake";
788
+ if (pass?.body === undefined)
789
+ return;
790
+ if (interrupt || (yield* settleable(executionId, pass.parked))) {
791
+ if (current.pass !== pass)
792
+ return;
793
+ current.next = "preempt";
794
+ yield* Fiber.interrupt(pass.body).pipe(Effect.forkIn(scope));
795
+ }
796
+ if (pass.working > 0)
797
+ yield* fenced(Effect.gen(function* () {
798
+ const [row] = yield* sql `SELECT caller FROM actor_workflow_executions
799
+ WHERE routing_key = ${routingKey} AND execution_id = ${executionId}
800
+ AND status <> 'finished'`;
801
+ if (row === undefined)
802
+ return;
803
+ const caller = yield* decodeCaller(row.caller).pipe(Effect.orDie);
804
+ yield* armTimer(routingKey, ref, executionId, (yield* now) + RECOVERY_MS, principal(caller));
805
+ })).pipe(Effect.ignoreCause);
806
+ }).pipe(Effect.provideContext(services));
807
+ return { kick, live: () => live.size };
808
+ });
809
+ /**
810
+ * Re-arms the resume timer of every execution with a pending wait for one of
811
+ * `tags`, inside the emitting turn. The turn holds the owner's generation
812
+ * lock, which a wait's registration also takes, so no event is missed.
813
+ */
814
+ export const notifyWaits = Effect.fnUntraced(function* (routingKey, ref, tags) {
815
+ const sql = yield* SqlClient.SqlClient;
816
+ const waiting = yield* sql `
817
+ SELECT DISTINCT s.execution_id, x.caller FROM actor_workflow_step s
818
+ JOIN actor_workflow_executions x ON x.routing_key = s.routing_key AND x.execution_id = s.execution_id
819
+ WHERE s.routing_key = ${routingKey} AND s.tenant_id = ${ref.tenant} AND s.actor_type = ${ref.actor}
820
+ AND s.actor_id = ${ref.id} AND s.kind = 'wait' AND s.exit IS NULL AND s.wait_event IN ${sql.in(tags)}`;
821
+ for (const row of waiting) {
822
+ const caller = yield* decodeCaller(row.caller).pipe(Effect.orDie);
823
+ yield* armTimer(routingKey, ref, row.execution_id, undefined, principal(caller));
824
+ }
825
+ return waiting.length > 0;
826
+ });