effect 4.0.4 → 4.0.5

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 (308) hide show
  1. package/ai-docs/src/52_graphql/10_basics.ts +19 -13
  2. package/ai-docs/src/52_graphql/30_batching.ts +6 -4
  3. package/ai-docs/src/52_graphql/40_aliased-batching.ts +6 -4
  4. package/dist/Array.d.ts +90 -6
  5. package/dist/Array.d.ts.map +1 -1
  6. package/dist/Array.js +4 -2
  7. package/dist/Array.js.map +1 -1
  8. package/dist/Channel.d.ts +6 -1
  9. package/dist/Channel.d.ts.map +1 -1
  10. package/dist/Channel.js +17 -3
  11. package/dist/Channel.js.map +1 -1
  12. package/dist/ConfigProvider.d.ts.map +1 -1
  13. package/dist/ConfigProvider.js +33 -32
  14. package/dist/ConfigProvider.js.map +1 -1
  15. package/dist/Duration.d.ts.map +1 -1
  16. package/dist/Duration.js +2 -5
  17. package/dist/Duration.js.map +1 -1
  18. package/dist/Effect.d.ts +61 -19
  19. package/dist/Effect.d.ts.map +1 -1
  20. package/dist/Effect.js +58 -39
  21. package/dist/Effect.js.map +1 -1
  22. package/dist/FileSystem.d.ts +23 -9
  23. package/dist/FileSystem.d.ts.map +1 -1
  24. package/dist/FileSystem.js.map +1 -1
  25. package/dist/Match.d.ts +20 -6
  26. package/dist/Match.d.ts.map +1 -1
  27. package/dist/Match.js +2 -2
  28. package/dist/Match.js.map +1 -1
  29. package/dist/Path.d.ts +37 -5
  30. package/dist/Path.d.ts.map +1 -1
  31. package/dist/Path.js +36 -5
  32. package/dist/Path.js.map +1 -1
  33. package/dist/Schema.d.ts +7 -2
  34. package/dist/Schema.d.ts.map +1 -1
  35. package/dist/Schema.js +9 -2
  36. package/dist/Schema.js.map +1 -1
  37. package/dist/String.d.ts +12 -0
  38. package/dist/String.d.ts.map +1 -1
  39. package/dist/String.js +17 -4
  40. package/dist/String.js.map +1 -1
  41. package/dist/TxRef.d.ts.map +1 -1
  42. package/dist/TxRef.js +3 -2
  43. package/dist/TxRef.js.map +1 -1
  44. package/dist/ai/AiError.d.ts +10 -10
  45. package/dist/ai/AiError.d.ts.map +1 -1
  46. package/dist/ai/AiError.js +1 -1
  47. package/dist/ai/AiError.js.map +1 -1
  48. package/dist/ai/Decision.d.ts +70 -19
  49. package/dist/ai/Decision.d.ts.map +1 -1
  50. package/dist/ai/Decision.js +37 -3
  51. package/dist/ai/Decision.js.map +1 -1
  52. package/dist/ai/DecisionModel.js +1 -1
  53. package/dist/ai/DecisionModel.js.map +1 -1
  54. package/dist/ai/LanguageModel.d.ts.map +1 -1
  55. package/dist/ai/LanguageModel.js +47 -35
  56. package/dist/ai/LanguageModel.js.map +1 -1
  57. package/dist/ai/McpServer.d.ts +6 -52
  58. package/dist/ai/McpServer.d.ts.map +1 -1
  59. package/dist/ai/McpServer.js +2 -28
  60. package/dist/ai/McpServer.js.map +1 -1
  61. package/dist/ai/Response.d.ts +1 -1
  62. package/dist/cli/Completions.d.ts +5 -0
  63. package/dist/cli/Completions.d.ts.map +1 -1
  64. package/dist/cli/Completions.js.map +1 -1
  65. package/dist/cli/Flag.d.ts +100 -0
  66. package/dist/cli/Flag.d.ts.map +1 -1
  67. package/dist/cli/Flag.js +33 -0
  68. package/dist/cli/Flag.js.map +1 -1
  69. package/dist/cli/Param.d.ts +87 -0
  70. package/dist/cli/Param.d.ts.map +1 -1
  71. package/dist/cli/Param.js +30 -0
  72. package/dist/cli/Param.js.map +1 -1
  73. package/dist/cli/internal/command.d.ts.map +1 -1
  74. package/dist/cli/internal/command.js +2 -1
  75. package/dist/cli/internal/command.js.map +1 -1
  76. package/dist/cli/internal/completions/bash.js +4 -3
  77. package/dist/cli/internal/completions/bash.js.map +1 -1
  78. package/dist/cli/internal/completions/descriptor.js +8 -1
  79. package/dist/cli/internal/completions/descriptor.js.map +1 -1
  80. package/dist/cli/internal/completions/fish.js +4 -4
  81. package/dist/cli/internal/completions/fish.js.map +1 -1
  82. package/dist/cli/internal/completions/powershell.js +3 -2
  83. package/dist/cli/internal/completions/powershell.js.map +1 -1
  84. package/dist/cli/internal/completions/zsh.js +7 -3
  85. package/dist/cli/internal/completions/zsh.js.map +1 -1
  86. package/dist/cli/internal/parser.js +11 -3
  87. package/dist/cli/internal/parser.js.map +1 -1
  88. package/dist/cli/internal/wizard.d.ts.map +1 -1
  89. package/dist/cli/internal/wizard.js +2 -1
  90. package/dist/cli/internal/wizard.js.map +1 -1
  91. package/dist/cluster/ClusterWorkflowEngine.d.ts +1 -0
  92. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  93. package/dist/cluster/ClusterWorkflowEngine.js +67 -13
  94. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  95. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  96. package/dist/cluster/MessageStorage.js +20 -12
  97. package/dist/cluster/MessageStorage.js.map +1 -1
  98. package/dist/cluster/Runners.d.ts.map +1 -1
  99. package/dist/cluster/Runners.js +54 -34
  100. package/dist/cluster/Runners.js.map +1 -1
  101. package/dist/cluster/internal/entityManager.js +1 -1
  102. package/dist/cluster/internal/entityManager.js.map +1 -1
  103. package/dist/encoding/Sse.js +1 -1
  104. package/dist/encoding/Sse.js.map +1 -1
  105. package/dist/graphql/GraphQLClient.d.ts.map +1 -1
  106. package/dist/graphql/GraphQLClient.js +12 -5
  107. package/dist/graphql/GraphQLClient.js.map +1 -1
  108. package/dist/graphql/GraphQLProtocol.d.ts +249 -11
  109. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
  110. package/dist/graphql/GraphQLProtocol.js +98 -8
  111. package/dist/graphql/GraphQLProtocol.js.map +1 -1
  112. package/dist/graphql/GraphQLResolver.d.ts +1 -1
  113. package/dist/graphql/GraphQLResolver.d.ts.map +1 -1
  114. package/dist/graphql/GraphQLResolver.js +46 -16
  115. package/dist/graphql/GraphQLResolver.js.map +1 -1
  116. package/dist/http/FetchHttpClient.d.ts +6 -3
  117. package/dist/http/FetchHttpClient.d.ts.map +1 -1
  118. package/dist/http/FetchHttpClient.js +6 -3
  119. package/dist/http/FetchHttpClient.js.map +1 -1
  120. package/dist/http/FindMyWay/internal/router.js +2 -1
  121. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  122. package/dist/http/Headers.d.ts +3 -3
  123. package/dist/http/Headers.d.ts.map +1 -1
  124. package/dist/http/Headers.js +6 -5
  125. package/dist/http/Headers.js.map +1 -1
  126. package/dist/http/HttpClient.d.ts +12 -0
  127. package/dist/http/HttpClient.d.ts.map +1 -1
  128. package/dist/http/HttpClient.js +14 -1
  129. package/dist/http/HttpClient.js.map +1 -1
  130. package/dist/http/HttpClientError.d.ts.map +1 -1
  131. package/dist/http/HttpClientError.js +8 -6
  132. package/dist/http/HttpClientError.js.map +1 -1
  133. package/dist/http/HttpClientRequest.d.ts +147 -4
  134. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  135. package/dist/http/HttpClientRequest.js +47 -1
  136. package/dist/http/HttpClientRequest.js.map +1 -1
  137. package/dist/http/HttpMiddleware.d.ts +60 -0
  138. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  139. package/dist/http/HttpMiddleware.js +67 -5
  140. package/dist/http/HttpMiddleware.js.map +1 -1
  141. package/dist/http/HttpRouter.d.ts.map +1 -1
  142. package/dist/http/HttpRouter.js +52 -13
  143. package/dist/http/HttpRouter.js.map +1 -1
  144. package/dist/http/HttpServerError.d.ts.map +1 -1
  145. package/dist/http/HttpServerError.js +6 -4
  146. package/dist/http/HttpServerError.js.map +1 -1
  147. package/dist/http/HttpServerRequest.js +2 -2
  148. package/dist/http/HttpServerRequest.js.map +1 -1
  149. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  150. package/dist/http/HttpStaticServer.js +4 -10
  151. package/dist/http/HttpStaticServer.js.map +1 -1
  152. package/dist/http/HttpTraceContext.js +1 -1
  153. package/dist/http/HttpTraceContext.js.map +1 -1
  154. package/dist/http/Url.d.ts.map +1 -1
  155. package/dist/http/Url.js +2 -1
  156. package/dist/http/Url.js.map +1 -1
  157. package/dist/http/UrlParams.d.ts +112 -8
  158. package/dist/http/UrlParams.d.ts.map +1 -1
  159. package/dist/http/UrlParams.js +141 -14
  160. package/dist/http/UrlParams.js.map +1 -1
  161. package/dist/http/internal/compression.d.ts +1 -1
  162. package/dist/http/internal/compression.d.ts.map +1 -1
  163. package/dist/http/internal/compression.js +2 -10
  164. package/dist/http/internal/compression.js.map +1 -1
  165. package/dist/http/internal/compressionBody.d.ts +2 -0
  166. package/dist/http/internal/compressionBody.d.ts.map +1 -0
  167. package/dist/http/internal/compressionBody.js +36 -0
  168. package/dist/http/internal/compressionBody.js.map +1 -0
  169. package/dist/http/internal/decompression.d.ts +2 -0
  170. package/dist/http/internal/decompression.d.ts.map +1 -0
  171. package/dist/http/internal/decompression.js +162 -0
  172. package/dist/http/internal/decompression.js.map +1 -0
  173. package/dist/http/internal/tracing.js +14 -4
  174. package/dist/http/internal/tracing.js.map +1 -1
  175. package/dist/http/internal/urlParams.d.ts +2 -0
  176. package/dist/http/internal/urlParams.d.ts.map +1 -0
  177. package/dist/http/internal/urlParams.js +4 -0
  178. package/dist/http/internal/urlParams.js.map +1 -0
  179. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  180. package/dist/http-api/HttpApiClient.js +2 -1
  181. package/dist/http-api/HttpApiClient.js.map +1 -1
  182. package/dist/internal/core.js +17 -1
  183. package/dist/internal/core.js.map +1 -1
  184. package/dist/internal/effect.js +5 -3
  185. package/dist/internal/effect.js.map +1 -1
  186. package/dist/internal/graphql.js +12 -2
  187. package/dist/internal/graphql.js.map +1 -1
  188. package/dist/internal/version.js +1 -1
  189. package/dist/observability/Otlp.d.ts +15 -0
  190. package/dist/observability/Otlp.d.ts.map +1 -1
  191. package/dist/observability/Otlp.js +3 -0
  192. package/dist/observability/Otlp.js.map +1 -1
  193. package/dist/observability/OtlpExporter.d.ts +8 -0
  194. package/dist/observability/OtlpExporter.d.ts.map +1 -1
  195. package/dist/observability/OtlpExporter.js +10 -1
  196. package/dist/observability/OtlpExporter.js.map +1 -1
  197. package/dist/observability/OtlpLogger.d.ts +17 -0
  198. package/dist/observability/OtlpLogger.d.ts.map +1 -1
  199. package/dist/observability/OtlpLogger.js +14 -1
  200. package/dist/observability/OtlpLogger.js.map +1 -1
  201. package/dist/observability/OtlpMetrics.d.ts +17 -0
  202. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  203. package/dist/observability/OtlpMetrics.js +13 -0
  204. package/dist/observability/OtlpMetrics.js.map +1 -1
  205. package/dist/observability/OtlpTracer.d.ts +17 -0
  206. package/dist/observability/OtlpTracer.d.ts.map +1 -1
  207. package/dist/observability/OtlpTracer.js +15 -2
  208. package/dist/observability/OtlpTracer.js.map +1 -1
  209. package/dist/reactivity/AsyncResult.d.ts +6 -0
  210. package/dist/reactivity/AsyncResult.d.ts.map +1 -1
  211. package/dist/reactivity/AsyncResult.js +27 -0
  212. package/dist/reactivity/AsyncResult.js.map +1 -1
  213. package/dist/reactivity/AtomRegistry.js +3 -1
  214. package/dist/reactivity/AtomRegistry.js.map +1 -1
  215. package/dist/rpc/RpcClient.d.ts.map +1 -1
  216. package/dist/rpc/RpcClient.js +6 -1
  217. package/dist/rpc/RpcClient.js.map +1 -1
  218. package/dist/sql/SqlClient.d.ts +8 -7
  219. package/dist/sql/SqlClient.d.ts.map +1 -1
  220. package/dist/sql/SqlClient.js +8 -7
  221. package/dist/sql/SqlClient.js.map +1 -1
  222. package/dist/testing/TestClock.d.ts +16 -3
  223. package/dist/testing/TestClock.d.ts.map +1 -1
  224. package/dist/testing/TestClock.js +112 -22
  225. package/dist/testing/TestClock.js.map +1 -1
  226. package/dist/workflow/Activity.js +1 -0
  227. package/dist/workflow/Activity.js.map +1 -1
  228. package/dist/workflow/Workflow.d.ts +22 -0
  229. package/dist/workflow/Workflow.d.ts.map +1 -1
  230. package/dist/workflow/Workflow.js +15 -3
  231. package/dist/workflow/Workflow.js.map +1 -1
  232. package/dist/workflow/WorkflowEngine.d.ts +20 -1
  233. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  234. package/dist/workflow/WorkflowEngine.js +35 -21
  235. package/dist/workflow/WorkflowEngine.js.map +1 -1
  236. package/package.json +1 -1
  237. package/src/Array.ts +95 -6
  238. package/src/Channel.ts +24 -3
  239. package/src/ConfigProvider.ts +40 -44
  240. package/src/Duration.ts +4 -5
  241. package/src/Effect.ts +140 -53
  242. package/src/FileSystem.ts +23 -9
  243. package/src/Match.ts +65 -12
  244. package/src/Path.ts +52 -7
  245. package/src/Schema.ts +17 -4
  246. package/src/String.ts +17 -4
  247. package/src/TxRef.ts +4 -2
  248. package/src/ai/AiError.ts +3 -1
  249. package/src/ai/Decision.ts +70 -21
  250. package/src/ai/DecisionModel.ts +1 -1
  251. package/src/ai/LanguageModel.ts +57 -51
  252. package/src/ai/McpServer.ts +15 -55
  253. package/src/cli/Completions.ts +5 -0
  254. package/src/cli/Flag.ts +101 -0
  255. package/src/cli/Param.ts +96 -0
  256. package/src/cli/internal/command.ts +2 -1
  257. package/src/cli/internal/completions/bash.ts +4 -3
  258. package/src/cli/internal/completions/descriptor.ts +10 -1
  259. package/src/cli/internal/completions/fish.ts +4 -4
  260. package/src/cli/internal/completions/powershell.ts +5 -2
  261. package/src/cli/internal/completions/zsh.ts +7 -3
  262. package/src/cli/internal/parser.ts +12 -3
  263. package/src/cli/internal/wizard.ts +2 -1
  264. package/src/cluster/ClusterWorkflowEngine.ts +92 -24
  265. package/src/cluster/MessageStorage.ts +14 -3
  266. package/src/cluster/Runners.ts +88 -66
  267. package/src/cluster/internal/entityManager.ts +1 -1
  268. package/src/encoding/Sse.ts +1 -1
  269. package/src/graphql/GraphQLClient.ts +17 -5
  270. package/src/graphql/GraphQLProtocol.ts +274 -20
  271. package/src/graphql/GraphQLResolver.ts +45 -17
  272. package/src/http/FetchHttpClient.ts +6 -3
  273. package/src/http/FindMyWay/internal/router.ts +2 -1
  274. package/src/http/Headers.ts +6 -9
  275. package/src/http/HttpClient.ts +18 -1
  276. package/src/http/HttpClientError.ts +10 -6
  277. package/src/http/HttpClientRequest.ts +173 -7
  278. package/src/http/HttpMiddleware.ts +85 -5
  279. package/src/http/HttpRouter.ts +60 -13
  280. package/src/http/HttpServerError.ts +8 -4
  281. package/src/http/HttpServerRequest.ts +2 -2
  282. package/src/http/HttpStaticServer.ts +4 -10
  283. package/src/http/HttpTraceContext.ts +1 -1
  284. package/src/http/Url.ts +2 -1
  285. package/src/http/UrlParams.ts +225 -26
  286. package/src/http/internal/compression.ts +3 -17
  287. package/src/http/internal/compressionBody.ts +56 -0
  288. package/src/http/internal/decompression.ts +226 -0
  289. package/src/http/internal/tracing.ts +21 -4
  290. package/src/http/internal/urlParams.ts +5 -0
  291. package/src/http-api/HttpApiClient.ts +2 -1
  292. package/src/internal/core.ts +21 -1
  293. package/src/internal/effect.ts +5 -4
  294. package/src/internal/graphql.ts +30 -7
  295. package/src/internal/version.ts +1 -1
  296. package/src/observability/Otlp.ts +18 -0
  297. package/src/observability/OtlpExporter.ts +14 -3
  298. package/src/observability/OtlpLogger.ts +31 -2
  299. package/src/observability/OtlpMetrics.ts +30 -1
  300. package/src/observability/OtlpTracer.ts +32 -3
  301. package/src/reactivity/AsyncResult.ts +31 -0
  302. package/src/reactivity/AtomRegistry.ts +3 -1
  303. package/src/rpc/RpcClient.ts +6 -1
  304. package/src/sql/SqlClient.ts +9 -7
  305. package/src/testing/TestClock.ts +144 -29
  306. package/src/workflow/Activity.ts +1 -0
  307. package/src/workflow/Workflow.ts +31 -5
  308. package/src/workflow/WorkflowEngine.ts +60 -22
@@ -84,6 +84,9 @@ export class WorkflowEngine extends Context.Service<
84
84
  * `suspendedRetrySchedule`; engines that observe the final result wake it
85
85
  * sooner. `ClusterWorkflowEngine` does so only for callers on the runner
86
86
  * that owns the execution.
87
+ *
88
+ * `detached: true` requires `discard: true` and skips parent completion
89
+ * wakes and interruption linkage. Otherwise, it is a defect.
87
90
  */
88
91
  readonly execute: <
89
92
  Name extends string,
@@ -97,6 +100,7 @@ export class WorkflowEngine extends Context.Service<
97
100
  readonly executionId: string
98
101
  readonly payload: Payload["Type"]
99
102
  readonly discard?: Discard | undefined
103
+ readonly detached?: boolean | undefined
100
104
  readonly suspendedRetrySchedule?:
101
105
  | Schedule.Schedule<any, unknown>
102
106
  | undefined
@@ -280,6 +284,12 @@ export class WorkflowInstance extends Context.Service<
280
284
  */
281
285
  cause: Cause.Cause<never> | undefined
282
286
 
287
+ /**
288
+ * Whether this workflow or an activity hit `SuspendOnFailure`, excluding
289
+ * inherited child failures.
290
+ */
291
+ failed: boolean
292
+
283
293
  /**
284
294
  * Deferred names this run waits on, counted per live wait; their
285
295
  * completions preempt the run.
@@ -298,17 +308,26 @@ export class WorkflowInstance extends Context.Service<
298
308
  static initial(
299
309
  workflow: Workflow.Any,
300
310
  executionId: string,
301
- scope = Scope.makeUnsafe()
311
+ options?: {
312
+ readonly scope?: Scope.Closeable | undefined
313
+ /**
314
+ * Awaited deferred names shared with the run this instance belongs to.
315
+ * An activity instance registers its durable waits there so the run
316
+ * can be woken once it suspends, without those waits preempting it.
317
+ */
318
+ readonly awaitedDeferreds?: Map<string, number> | undefined
319
+ }
302
320
  ): WorkflowInstance["Service"] {
303
321
  return WorkflowInstance.of({
304
322
  executionId,
305
323
  workflow,
306
- scope,
324
+ scope: options?.scope ?? Scope.makeUnsafe(),
307
325
  suspended: false,
308
326
  interrupted: false,
309
327
  abandoned: false,
310
328
  cause: undefined,
311
- awaitedDeferreds: new Map(),
329
+ failed: false,
330
+ awaitedDeferreds: options?.awaitedDeferreds ?? new Map(),
312
331
  completedDeferreds: new Set(),
313
332
  activityState: {
314
333
  count: 0,
@@ -406,6 +425,8 @@ export interface Encoded {
406
425
  readonly payload: object
407
426
  readonly discard: Discard
408
427
  readonly parent?: WorkflowInstance["Service"] | undefined
428
+ /** Skip parent completion wakes and interruption linkage. */
429
+ readonly detached?: boolean | undefined
409
430
  }
410
431
  ) => Effect.Effect<
411
432
  Discard extends true ? void : Workflow.Result<unknown, unknown>
@@ -514,11 +535,15 @@ export const makeUnsafe = (options: Encoded): WorkflowEngine["Service"] =>
514
535
  readonly executionId: string
515
536
  readonly payload: Payload["Type"]
516
537
  readonly discard?: Discard | undefined
538
+ readonly detached?: boolean | undefined
517
539
  readonly suspendedRetrySchedule?:
518
540
  | Schedule.Schedule<any, unknown>
519
541
  | undefined
520
542
  }
521
543
  ) {
544
+ if (opts.detached && !opts.discard) {
545
+ return yield* Effect.die(`${self._tag}.execute: detached requires discard`)
546
+ }
522
547
  const payload = opts.payload
523
548
  const executionId = opts.executionId
524
549
  const suspendedRetrySchedule = opts.suspendedRetrySchedule ?? defaultRetrySchedule
@@ -527,7 +552,7 @@ export const makeUnsafe = (options: Encoded): WorkflowEngine["Service"] =>
527
552
 
528
553
  // link interruption with parent workflow
529
554
  const parentInstance = yield* Effect.serviceOption(WorkflowInstance)
530
- if (Option.isSome(parentInstance)) {
555
+ if (Option.isSome(parentInstance) && !opts.detached) {
531
556
  const instance = parentInstance.value
532
557
  yield* Effect.addFinalizer(() => {
533
558
  if (!instance.interrupted || (Option.isSome(result) && result.value._tag === "Complete")) {
@@ -540,7 +565,8 @@ export const makeUnsafe = (options: Encoded): WorkflowEngine["Service"] =>
540
565
  executionId,
541
566
  payload: payload as object,
542
567
  discard: opts.discard ?? false,
543
- parent: Option.getOrUndefined(parentInstance)
568
+ parent: Option.getOrUndefined(parentInstance),
569
+ detached: opts.detached
544
570
  }) as Effect.Effect<Workflow.Result<Success["Type"], Error["Type"]>>
545
571
 
546
572
  if (opts.discard) {
@@ -675,6 +701,11 @@ const defaultRetrySchedule = Schedule.min([
675
701
  Schedule.spaced(30000)
676
702
  ])
677
703
 
704
+ type WakeMode = "explicit" | "automatic"
705
+
706
+ const isUnwakeable = (result: Workflow.Result<unknown, unknown>, mode: WakeMode) =>
707
+ result._tag === "Complete" || (mode === "automatic" && result.failed === true)
708
+
678
709
  /**
679
710
  * Layer that provides an in-memory `WorkflowEngine`.
680
711
  *
@@ -714,7 +745,8 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
714
745
  readonly parent: string | undefined
715
746
  instance: WorkflowInstance["Service"]
716
747
  interrupted: boolean
717
- resumeRequested: boolean
748
+ // The strongest wake requested while a run was still finishing.
749
+ resumeRequested: WakeMode | undefined
718
750
  fiber: Fiber.Fiber<Workflow.Result<unknown, unknown>> | undefined
719
751
  // Completed once a run succeeds with `Complete`, after which it cannot resume.
720
752
  readonly done: Deferred.Deferred<void>
@@ -728,21 +760,22 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
728
760
 
729
761
  const deferredState = makeDeferredState()
730
762
 
731
- const resume = Effect.fnUntraced(function*(executionId: string): Effect.fn.Return<void> {
763
+ const resume = Effect.fnUntraced(function*(executionId: string, mode: WakeMode): Effect.fn.Return<void> {
732
764
  const state = executions.get(executionId)
733
765
  if (!state) return
734
766
  const exit = state.fiber?.pollUnsafe()
735
- if (exit && exit._tag === "Success" && exit.value._tag === "Complete") {
767
+ if (exit && exit._tag === "Success" && isUnwakeable(exit.value, mode)) {
736
768
  return
737
769
  } else if (state.fiber && !exit) {
738
- // A child can finish while the parent is still releasing its activity.
739
- // Preserve the wake until that run has published its suspended result.
740
- if (!state.resumeRequested) {
741
- state.resumeRequested = true
770
+ // Queue wakes until the run finishes cleanup; explicit wakes take priority.
771
+ const requested = state.resumeRequested
772
+ state.resumeRequested = mode === "explicit" ? mode : requested ?? mode
773
+ if (requested === undefined) {
742
774
  yield* Fiber.await(state.fiber).pipe(
743
775
  Effect.flatMap(() => {
744
- state.resumeRequested = false
745
- return resume(executionId)
776
+ const mode = state.resumeRequested!
777
+ state.resumeRequested = undefined
778
+ return resume(executionId, mode)
746
779
  }),
747
780
  Effect.forkIn(scope)
748
781
  )
@@ -754,7 +787,7 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
754
787
  const instance = WorkflowInstance.initial(
755
788
  state.instance.workflow,
756
789
  state.instance.executionId,
757
- state.instance.scope
790
+ { scope: state.instance.scope }
758
791
  )
759
792
  state.instance = instance
760
793
  state.fiber = yield* state.execute(state.payload, state.instance.executionId).pipe(
@@ -773,7 +806,7 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
773
806
  if (!state.parent || result._tag !== "Complete") {
774
807
  return Effect.void
775
808
  }
776
- return Effect.forkIn(resume(state.parent), scope)
809
+ return Effect.forkIn(resume(state.parent, "automatic"), scope)
777
810
  }),
778
811
  Effect.onExit((exit) => {
779
812
  return Exit.isSuccess(exit) && exit.value._tag === "Complete"
@@ -809,13 +842,13 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
809
842
  execute: entry.execute,
810
843
  instance: WorkflowInstance.initial(workflow, options.executionId),
811
844
  interrupted: false,
812
- resumeRequested: false,
845
+ resumeRequested: undefined,
813
846
  fiber: undefined,
814
847
  done: Deferred.makeUnsafe(),
815
- parent: options.parent?.executionId
848
+ parent: options.detached ? undefined : options.parent?.executionId
816
849
  }
817
850
  executions.set(options.executionId, state)
818
- yield* resume(options.executionId)
851
+ yield* resume(options.executionId, "explicit")
819
852
  }
820
853
  if (options.discard) return
821
854
  // Capture together so a wake that swaps in a replay cannot desync them.
@@ -836,7 +869,7 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
836
869
  const state = executions.get(executionId)
837
870
  if (!state) return
838
871
  state.interrupted = true
839
- yield* resume(executionId)
872
+ yield* resume(executionId, "explicit")
840
873
  }),
841
874
  interruptUnsafe: Effect.fnUntraced(function*(_workflow, executionId) {
842
875
  const state = executions.get(executionId)
@@ -847,7 +880,7 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
847
880
  }
848
881
  }),
849
882
  resume(_workflow, executionId) {
850
- return resume(executionId)
883
+ return resume(executionId, "explicit")
851
884
  },
852
885
  activityExecute: Effect.fnUntraced(function*(activity, attempt) {
853
886
  const instance = yield* WorkflowInstance
@@ -864,6 +897,11 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
864
897
  state = { exit: undefined }
865
898
  activities.set(activityId, state)
866
899
  }
900
+ // A pending interrupt replays only to rebuild compensations, so it must
901
+ // not run new activities. Finalizers run once `interrupted` is set.
902
+ if (executions.get(instance.executionId)?.interrupted && !instance.interrupted) {
903
+ return new Workflow.Suspended({})
904
+ }
867
905
  const activityInstance = WorkflowInstance.initial(instance.workflow, instance.executionId)
868
906
  activityInstance.interrupted = instance.interrupted
869
907
  return yield* activity.executeEncoded.pipe(
@@ -902,7 +940,7 @@ export const layerMemory: Layer.Layer<WorkflowEngine> = Layer.effect(WorkflowEng
902
940
  deferredResults.set(id, options.exit)
903
941
  const wake = Effect.andThen(
904
942
  deferredState.deferredDone(options.executionId, options.deferredName),
905
- resume(options.executionId)
943
+ resume(options.executionId, "automatic")
906
944
  )
907
945
  return Effect.flatMap(Effect.serviceOption(WorkflowInstance), (instance) =>
908
946
  // A workflow finalizer cannot wait for its own run's cleanup.