@swirls/looms 0.0.2 → 0.2.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 (375) hide show
  1. package/CHANGELOG.md +24 -2
  2. package/dist/actor/cell.d.ts +9 -4
  3. package/dist/actor/cell.js +7 -11
  4. package/dist/actor/host.d.ts +7 -3
  5. package/dist/actor/host.js +57 -33
  6. package/dist/actor/index.d.ts +1 -1
  7. package/dist/actor/index.js +1 -1
  8. package/dist/actor/routing.d.ts +12 -1
  9. package/dist/actor/routing.js +57 -51
  10. package/dist/agent/agent-session.d.ts +5 -0
  11. package/dist/agent/agent-session.js +270 -0
  12. package/dist/agent/debugger/agent-chat.d.ts +2 -0
  13. package/dist/agent/debugger/agent-chat.js +176 -0
  14. package/dist/agent/debugger/index.d.ts +5 -0
  15. package/dist/agent/debugger/index.js +19 -0
  16. package/dist/agent/debugger/summarize.d.ts +2 -0
  17. package/dist/agent/debugger/summarize.js +51 -0
  18. package/dist/agent/debugger/token-usage.d.ts +3 -0
  19. package/dist/agent/debugger/token-usage.js +11 -0
  20. package/dist/agent/definitions-store.d.ts +2 -3
  21. package/dist/agent/definitions-store.js +2 -4
  22. package/dist/agent/definitions.d.ts +47 -29
  23. package/dist/agent/definitions.js +39 -12
  24. package/dist/agent/effects.d.ts +359 -2
  25. package/dist/agent/effects.js +60 -34
  26. package/dist/agent/events.d.ts +175 -19
  27. package/dist/agent/events.js +45 -10
  28. package/dist/agent/index.d.ts +1 -0
  29. package/dist/agent/index.js +1 -0
  30. package/dist/agent/llm.d.ts +11 -2
  31. package/dist/agent/llm.js +13 -3
  32. package/dist/agent/module.d.ts +812 -78
  33. package/dist/agent/module.js +16 -4
  34. package/dist/agent/scope.d.ts +174 -18
  35. package/dist/agent/signals.d.ts +26 -1
  36. package/dist/agent/signals.js +79 -0
  37. package/dist/agent/threads.d.ts +3 -33
  38. package/dist/agent/threads.js +20 -25
  39. package/dist/agent/tool-schema.d.ts +1 -17
  40. package/dist/agent/tool-schema.js +3 -43
  41. package/dist/agent/types.d.ts +49 -4
  42. package/dist/agent/types.js +5 -5
  43. package/dist/ai-vercel/index.d.ts +1 -0
  44. package/dist/ai-vercel/index.js +1 -0
  45. package/dist/ai-vercel/messages.js +22 -7
  46. package/dist/ai-vercel/vercel-evaluator.d.ts +36 -0
  47. package/dist/ai-vercel/vercel-evaluator.js +73 -0
  48. package/dist/ai-vercel/vercel-llm.js +64 -44
  49. package/dist/approval/debugger/approvals-view.d.ts +3 -0
  50. package/dist/approval/debugger/approvals-view.js +16 -0
  51. package/dist/approval/debugger/index.d.ts +4 -0
  52. package/dist/approval/debugger/index.js +11 -0
  53. package/dist/approval/debugger/summarize.d.ts +2 -0
  54. package/dist/approval/debugger/summarize.js +17 -0
  55. package/dist/approval/effects.d.ts +89 -0
  56. package/dist/approval/module.d.ts +179 -29
  57. package/dist/approval/projections.d.ts +0 -14
  58. package/dist/approval/projections.js +20 -3
  59. package/dist/approval/signals.d.ts +2 -0
  60. package/dist/approval/signals.js +18 -2
  61. package/dist/cli/cli.js +2 -0
  62. package/dist/cli/commands.js +12 -16
  63. package/dist/client/client.d.ts +1213 -18
  64. package/dist/client/client.js +120 -120
  65. package/dist/client/index.d.ts +1 -1
  66. package/dist/client/index.js +1 -1
  67. package/dist/client/sse.d.ts +13 -0
  68. package/dist/client/sse.js +38 -44
  69. package/dist/cloudflare/alarm-scheduler.d.ts +12 -2
  70. package/dist/cloudflare/alarm-scheduler.js +34 -7
  71. package/dist/cloudflare/durable-object.d.ts +10 -2
  72. package/dist/cloudflare/durable-object.js +59 -28
  73. package/dist/cloudflare/event-store.d.ts +7 -2
  74. package/dist/cloudflare/event-store.js +8 -7
  75. package/dist/cloudflare/index.d.ts +2 -2
  76. package/dist/cloudflare/index.js +2 -2
  77. package/dist/cloudflare/router.d.ts +1 -1
  78. package/dist/cloudflare/router.js +15 -16
  79. package/dist/core/catalog.d.ts +3 -3
  80. package/dist/core/catalog.js +2 -5
  81. package/dist/core/coalesce.js +5 -3
  82. package/dist/core/compose.d.ts +2 -1
  83. package/dist/core/compose.js +19 -2
  84. package/dist/core/debugger-host.d.ts +16 -0
  85. package/dist/core/debugger-host.js +1 -0
  86. package/dist/core/definition-store.d.ts +11 -0
  87. package/dist/core/definition-store.js +6 -0
  88. package/dist/core/effects.d.ts +127 -15
  89. package/dist/core/effects.js +89 -17
  90. package/dist/core/envelope.d.ts +27 -7
  91. package/dist/core/envelope.js +20 -6
  92. package/dist/core/event-codec.d.ts +4 -2
  93. package/dist/core/event-codec.js +10 -5
  94. package/dist/core/event-index.js +1 -3
  95. package/dist/core/fold.d.ts +3 -0
  96. package/dist/core/fold.js +171 -24
  97. package/dist/core/ids.d.ts +5 -0
  98. package/dist/core/ids.js +35 -2
  99. package/dist/core/index.d.ts +7 -1
  100. package/dist/core/index.js +6 -1
  101. package/dist/core/kind.d.ts +22 -0
  102. package/dist/core/kind.js +17 -0
  103. package/dist/core/limits.d.ts +34 -0
  104. package/dist/core/limits.js +46 -0
  105. package/dist/core/match.d.ts +1 -0
  106. package/dist/core/match.js +10 -1
  107. package/dist/core/module-scope.d.ts +22 -20
  108. package/dist/core/module-scope.js +38 -28
  109. package/dist/core/module.d.ts +18 -5
  110. package/dist/core/module.js +4 -0
  111. package/dist/core/projection.d.ts +13 -13
  112. package/dist/core/projection.js +9 -5
  113. package/dist/core/protocol.d.ts +68 -11
  114. package/dist/core/protocol.js +82 -11
  115. package/dist/core/published.d.ts +43 -0
  116. package/dist/core/published.js +44 -0
  117. package/dist/core/replay.d.ts +312 -3
  118. package/dist/core/replay.js +11 -1
  119. package/dist/core/schema.d.ts +11 -20
  120. package/dist/core/schema.js +63 -80
  121. package/dist/core/serialize.js +2 -4
  122. package/dist/core/snapshot-store.d.ts +6 -1
  123. package/dist/core/snapshot-store.js +15 -2
  124. package/dist/core/snapshots.d.ts +5 -1
  125. package/dist/core/snapshots.js +10 -15
  126. package/dist/core/sqlite-store.js +95 -11
  127. package/dist/core/state.d.ts +142 -4
  128. package/dist/core/state.js +78 -0
  129. package/dist/core/store.d.ts +38 -3
  130. package/dist/core/store.js +77 -22
  131. package/dist/core/thread.d.ts +10 -9
  132. package/dist/core/types.d.ts +5 -8
  133. package/dist/core/types.js +28 -24
  134. package/dist/core/validate-event.js +14 -4
  135. package/dist/core/worker-callback.d.ts +17 -0
  136. package/dist/core/worker-callback.js +1 -0
  137. package/dist/debugger/app/assets/index-B3Ah8WAE.css +2 -0
  138. package/dist/debugger/app/assets/index-Qb371t_O.js +22 -0
  139. package/dist/debugger/app/assets/rolldown-runtime-CbXtAM7H.js +1 -0
  140. package/dist/debugger/app/assets/routes-CjtEHgPQ.js +47 -0
  141. package/dist/debugger/app/index.html +14 -0
  142. package/dist/debugger/components/composer.d.ts +17 -0
  143. package/dist/debugger/components/composer.js +25 -0
  144. package/dist/debugger/components/debugger-split.d.ts +2 -1
  145. package/dist/debugger/components/debugger-split.js +2 -2
  146. package/dist/debugger/components/event-inspector.d.ts +2 -1
  147. package/dist/debugger/components/event-inspector.js +25 -16
  148. package/dist/debugger/components/event-stream.d.ts +2 -1
  149. package/dist/debugger/components/event-stream.js +14 -74
  150. package/dist/debugger/components/follow-list.d.ts +19 -0
  151. package/dist/debugger/components/follow-list.js +96 -0
  152. package/dist/debugger/components/json-tree.d.ts +11 -0
  153. package/dist/debugger/components/json-tree.js +120 -0
  154. package/dist/debugger/components/json-view.js +2 -2
  155. package/dist/debugger/components/run-tree.js +53 -20
  156. package/dist/debugger/components/status-dot.d.ts +4 -0
  157. package/dist/debugger/components/status-dot.js +6 -2
  158. package/dist/debugger/context.d.ts +14 -0
  159. package/dist/debugger/context.js +17 -0
  160. package/dist/debugger/contracts.d.ts +7 -4
  161. package/dist/debugger/events/builtin-families.d.ts +3 -0
  162. package/dist/debugger/events/builtin-families.js +9 -0
  163. package/dist/debugger/events/catalog.d.ts +3 -4
  164. package/dist/debugger/events/catalog.js +27 -17
  165. package/dist/debugger/events/protocol-summarize.d.ts +1 -2
  166. package/dist/debugger/events/protocol-summarize.js +42 -24
  167. package/dist/debugger/index.d.ts +20 -6
  168. package/dist/debugger/index.js +19 -5
  169. package/dist/debugger/lib/cn.d.ts +1 -0
  170. package/dist/debugger/lib/cn.js +3 -0
  171. package/dist/debugger/lib/event-meta.d.ts +2 -3
  172. package/dist/debugger/lib/event-meta.js +6 -12
  173. package/dist/debugger/lib/json.d.ts +25 -0
  174. package/dist/debugger/lib/json.js +87 -0
  175. package/dist/debugger/lib/payload.d.ts +7 -0
  176. package/dist/debugger/lib/payload.js +11 -0
  177. package/dist/debugger/lib/time.d.ts +3 -0
  178. package/dist/debugger/lib/time.js +24 -0
  179. package/dist/debugger/plugin.d.ts +36 -0
  180. package/dist/debugger/plugin.js +14 -0
  181. package/dist/debugger/server/index.d.ts +14 -0
  182. package/dist/debugger/server/index.js +114 -0
  183. package/dist/debugger/shell/debugger-shell.d.ts +15 -0
  184. package/dist/debugger/shell/debugger-shell.js +43 -0
  185. package/dist/debugger/shell/definition-key.d.ts +3 -0
  186. package/dist/debugger/shell/definition-key.js +4 -0
  187. package/dist/debugger/shell/events-pane.d.ts +12 -0
  188. package/dist/debugger/shell/events-pane.js +25 -0
  189. package/dist/debugger/shell/projections-panel.d.ts +4 -0
  190. package/dist/debugger/shell/projections-panel.js +59 -0
  191. package/dist/debugger/shell/run-controls.d.ts +4 -0
  192. package/dist/debugger/shell/run-controls.js +72 -0
  193. package/dist/debugger/shell/run-search.d.ts +6 -0
  194. package/dist/debugger/shell/run-search.js +102 -0
  195. package/dist/debugger/shell/run-type-menu.d.ts +6 -0
  196. package/dist/debugger/shell/run-type-menu.js +11 -0
  197. package/dist/debugger/shell/schema-form.d.ts +31 -0
  198. package/dist/debugger/shell/schema-form.js +117 -0
  199. package/dist/debugger/shell/start-form.d.ts +3 -0
  200. package/dist/debugger/shell/start-form.js +75 -0
  201. package/dist/debugger/shell/use-start-run.d.ts +14 -0
  202. package/dist/debugger/shell/use-start-run.js +32 -0
  203. package/dist/debugger/shell/workspace.d.ts +6 -0
  204. package/dist/debugger/shell/workspace.js +15 -0
  205. package/dist/debugger/styles.css +111 -27
  206. package/dist/debugger/ui/button.d.ts +24 -0
  207. package/dist/debugger/ui/button.js +24 -0
  208. package/dist/debugger/ui/command.d.ts +9 -0
  209. package/dist/debugger/ui/command.js +24 -0
  210. package/dist/debugger/ui/dropdown-menu.d.ts +13 -0
  211. package/dist/debugger/ui/dropdown-menu.js +37 -0
  212. package/dist/debugger/ui/panel.d.ts +14 -0
  213. package/dist/debugger/ui/panel.js +16 -0
  214. package/dist/debugger/ui/popover.d.ts +7 -0
  215. package/dist/debugger/ui/popover.js +17 -0
  216. package/dist/debugger/ui/resizable.d.ts +7 -0
  217. package/dist/debugger/ui/resizable.js +14 -0
  218. package/dist/debugger/ui/scroll-area.d.ts +2 -1
  219. package/dist/debugger/ui/scroll-area.js +5 -3
  220. package/dist/debugger/ui/select.d.ts +10 -0
  221. package/dist/debugger/ui/select.js +21 -0
  222. package/dist/debugger/ui/tabs.js +2 -2
  223. package/dist/debugger/ui/textarea.d.ts +3 -0
  224. package/dist/debugger/ui/textarea.js +7 -0
  225. package/dist/evaluator/definitions-store.d.ts +11 -0
  226. package/dist/evaluator/definitions-store.js +8 -0
  227. package/dist/evaluator/definitions.d.ts +18 -0
  228. package/dist/evaluator/definitions.js +4 -0
  229. package/dist/evaluator/effects.d.ts +226 -0
  230. package/dist/evaluator/effects.js +132 -0
  231. package/dist/evaluator/evaluator.d.ts +24 -0
  232. package/dist/evaluator/evaluator.js +67 -0
  233. package/dist/evaluator/events.d.ts +59 -0
  234. package/dist/evaluator/events.js +21 -0
  235. package/dist/evaluator/index.d.ts +11 -0
  236. package/dist/evaluator/index.js +11 -0
  237. package/dist/evaluator/module.d.ts +606 -0
  238. package/dist/evaluator/module.js +25 -0
  239. package/dist/evaluator/projections.d.ts +50 -0
  240. package/dist/evaluator/projections.js +20 -0
  241. package/dist/evaluator/scope.d.ts +59 -0
  242. package/dist/evaluator/scope.js +7 -0
  243. package/dist/evaluator/signals.d.ts +3 -0
  244. package/dist/evaluator/signals.js +17 -0
  245. package/dist/evaluator/threads.d.ts +62 -0
  246. package/dist/evaluator/threads.js +117 -0
  247. package/dist/evaluator/types.d.ts +125 -0
  248. package/dist/evaluator/types.js +51 -0
  249. package/dist/projectors/delivery.d.ts +83 -0
  250. package/dist/projectors/delivery.js +182 -0
  251. package/dist/projectors/index-model.d.ts +1 -1
  252. package/dist/projectors/index-model.js +4 -6
  253. package/dist/projectors/index.d.ts +2 -0
  254. package/dist/projectors/index.js +2 -0
  255. package/dist/projectors/memory.d.ts +1 -1
  256. package/dist/projectors/memory.js +10 -8
  257. package/dist/projectors/postgres.js +44 -58
  258. package/dist/projectors/projector.d.ts +17 -0
  259. package/dist/projectors/projector.js +26 -1
  260. package/dist/projectors/sqlite-delivery.d.ts +4 -0
  261. package/dist/projectors/sqlite-delivery.js +147 -0
  262. package/dist/projectors/sqlite.js +23 -23
  263. package/dist/projectors/with-projectors.d.ts +7 -2
  264. package/dist/projectors/with-projectors.js +27 -28
  265. package/dist/react/notify.js +11 -8
  266. package/dist/react/react.d.ts +2 -3
  267. package/dist/react/react.js +14 -30
  268. package/dist/react/sse.d.ts +1 -1
  269. package/dist/react/sse.js +1 -1
  270. package/dist/react/store.d.ts +3 -3
  271. package/dist/react/store.js +109 -119
  272. package/dist/runtime/cancellation.d.ts +16 -0
  273. package/dist/runtime/cancellation.js +129 -0
  274. package/dist/runtime/deadline-transition-planner.d.ts +31 -0
  275. package/dist/runtime/deadline-transition-planner.js +139 -0
  276. package/dist/runtime/dispatch-effect.d.ts +3 -2
  277. package/dist/runtime/dispatch-effect.js +7 -13
  278. package/dist/runtime/errors.d.ts +51 -0
  279. package/dist/runtime/errors.js +39 -0
  280. package/dist/runtime/{runtime-helpers.d.ts → helpers.d.ts} +24 -4
  281. package/dist/runtime/{runtime-helpers.js → helpers.js} +56 -19
  282. package/dist/runtime/index.d.ts +3 -3
  283. package/dist/runtime/index.js +3 -3
  284. package/dist/runtime/ingress.d.ts +15 -0
  285. package/dist/runtime/ingress.js +42 -0
  286. package/dist/runtime/local-effect-executor.d.ts +21 -0
  287. package/dist/runtime/local-effect-executor.js +137 -0
  288. package/dist/runtime/looms.d.ts +30 -4
  289. package/dist/runtime/looms.js +57 -37
  290. package/dist/runtime/observer.d.ts +45 -0
  291. package/dist/runtime/observer.js +11 -0
  292. package/dist/runtime/repository.d.ts +55 -0
  293. package/dist/runtime/repository.js +293 -0
  294. package/dist/runtime/retry-policy.d.ts +16 -0
  295. package/dist/runtime/retry-policy.js +29 -0
  296. package/dist/runtime/run-execution-context.d.ts +30 -0
  297. package/dist/runtime/run-execution-context.js +56 -0
  298. package/dist/runtime/run-start.d.ts +4 -0
  299. package/dist/runtime/run-start.js +44 -0
  300. package/dist/runtime/runtime.d.ts +6 -87
  301. package/dist/runtime/runtime.js +248 -470
  302. package/dist/runtime/server/auth.d.ts +41 -0
  303. package/dist/runtime/server/auth.js +45 -0
  304. package/dist/runtime/server/debugger-host.d.ts +11 -0
  305. package/dist/runtime/server/debugger-host.js +32 -0
  306. package/dist/runtime/server/fetch-handler.d.ts +18 -0
  307. package/dist/runtime/server/fetch-handler.js +62 -0
  308. package/dist/runtime/server/http.d.ts +38 -0
  309. package/dist/runtime/server/http.js +66 -0
  310. package/dist/runtime/server/route-table.d.ts +55 -0
  311. package/dist/runtime/server/route-table.js +74 -0
  312. package/dist/runtime/server/routes/definitions.d.ts +3 -0
  313. package/dist/runtime/server/routes/definitions.js +20 -0
  314. package/dist/runtime/server/routes/effects.d.ts +3 -0
  315. package/dist/runtime/server/routes/effects.js +59 -0
  316. package/dist/runtime/server/routes/operations.d.ts +3 -0
  317. package/dist/runtime/server/routes/operations.js +14 -0
  318. package/dist/runtime/server/routes/runs.d.ts +3 -0
  319. package/dist/runtime/server/routes/runs.js +199 -0
  320. package/dist/runtime/server.d.ts +4 -8
  321. package/dist/runtime/server.js +6 -211
  322. package/dist/runtime/sse.d.ts +2 -1
  323. package/dist/runtime/sse.js +24 -17
  324. package/dist/runtime/types.d.ts +117 -0
  325. package/dist/runtime/types.js +1 -0
  326. package/dist/runtime/wake-engine.d.ts +20 -0
  327. package/dist/runtime/wake-engine.js +311 -0
  328. package/dist/runtime/wake-scheduler.d.ts +3 -4
  329. package/dist/runtime/wake-scheduler.js +25 -31
  330. package/dist/runtime/worker-callbacks.d.ts +16 -0
  331. package/dist/runtime/worker-callbacks.js +167 -0
  332. package/dist/runtime/worker-effect-dispatch.d.ts +36 -0
  333. package/dist/runtime/worker-effect-dispatch.js +126 -0
  334. package/dist/s2/config.d.ts +1 -1
  335. package/dist/s2/config.js +1 -1
  336. package/dist/s2/lite.js +70 -82
  337. package/dist/s2/pagination.d.ts +15 -0
  338. package/dist/s2/pagination.js +36 -0
  339. package/dist/s2/projector.js +6 -5
  340. package/dist/s2/snapshot-store.js +188 -161
  341. package/dist/s2/store.d.ts +3 -21
  342. package/dist/s2/store.js +71 -165
  343. package/dist/testing/index.d.ts +15 -0
  344. package/dist/testing/index.js +53 -16
  345. package/dist/workflow/debugger/index.d.ts +4 -0
  346. package/dist/workflow/debugger/index.js +11 -0
  347. package/dist/workflow/debugger/nodes-view.d.ts +3 -0
  348. package/dist/workflow/debugger/nodes-view.js +13 -0
  349. package/dist/workflow/debugger/summarize.d.ts +2 -0
  350. package/dist/workflow/debugger/summarize.js +30 -0
  351. package/dist/workflow/definitions-store.d.ts +2 -3
  352. package/dist/workflow/definitions-store.js +2 -2
  353. package/dist/workflow/definitions.d.ts +78 -22
  354. package/dist/workflow/definitions.js +80 -14
  355. package/dist/workflow/effects.d.ts +453 -107
  356. package/dist/workflow/effects.js +214 -115
  357. package/dist/workflow/events.d.ts +149 -5
  358. package/dist/workflow/events.js +27 -5
  359. package/dist/workflow/graph.d.ts +56 -0
  360. package/dist/workflow/graph.js +207 -0
  361. package/dist/workflow/index.d.ts +1 -0
  362. package/dist/workflow/index.js +1 -0
  363. package/dist/workflow/module.d.ts +1047 -266
  364. package/dist/workflow/projections.d.ts +14 -12
  365. package/dist/workflow/projections.js +30 -8
  366. package/dist/workflow/scope.d.ts +146 -4
  367. package/dist/workflow/threads.d.ts +383 -155
  368. package/dist/workflow/threads.js +308 -110
  369. package/package.json +26 -2
  370. package/dist/debugger/events/domain-summarize.d.ts +0 -3
  371. package/dist/debugger/events/domain-summarize.js +0 -107
  372. package/dist/debugger/events/family.d.ts +0 -8
  373. package/dist/debugger/events/family.js +0 -44
  374. package/dist/runtime/events-api.d.ts +0 -4
  375. package/dist/runtime/events-api.js +0 -84
@@ -1,6 +1,6 @@
1
- import { Effect, Schedule } from 'effect';
1
+ import { Effect } from 'effect';
2
2
  import { asJson, isPrimitiveEffect, isWaitOnTimer, } from '@swirls/looms/core';
3
- import { threadStartedEvents } from './runtime-helpers.js';
3
+ import { threadStartedEvents } from './helpers.js';
4
4
  export function dispatchEffect(registry, services, definitions, effect, ctx) {
5
5
  const currentThreadId = ctx.threadId;
6
6
  const baseDispatch = (eff, effCtx) => {
@@ -11,6 +11,7 @@ export function dispatchEffect(registry, services, definitions, effect, ctx) {
11
11
  return threadStartedEvents(definitions, {
12
12
  kind: eff.kind,
13
13
  definitionName: eff.definitionName,
14
+ definitionVersion: eff.definitionVersion,
14
15
  input: eff.input,
15
16
  threadId: childThreadId,
16
17
  parentThreadId: currentThreadId,
@@ -83,17 +84,10 @@ export function dispatchEffect(registry, services, definitions, effect, ctx) {
83
84
  ]);
84
85
  }
85
86
  const input = 'input' in eff ? eff.input : {};
86
- let execution = handler
87
- .execute(input, effCtx)
88
- .pipe(Effect.provide(services));
89
- if (handler.retry && handler.retry.maxAttempts > 1) {
90
- const retryPolicy = handler.retry;
91
- const backoff = retryPolicy.backoffMs ?? 100;
92
- execution = execution.pipe(Effect.retry({
93
- times: retryPolicy.maxAttempts - 1,
94
- schedule: Schedule.spaced(backoff),
95
- }));
96
- }
87
+ const execution = Effect.gen(function* () {
88
+ const serviceContext = yield* services.contextEffect;
89
+ return yield* handler.execute(input, effCtx).pipe(Effect.provide(serviceContext));
90
+ });
97
91
  return execution.pipe(Effect.catch((err) => Effect.succeed([
98
92
  {
99
93
  type: 'runtime.effect.failed',
@@ -0,0 +1,51 @@
1
+ import type { JsonValue, RunStartIdentity as DurableRunStartIdentity } from '@swirls/looms/core';
2
+ export interface RunStartIdentity {
3
+ readonly kind: string;
4
+ readonly definitionName: string;
5
+ readonly definitionVersion: string;
6
+ readonly input: JsonValue;
7
+ readonly requestedThreadId: string | null;
8
+ readonly idempotencyKey: string | null;
9
+ }
10
+ declare const StartRunConflictError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
11
+ readonly _tag: "StartRunConflictError";
12
+ } & Readonly<A>;
13
+ export declare class StartRunConflictError extends StartRunConflictError_base<{
14
+ readonly runId: string;
15
+ readonly requested: RunStartIdentity;
16
+ readonly existing: DurableRunStartIdentity;
17
+ readonly mismatches: readonly (keyof RunStartIdentity)[];
18
+ readonly message: string;
19
+ }> {
20
+ constructor(runId: string, requested: RunStartIdentity, existing: DurableRunStartIdentity, mismatches: readonly (keyof RunStartIdentity)[]);
21
+ }
22
+ declare const DuplicateEffectDispatchError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
23
+ readonly _tag: "DuplicateEffectDispatchError";
24
+ } & Readonly<A>;
25
+ export declare class DuplicateEffectDispatchError extends DuplicateEffectDispatchError_base<{
26
+ readonly runId: string;
27
+ readonly effectId: string;
28
+ readonly threadId: string;
29
+ readonly message: string;
30
+ }> {
31
+ constructor(runId: string, effectId: string, threadId: string);
32
+ }
33
+ declare const MaxWakeIterationsError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
34
+ readonly _tag: "MaxWakeIterationsError";
35
+ } & Readonly<A>;
36
+ export declare class MaxWakeIterationsError extends MaxWakeIterationsError_base<{
37
+ readonly runId: string;
38
+ readonly maxIterations: number;
39
+ readonly message: string;
40
+ }> {
41
+ constructor(runId: string, maxIterations: number);
42
+ }
43
+ declare const RuntimeExecutionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
44
+ readonly _tag: "RuntimeExecutionError";
45
+ } & Readonly<A>;
46
+ export declare class RuntimeExecutionError extends RuntimeExecutionError_base<{
47
+ readonly message: string;
48
+ }> {
49
+ constructor(message: string);
50
+ }
51
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Data } from 'effect';
2
+ export class StartRunConflictError extends Data.TaggedError('StartRunConflictError') {
3
+ constructor(runId, requested, existing, mismatches) {
4
+ super({
5
+ runId,
6
+ requested,
7
+ existing,
8
+ mismatches,
9
+ message: `Run "${runId}" already has a different durable start (${mismatches.join(', ')})`,
10
+ });
11
+ this.name = 'StartRunConflictError';
12
+ }
13
+ }
14
+ export class DuplicateEffectDispatchError extends Data.TaggedError('DuplicateEffectDispatchError') {
15
+ constructor(runId, effectId, threadId) {
16
+ super({
17
+ runId,
18
+ effectId,
19
+ threadId,
20
+ message: `Duplicate effect dispatch detected for effectId "${effectId}" on thread "${threadId}"; refusing to re-dispatch already executed effect`,
21
+ });
22
+ this.name = 'DuplicateEffectDispatchError';
23
+ }
24
+ }
25
+ export class MaxWakeIterationsError extends Data.TaggedError('MaxWakeIterationsError') {
26
+ constructor(runId, maxIterations) {
27
+ super({
28
+ runId,
29
+ maxIterations,
30
+ message: `Max wake iterations exceeded (${maxIterations}) for run "${runId}"; possible infinite loop`,
31
+ });
32
+ this.name = 'MaxWakeIterationsError';
33
+ }
34
+ }
35
+ export class RuntimeExecutionError extends Data.TaggedError('RuntimeExecutionError') {
36
+ constructor(message) {
37
+ super({ message });
38
+ }
39
+ }
@@ -1,5 +1,18 @@
1
- import { Effect, Layer } from 'effect';
2
- import { type AnyRuntimeModule, type AppendableEvent, type EventCatalog, type EventEnvelope, type EventInput, type EventOrigin, type EventStore, type InvalidEventError, type JsonValue, type RegisteredDefinition, type RunCursor, type RunState, type SnapshotStore } from '@swirls/looms/core';
1
+ import { Effect, Layer, type Context } from 'effect';
2
+ import { type AnyRuntimeModule, type AppendableEvent, type EventCatalog, type EventEnvelope, type EventInput, type EventOrigin, type EventStore, InvalidEventError, type JsonValue, type OutstandingEffect, type RegisteredDefinition, type RunCursor, type RunState, type SnapshotStore } from '@swirls/looms/core';
3
+ import type { EffectWorkerTask } from './types';
4
+ export declare function workerTask(runId: string, item: OutstandingEffect, attempt: number): EffectWorkerTask;
5
+ declare const UnknownDefinitionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
6
+ readonly _tag: "UnknownDefinitionError";
7
+ } & Readonly<A>;
8
+ export declare class UnknownDefinitionError extends UnknownDefinitionError_base<{
9
+ readonly kind: string;
10
+ readonly definitionName: string;
11
+ readonly definitionVersion: string;
12
+ readonly message: string;
13
+ }> {
14
+ constructor(kind: string, definitionName: string, definitionVersion: string);
15
+ }
3
16
  export declare function resolveSnapshotStore(explicit: SnapshotStore | undefined, store: EventStore | undefined): SnapshotStore;
4
17
  export declare class RunCursorCache {
5
18
  private readonly max;
@@ -10,7 +23,7 @@ export declare class RunCursorCache {
10
23
  delete(runId: string): void;
11
24
  }
12
25
  export declare function stripSeq(events: ReadonlyArray<EventEnvelope>): AppendableEvent[];
13
- export declare function moduleServices(modules: readonly AnyRuntimeModule[]): Layer.Layer<any>;
26
+ export declare function moduleServices(modules: readonly AnyRuntimeModule[]): Layer.Layer<Context.Service.Any>;
14
27
  export declare function groupOutstanding(items: readonly {
15
28
  threadId: string;
16
29
  causingSeq: number;
@@ -24,10 +37,11 @@ export declare function groupOutstanding(items: readonly {
24
37
  export declare function threadStartedEvents(definitions: ReadonlyMap<string, RegisteredDefinition>, args: {
25
38
  kind: string;
26
39
  definitionName: string;
40
+ definitionVersion: string;
27
41
  input: JsonValue;
28
42
  threadId: string;
29
43
  parentThreadId: string | null;
30
- }): Effect.Effect<ReadonlyArray<EventInput>, Error>;
44
+ }): Effect.Effect<ReadonlyArray<EventInput>, UnknownDefinitionError>;
31
45
  export declare function synthesizedThreadFailed(before: RunState, after: RunState, written: readonly EventEnvelope[]): EventInput[];
32
46
  export declare function waitSatisfiedEvents(state: RunState, events: readonly EventEnvelope[]): EventInput[];
33
47
  export declare function createEffectFailedEvent(runId: string, item: {
@@ -45,7 +59,13 @@ export declare function createLiveEvent(runId: string, item: {
45
59
  causingEventId: string;
46
60
  threadId: string;
47
61
  }, validated: EventInput): AppendableEvent | undefined;
62
+ /**
63
+ * Admit events from an external caller. Runtime protocol events are reserved for the runtime
64
+ * itself, and external events can never claim an effect outcome or a non-external origin.
65
+ */
66
+ export declare function admitExternalEvents(events: readonly EventInput[]): Effect.Effect<EventInput[], InvalidEventError>;
48
67
  export declare function validateAndCreateEvents(catalogs: readonly EventCatalog[], runId: string, events: readonly EventInput[], defaults: {
49
68
  origin: EventOrigin;
50
69
  threadId?: string | null;
51
70
  }): Effect.Effect<EventEnvelope[], InvalidEventError>;
71
+ export {};
@@ -1,5 +1,25 @@
1
- import { Effect, Layer, Predicate } from 'effect';
2
- import { asJson, createEvent, makeMemorySnapshotStore, matchingWaits, snapshotStoreOf, validateEventInput, validateEventsEffect, validateInput, withSnapshotStore, } from '@swirls/looms/core';
1
+ import { Data, Effect, Layer, Predicate } from 'effect';
2
+ import { asJson, createEvent, definitionKey, makeMemorySnapshotStore, matchingWaits, snapshotStoreOf, validateEventInput, validateEventsEffect, validateInputEffect, withSnapshotStore, InvalidEventError, } from '@swirls/looms/core';
3
+ export function workerTask(runId, item, attempt) {
4
+ return {
5
+ runId,
6
+ effectId: item.effectId,
7
+ attempt,
8
+ type: item.effect.type,
9
+ input: 'input' in item.effect ? item.effect.input : null,
10
+ };
11
+ }
12
+ export class UnknownDefinitionError extends Data.TaggedError('UnknownDefinitionError') {
13
+ constructor(kind, definitionName, definitionVersion) {
14
+ super({
15
+ kind,
16
+ definitionName,
17
+ definitionVersion,
18
+ message: `Unknown definition ${definitionKey(kind, definitionName, definitionVersion)}`,
19
+ });
20
+ this.name = 'UnknownDefinitionError';
21
+ }
22
+ }
3
23
  export function resolveSnapshotStore(explicit, store) {
4
24
  if (explicit) {
5
25
  if (store) {
@@ -52,15 +72,17 @@ export class RunCursorCache {
52
72
  export function stripSeq(events) {
53
73
  return events.map(({ seq: _seq, ...rest }) => rest);
54
74
  }
75
+ // Heterogeneous module service identifiers are intentionally erased after composition.
76
+ // oxlint-disable-next-line effecttsgo/any-unknown-in-error-context
55
77
  export function moduleServices(modules) {
56
- // SAFETY: Empty layer serves as seed; module service layers are merged in.
57
- let merged = Layer.empty;
58
- for (const module of modules) {
59
- if (module.services) {
60
- merged = Layer.merge(merged, module.services());
61
- }
78
+ const layers = modules.flatMap((module) => (module.services ? [module.services()] : []));
79
+ const [first, ...rest] = layers;
80
+ if (!first) {
81
+ // SAFETY: An empty service set satisfies the erased registry boundary.
82
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
83
+ return Layer.empty;
62
84
  }
63
- return merged;
85
+ return rest.reduce((merged, layer) => Layer.merge(merged, layer), first);
64
86
  }
65
87
  export function groupOutstanding(items) {
66
88
  const keys = [];
@@ -83,21 +105,18 @@ export function groupOutstanding(items) {
83
105
  */
84
106
  export function threadStartedEvents(definitions, args) {
85
107
  return Effect.gen(function* () {
86
- const def = definitions.get(`${args.kind}:${args.definitionName}`);
108
+ const def = definitions.get(definitionKey(args.kind, args.definitionName, args.definitionVersion));
87
109
  if (!def) {
88
- return yield* Effect.fail(new Error(`Unknown definition ${args.kind}:${args.definitionName}`));
110
+ return yield* new UnknownDefinitionError(args.kind, args.definitionName, args.definitionVersion);
89
111
  }
90
112
  const raw = args.input ?? null;
91
113
  let startedInput = raw;
92
114
  let validationError;
93
115
  if (def?.input) {
94
- const validated = yield* Effect.tryPromise({
95
- try: () => {
96
- // SAFETY: RegisteredDefinition.input is a Standard Schema when present.
97
- return validateInput(def.input, raw);
98
- },
99
- catch: (err) => (err instanceof Error ? err : new Error(String(err))),
100
- }).pipe(Effect.map((value) => ({ ok: true, value })), Effect.catch((err) => Effect.succeed({ ok: false, error: err.message })));
116
+ const validated = yield* validateInputEffect(def.input, raw).pipe(Effect.match({
117
+ onFailure: (error) => ({ ok: false, error: error.message }),
118
+ onSuccess: (value) => ({ ok: true, value }),
119
+ }));
101
120
  if (validated.ok) {
102
121
  startedInput = validated.value;
103
122
  }
@@ -111,6 +130,7 @@ export function threadStartedEvents(definitions, args) {
111
130
  threadId: args.threadId,
112
131
  kind: args.kind,
113
132
  definitionName: args.definitionName,
133
+ definitionVersion: args.definitionVersion,
114
134
  input: startedInput,
115
135
  parentThreadId: args.parentThreadId,
116
136
  },
@@ -215,12 +235,29 @@ export function createLiveEvent(runId, item, validated) {
215
235
  effectId: item.effectId,
216
236
  causationId: item.causingEventId,
217
237
  threadId: targetThreadId,
218
- ephemeral: validated.ephemeral ?? true,
238
+ ephemeral: true,
219
239
  origin: validated.origin ?? { type: 'thread', threadId: item.threadId },
220
240
  });
221
241
  const [liveEvent] = stripSeq([ephemeral]);
222
242
  return liveEvent;
223
243
  }
244
+ const EXTERNAL_RUNTIME_EVENT_TYPES = new Set([
245
+ 'runtime.signal.received',
246
+ 'runtime.thread.cancel.requested',
247
+ ]);
248
+ /**
249
+ * Admit events from an external caller. Runtime protocol events are reserved for the runtime
250
+ * itself, and external events can never claim an effect outcome or a non-external origin.
251
+ */
252
+ export function admitExternalEvents(events) {
253
+ return Effect.forEach(events, (input) => input.type.startsWith('runtime.') && !EXTERNAL_RUNTIME_EVENT_TYPES.has(input.type)
254
+ ? Effect.fail(new InvalidEventError(input.type, `Event type "${input.type}" is reserved for the runtime`))
255
+ : Effect.succeed({
256
+ ...input,
257
+ effectId: null,
258
+ origin: input.origin?.type === 'external' ? input.origin : { type: 'external' },
259
+ }));
260
+ }
224
261
  export function validateAndCreateEvents(catalogs, runId, events, defaults) {
225
262
  return validateEventsEffect(catalogs, events).pipe(Effect.map((validated) => validated.map((input) => createEvent(runId, {
226
263
  ...input,
@@ -1,5 +1,5 @@
1
- export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, type CreateRuntimeOptions, type LoomsRuntime, type RegisteredDefinition, type StartRunArgs, type WakeError, type WakeScheduler, } from './runtime';
1
+ export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, RunOverloadedError, StartRunConflictError, type CreateRuntimeOptions, type EffectWorker, type EffectWorkerTask, type LoomsRuntime, type RunOperationalStatus, type RegisteredDefinition, type StartRunArgs, type WakeError, type WakeScheduler, type WorkerCallback, type WorkerCallbackInput, } from './runtime';
2
2
  export { createLooms, type Looms, type CreateLoomsOptions, type StartResult } from './looms';
3
- export { serveHttp, createFetchHandler, isLoomsApiPath, type FetchHandlerOptions, type RunningServer, type LoomsFetchResult, } from './server';
4
- export { handleEventsApi, encodeLoomsEvent, type EncodedLoomsEvent } from './events-api';
3
+ export { serveHttp, createFetchHandler, isLoomsApiPath, type FetchHandlerOptions, authAllowed, authDenied, bearerAuth, defaultAuthorize, type AuthDecision, type AuthorizedAccess, type Authorize, type BearerTokens, type RouteAccess, type RouteInfo, type RunningServer, type LoomsFetchResult, } from './server';
5
4
  export { createEventStreamResponse, type EventStreamOptions } from './sse';
5
+ export { notifyObserver, type RuntimeObservation, type RuntimeObserver } from './observer';
@@ -1,5 +1,5 @@
1
- export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, } from './runtime.js';
1
+ export { createRuntime, createTimeoutScheduler, DuplicateEffectDispatchError, MaxWakeIterationsError, RunOverloadedError, StartRunConflictError, } from './runtime.js';
2
2
  export { createLooms } from './looms.js';
3
- export { serveHttp, createFetchHandler, isLoomsApiPath, } from './server.js';
4
- export { handleEventsApi, encodeLoomsEvent } from './events-api.js';
3
+ export { serveHttp, createFetchHandler, isLoomsApiPath, authAllowed, authDenied, bearerAuth, defaultAuthorize, } from './server.js';
5
4
  export { createEventStreamResponse } from './sse.js';
5
+ export { notifyObserver } from './observer.js';
@@ -0,0 +1,15 @@
1
+ import { Effect } from 'effect';
2
+ import type { RunExecutionContexts } from './run-execution-context';
3
+ declare const RunOverloadedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
4
+ readonly _tag: "RunOverloadedError";
5
+ } & Readonly<A>;
6
+ export declare class RunOverloadedError extends RunOverloadedError_base<{
7
+ readonly runId: string;
8
+ readonly limit: number;
9
+ readonly message: string;
10
+ }> {
11
+ constructor(runId: string, limit: number);
12
+ }
13
+ export type RunIngress = <A, E, R>(runId: string, operation: Effect.Effect<A, E, R>) => Effect.Effect<A, E | RunOverloadedError, R>;
14
+ export declare function createRunIngress(executionContexts: RunExecutionContexts, maxPendingRunOperations: number): RunIngress;
15
+ export {};
@@ -0,0 +1,42 @@
1
+ import { Data, Effect } from 'effect';
2
+ export class RunOverloadedError extends Data.TaggedError('RunOverloadedError') {
3
+ constructor(runId, limit) {
4
+ super({
5
+ runId,
6
+ limit,
7
+ message: `Run "${runId}" has reached its pending operation limit (${limit})`,
8
+ });
9
+ this.name = 'RunOverloadedError';
10
+ }
11
+ }
12
+ export function createRunIngress(executionContexts, maxPendingRunOperations) {
13
+ return (runId, operation) => Effect.suspend(() => {
14
+ const context = executionContexts.get(runId);
15
+ const current = context.ingress ?? { pending: 0, tail: Promise.resolve() };
16
+ if (current.pending >= maxPendingRunOperations) {
17
+ return Effect.fail(new RunOverloadedError(runId, maxPendingRunOperations));
18
+ }
19
+ let release;
20
+ // Promise chaining is the admission queue; the workload itself remains an Effect.
21
+ // oxlint-disable-next-line effecttsgo/new-promise
22
+ const own = new Promise((resolve) => {
23
+ release = resolve;
24
+ });
25
+ const previous = current.tail;
26
+ context.ingress = { pending: current.pending + 1, tail: own };
27
+ return Effect.promise(() => previous).pipe(Effect.andThen(operation), Effect.ensuring(Effect.sync(() => {
28
+ release();
29
+ const latest = context.ingress;
30
+ if (!latest) {
31
+ return;
32
+ }
33
+ if (latest.pending <= 1) {
34
+ context.ingress = null;
35
+ }
36
+ else {
37
+ context.ingress = { ...latest, pending: latest.pending - 1 };
38
+ }
39
+ executionContexts.releaseIfIdle(runId);
40
+ })));
41
+ });
42
+ }
@@ -0,0 +1,21 @@
1
+ import { Effect, type Context, type ManagedRuntime } from 'effect';
2
+ import { type ComposedRegistry, type EventEnvelope, type OutstandingEffect, type RegisteredDefinition } from '@swirls/looms/core';
3
+ import type { RuntimeObserver } from './observer';
4
+ import type { RuntimeRepository } from './repository';
5
+ import type { RunExecutionContext } from './run-execution-context';
6
+ export interface LocalEffectExecutorOptions {
7
+ readonly registry: ComposedRegistry;
8
+ readonly services: ManagedRuntime.ManagedRuntime<Context.Service.Any, never>;
9
+ readonly definitions: ReadonlyMap<string, RegisteredDefinition>;
10
+ readonly executionContext: RunExecutionContext;
11
+ readonly liveAppends: RuntimeRepository['liveAppends'];
12
+ readonly runInContext: <A, E>(effect: Effect.Effect<A, E>) => Promise<A>;
13
+ readonly observe: (event: Parameters<RuntimeObserver['observe']>[0]) => void;
14
+ }
15
+ export interface ExecuteLocalEffectsInput {
16
+ readonly runId: string;
17
+ readonly outstanding: ReadonlyArray<OutstandingEffect>;
18
+ readonly attempts: ReadonlyMap<string, number>;
19
+ readonly now: number;
20
+ }
21
+ export declare function executeLocalEffects(options: LocalEffectExecutorOptions, input: ExecuteLocalEffectsInput): Effect.Effect<ReadonlyArray<EventEnvelope>, Error>;
@@ -0,0 +1,137 @@
1
+ import { Effect, Option, Predicate } from 'effect';
2
+ import { createEvent, validateEventInput, withdrawnError, } from '@swirls/looms/core';
3
+ import { dispatchEffect } from './dispatch-effect.js';
4
+ import { RuntimeExecutionError } from './errors.js';
5
+ import { createEffectFailedEvent, createLiveEvent, groupOutstanding, materializeEffectOutcome, } from './helpers.js';
6
+ import { planAttemptFailure } from './retry-policy.js';
7
+ function makeAbortController() {
8
+ return new AbortController();
9
+ }
10
+ /** Completes when the signal aborts, so racing it interrupts a handler that ignores the signal. */
11
+ function abortion(signal) {
12
+ return Effect.callback((resume) => {
13
+ const onAbort = () => resume(Effect.succeed({ _tag: 'aborted' }));
14
+ if (signal.aborted) {
15
+ onAbort();
16
+ return Effect.void;
17
+ }
18
+ signal.addEventListener('abort', onAbort, { once: true });
19
+ return Effect.sync(() => signal.removeEventListener('abort', onAbort));
20
+ });
21
+ }
22
+ export function executeLocalEffects(options, input) {
23
+ const { registry, services, definitions, executionContext, liveAppends, runInContext, observe } = options;
24
+ return Effect.forEach(groupOutstanding(input.outstanding), (groupKey) => Effect.gen(function* () {
25
+ const group = input.outstanding.filter((item) => `${item.threadId}:${item.causingSeq}` === groupKey);
26
+ const produced = [];
27
+ let failedEffectId;
28
+ for (const item of group) {
29
+ if (failedEffectId && item.effect.type === 'runtime.wait') {
30
+ produced.push(createEffectFailedEvent(input.runId, item, withdrawnError(failedEffectId)));
31
+ continue;
32
+ }
33
+ const appendLive = (eventInput) => runInContext(Effect.gen(function* () {
34
+ const validated = yield* validateEventInput(registry.catalogs, eventInput);
35
+ const liveEvent = createLiveEvent(input.runId, item, validated);
36
+ if (liveEvent) {
37
+ yield* liveAppends.push(input.runId, liveEvent);
38
+ }
39
+ }));
40
+ const controller = makeAbortController();
41
+ executionContext.activeEffects.set(item.effectId, {
42
+ controller,
43
+ threadId: item.threadId,
44
+ });
45
+ const retry = registry.effects.get(item.effect.type)?.retry;
46
+ const dispatched = dispatchEffect(registry, services, definitions, item.effect, {
47
+ effectId: item.effectId,
48
+ runId: input.runId,
49
+ threadId: item.threadId,
50
+ causingEventId: item.causingEventId,
51
+ signal: controller.signal,
52
+ emit: appendLive,
53
+ }).pipe(Effect.map((outcomes) => ({ _tag: 'completed', outcomes })), Effect.raceFirst(abortion(controller.signal)));
54
+ const settled = yield* (retry?.startToCloseTimeoutMs
55
+ ? dispatched.pipe(Effect.timeoutOption(retry.startToCloseTimeoutMs), Effect.map(Option.getOrElse(() => ({ _tag: 'timed-out' }))))
56
+ : dispatched).pipe(Effect.ensuring(Effect.sync(() => {
57
+ executionContext.activeEffects.delete(item.effectId);
58
+ })));
59
+ if (settled._tag === 'aborted') {
60
+ continue;
61
+ }
62
+ const before = produced.length;
63
+ if (settled._tag === 'timed-out') {
64
+ controller.abort(new RuntimeExecutionError('start-to-close timeout'));
65
+ const attemptNumber = input.attempts.get(item.effectId) ?? 1;
66
+ observe({
67
+ type: 'effect.timeout',
68
+ runId: input.runId,
69
+ at: input.now,
70
+ effectId: item.effectId,
71
+ attempt: attemptNumber,
72
+ detail: 'start-to-close',
73
+ });
74
+ produced.push(createEvent(input.runId, {
75
+ type: 'runtime.effect.timed_out',
76
+ payload: {
77
+ effectId: item.effectId,
78
+ attempt: attemptNumber,
79
+ timeout: 'start-to-close',
80
+ },
81
+ threadId: item.threadId,
82
+ causationId: item.causingEventId,
83
+ origin: { type: 'system' },
84
+ }), planAttemptFailure({
85
+ runId: input.runId,
86
+ item,
87
+ attempt: attemptNumber,
88
+ error: 'start-to-close timeout',
89
+ now: input.now,
90
+ retry,
91
+ origin: { type: 'system' },
92
+ }).event);
93
+ failedEffectId = item.effectId;
94
+ continue;
95
+ }
96
+ const { outcomes } = settled;
97
+ if (outcomes.length === 0) {
98
+ produced.push(createEffectFailedEvent(input.runId, item, 'empty-outcome'));
99
+ }
100
+ for (const outcome of outcomes) {
101
+ if (outcome.type === 'runtime.effect.failed') {
102
+ const attempt = input.attempts.get(item.effectId) ?? 1;
103
+ const payload = Predicate.isObject(outcome.payload) ? outcome.payload : {};
104
+ const error = Predicate.isString(payload.error) ? payload.error : 'effect failed';
105
+ const failure = planAttemptFailure({
106
+ runId: input.runId,
107
+ item,
108
+ attempt,
109
+ error,
110
+ now: input.now,
111
+ retry,
112
+ origin: { type: 'system' },
113
+ });
114
+ if (failure.retrying) {
115
+ observe({
116
+ type: 'effect.retry',
117
+ runId: input.runId,
118
+ at: input.now,
119
+ effectId: item.effectId,
120
+ attempt,
121
+ detail: error,
122
+ });
123
+ produced.push(failure.event);
124
+ continue;
125
+ }
126
+ }
127
+ produced.push(yield* materializeEffectOutcome(registry.catalogs, input.runId, item, outcome));
128
+ }
129
+ const itemOutcomes = produced.slice(before);
130
+ if (item.effect.type !== 'runtime.wait' &&
131
+ itemOutcomes.some((event) => event.type === 'runtime.effect.failed')) {
132
+ failedEffectId = item.effectId;
133
+ }
134
+ }
135
+ return produced;
136
+ }), { concurrency: 'unbounded' }).pipe(Effect.map((groups) => groups.flat()));
137
+ }
@@ -1,6 +1,7 @@
1
- import { type AnyRuntimeModule, type DefinitionInput, type DefinitionRef, type EventEnvelope, type EventInput, type EventStore, type JsonValue, type SnapshotStore, type ProjectionDefinition, type ReplayStep, type RunState } from '@swirls/looms/core';
2
- import { type LoomsRuntime, type WakeScheduler } from './runtime';
3
- import { type RunningServer } from './server';
1
+ import { type AnyRuntimeModule, type DebuggerHost, type DefinitionInput, type DefinitionRef, type EventEnvelope, type EventInput, type EventStore, type EventStoreTrimCoverage, type JsonValue, type SnapshotStore, type ProjectionDefinition, type ReplayStep, type RunState } from '@swirls/looms/core';
2
+ import type { RuntimeObserver } from './observer';
3
+ import { type EffectWorker, type LoomsRuntime, type RunOperationalStatus, type WakeScheduler, type WorkerCallbackInput } from './runtime';
4
+ import { type Authorize, type RunningServer } from './server';
4
5
  export interface CreateLoomsOptions {
5
6
  /** Runtime modules to enable. Pass `agent()`, `workflow()`, `approval()`, and/or your own. */
6
7
  readonly modules?: readonly AnyRuntimeModule[];
@@ -10,19 +11,38 @@ export interface CreateLoomsOptions {
10
11
  hostname?: string;
11
12
  };
12
13
  readonly maxWakeIterations?: number;
14
+ /** Maximum active and queued mutation operations per run. Default 256. */
15
+ readonly maxPendingRunOperations?: number;
13
16
  /** Durable events between mid-wake snapshots. Default 200; `0` disables. Parking always snapshots. */
14
17
  readonly snapshotEvery?: number;
15
18
  /** Defaults to the EventStore's attached store (S2) or an in-memory SnapshotStore. */
16
19
  readonly snapshotStore?: SnapshotStore;
17
20
  readonly trimAfterSnapshot?: {
18
21
  keepSnapshots: number;
22
+ coverage?: (runId: string) => EventStoreTrimCoverage | Promise<EventStoreTrimCoverage>;
19
23
  };
20
24
  /** In-process cursor cache size. Default `0` (stateless between calls). */
21
25
  readonly runCacheSize?: number;
22
26
  /** Scan existing runs for pending timers on boot. Default true. */
23
27
  readonly rescanTimers?: boolean;
24
- /** Pluggable wake scheduler for timer waits. Defaults to an in-process setTimeout scheduler. */
28
+ /** Pluggable wake scheduler for timer waits. Defaults to an in-process Effect fiber scheduler. */
25
29
  readonly scheduler?: WakeScheduler;
30
+ readonly worker?: EffectWorker;
31
+ /** Failure-isolated runtime observation sink. */
32
+ readonly observer?: RuntimeObserver;
33
+ /**
34
+ * Authorizes HTTP API requests. Without it, run reads and writes are open while worker callback
35
+ * and operations routes return 503; `bearerAuth({ worker, operations })` enables them.
36
+ *
37
+ * A mounted debugger is authorized as `{ access: 'read', name: 'debugger' }`. Bearer tokens on
38
+ * reads block browser navigation, so hosts that need auth should use a cookie or session policy.
39
+ */
40
+ readonly authorize?: Authorize;
41
+ /**
42
+ * Serves a debugger UI under `debugger.basePath` (for example `/debugger`). The runtime does not
43
+ * bundle a UI; pass `debuggerUi()` from `@swirls/looms/debugger/server`.
44
+ */
45
+ readonly debugger?: DebuggerHost;
26
46
  }
27
47
  export interface StartResult {
28
48
  readonly runId: string;
@@ -46,6 +66,7 @@ export interface Looms {
46
66
  startRun(args: {
47
67
  kind: string;
48
68
  definitionName: string;
69
+ definitionVersion?: string;
49
70
  input?: JsonValue;
50
71
  runId?: string;
51
72
  threadId?: string;
@@ -61,9 +82,14 @@ export interface Looms {
61
82
  }): Promise<RunState>;
62
83
  wake(runId: string): Promise<RunState>;
63
84
  rescanTimers(): Promise<number>;
85
+ recoverDeadlines(): Promise<number>;
86
+ inspectRun(runId: string): Promise<RunOperationalStatus>;
87
+ retryEffect(runId: string, effectId: string): Promise<RunState>;
88
+ listRuns(): Promise<string[]>;
64
89
  project<S>(runId: string, definition: ProjectionDefinition<S>): Promise<S>;
65
90
  replayTo(runId: string, seq: number): Promise<ReplayStep | null>;
66
91
  cancel(runId: string, threadId?: string): Promise<RunState>;
92
+ workerCallback(runId: string, input: WorkerCallbackInput): Promise<RunState>;
67
93
  fetch(req: Request): Promise<Response | null>;
68
94
  serve(options?: {
69
95
  port?: number;