@lostgradient/weft 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (579) hide show
  1. package/README.md +123 -43
  2. package/dist/cli/conformance.js +7 -1
  3. package/dist/cli/generated/operation-client.generated.d.ts +55 -13
  4. package/dist/cli/generated/operation-client.generated.js +3 -0
  5. package/dist/cli/help-text.d.ts +1 -1
  6. package/dist/cli/help-text.js +1 -0
  7. package/dist/cli/operation-catalog-snapshot.d.ts +8 -0
  8. package/dist/cli/operation-catalog-snapshot.js +11 -0
  9. package/dist/cli/parse-schedule-arguments.js +3 -1
  10. package/dist/cli/schedule.js +2 -1
  11. package/dist/cli/types.d.ts +1 -0
  12. package/dist/cli-main.js +80 -79
  13. package/dist/client/handle-delegation.d.ts +7 -2
  14. package/dist/client/handle-delegation.js +9 -1
  15. package/dist/client/http-client-requests.d.ts +4 -1
  16. package/dist/client/http-client-requests.js +10 -0
  17. package/dist/client/http-client.d.ts +10 -4
  18. package/dist/client/http-client.js +18 -1
  19. package/dist/client/http-request.d.ts +11 -1
  20. package/dist/client/http-request.js +17 -7
  21. package/dist/client/index.d.ts +1 -1
  22. package/dist/client/interface.d.ts +100 -4
  23. package/dist/client/local.d.ts +7 -1
  24. package/dist/client/local.js +17 -2
  25. package/dist/client/start-body.d.ts +9 -2
  26. package/dist/client/start-body.js +13 -4
  27. package/dist/core/byte-arrays.d.ts +5 -0
  28. package/dist/core/byte-arrays.js +5 -0
  29. package/dist/core/checkpoint/lifecycle.d.ts +3 -0
  30. package/dist/core/checkpoint/lifecycle.js +9 -4
  31. package/dist/core/checkpoint/serialization.js +12 -5
  32. package/dist/core/codec/extension-codec.d.ts +16 -0
  33. package/dist/core/codec/extension-codec.js +104 -8
  34. package/dist/core/codec/index.d.ts +1 -0
  35. package/dist/core/codec/index.js +1 -0
  36. package/dist/core/codec/serializer-registry.d.ts +122 -0
  37. package/dist/core/codec/serializer-registry.js +51 -0
  38. package/dist/core/context/activity-retry-state.d.ts +38 -0
  39. package/dist/core/context/activity-retry-state.js +89 -0
  40. package/dist/core/context/activity-schedule-to-close.d.ts +159 -0
  41. package/dist/core/context/activity-schedule-to-close.js +69 -0
  42. package/dist/core/context/child-workflow-pipe.d.ts +5 -5
  43. package/dist/core/context/child-workflow-pipe.js +15 -2
  44. package/dist/core/context/context-presence.d.ts +19 -0
  45. package/dist/core/context/context-presence.js +13 -0
  46. package/dist/core/context/durable-operations.d.ts +25 -0
  47. package/dist/core/context/durable-operations.js +64 -0
  48. package/dist/core/context/index.d.ts +18 -5
  49. package/dist/core/context/index.js +17 -12
  50. package/dist/core/context/internals.d.ts +29 -0
  51. package/dist/core/context/internals.js +6 -1
  52. package/dist/core/context/operation-request.d.ts +35 -0
  53. package/dist/core/context/parallel-cache-entry.d.ts +14 -5
  54. package/dist/core/context/run-operation.d.ts +21 -3
  55. package/dist/core/context/run-operation.js +56 -93
  56. package/dist/core/context/session-state.js +7 -8
  57. package/dist/core/context/speculative-child.js +2 -0
  58. package/dist/core/context/types.d.ts +15 -0
  59. package/dist/core/context/version-patching.d.ts +8 -0
  60. package/dist/core/context/version-patching.js +40 -0
  61. package/dist/core/context/workflow-logger.d.ts +98 -0
  62. package/dist/core/context/workflow-logger.js +68 -0
  63. package/dist/core/engine/activity-heartbeat-tracking.d.ts +64 -0
  64. package/dist/core/engine/activity-heartbeat-tracking.js +42 -0
  65. package/dist/core/engine/activity-per-attempt-timeout.d.ts +41 -0
  66. package/dist/core/engine/activity-per-attempt-timeout.js +36 -0
  67. package/dist/core/engine/activity-reconciliation.d.ts +1 -0
  68. package/dist/core/engine/activity-reconciliation.js +12 -1
  69. package/dist/core/engine/activity-resolution.d.ts +23 -0
  70. package/dist/core/engine/activity-resolution.js +37 -0
  71. package/dist/core/engine/aggregate.js +66 -30
  72. package/dist/core/engine/async-activity-completion.d.ts +23 -6
  73. package/dist/core/engine/async-activity-completion.js +53 -12
  74. package/dist/core/engine/attributes-tags.js +9 -4
  75. package/dist/core/engine/bulk-operations-purge.d.ts +26 -0
  76. package/dist/core/engine/bulk-operations-purge.js +38 -3
  77. package/dist/core/engine/bulk-operations-shared.d.ts +2 -0
  78. package/dist/core/engine/bulk-operations-shared.js +8 -2
  79. package/dist/core/engine/bulk-operations.d.ts +4 -1
  80. package/dist/core/engine/bulk-operations.js +235 -24
  81. package/dist/core/engine/callback-creators-bundles.d.ts +9 -0
  82. package/dist/core/engine/callback-creators-bundles.js +30 -2
  83. package/dist/core/engine/callback-creators-core.js +6 -4
  84. package/dist/core/engine/callback-creators-router.js +10 -0
  85. package/dist/core/engine/callback-creators-schedule.d.ts +2 -2
  86. package/dist/core/engine/callback-creators-schedule.js +12 -8
  87. package/dist/core/engine/candidate-read-batching.d.ts +6 -0
  88. package/dist/core/engine/candidate-read-batching.js +1 -0
  89. package/dist/core/engine/checkpoint-io.js +61 -25
  90. package/dist/core/engine/checkpoint-reads.js +3 -2
  91. package/dist/core/engine/checkpoint-replay.d.ts +20 -0
  92. package/dist/core/engine/checkpoint-replay.js +242 -0
  93. package/dist/core/engine/checkpoint-side-effects.d.ts +23 -0
  94. package/dist/core/engine/checkpoint-side-effects.js +35 -0
  95. package/dist/core/engine/child-workflow-cancellation.d.ts +10 -0
  96. package/dist/core/engine/child-workflow-cancellation.js +40 -0
  97. package/dist/core/engine/child-workflow.js +27 -4
  98. package/dist/core/engine/condition-waiters.d.ts +14 -0
  99. package/dist/core/engine/condition-waiters.js +5 -0
  100. package/dist/core/engine/construction.d.ts +3 -1
  101. package/dist/core/engine/construction.js +30 -8
  102. package/dist/core/engine/coordination-branch-executors.d.ts +70 -0
  103. package/dist/core/engine/coordination-branch-executors.js +107 -0
  104. package/dist/core/engine/deferred-consume-envelope.d.ts +59 -0
  105. package/dist/core/engine/deferred-consume-envelope.js +14 -0
  106. package/dist/core/engine/disposal.js +25 -0
  107. package/dist/core/engine/engine-create-types.d.ts +14 -18
  108. package/dist/core/engine/engine-internal-types.d.ts +38 -3
  109. package/dist/core/engine/engine-leak-warnings.d.ts +6 -0
  110. package/dist/core/engine/engine-leak-warnings.js +4 -0
  111. package/dist/core/engine/engine-runtime-helpers.d.ts +17 -0
  112. package/dist/core/engine/engine-runtime-helpers.js +26 -5
  113. package/dist/core/engine/errors.d.ts +121 -0
  114. package/dist/core/engine/errors.js +45 -1
  115. package/dist/core/engine/event-log-compaction.d.ts +8 -0
  116. package/dist/core/engine/event-log-compaction.js +20 -2
  117. package/dist/core/engine/fenced-write.d.ts +65 -0
  118. package/dist/core/engine/fenced-write.js +71 -0
  119. package/dist/core/engine/finalizer-state.d.ts +28 -0
  120. package/dist/core/engine/finalizer-state.js +16 -0
  121. package/dist/core/engine/handle-result.js +1 -1
  122. package/dist/core/engine/handles.d.ts +97 -40
  123. package/dist/core/engine/handles.js +25 -27
  124. package/dist/core/engine/index.d.ts +125 -15
  125. package/dist/core/engine/index.js +207 -11
  126. package/dist/core/engine/inline-launch-queue.d.ts +14 -0
  127. package/dist/core/engine/inline-launch-queue.js +32 -7
  128. package/dist/core/engine/inline-parking.js +3 -2
  129. package/dist/core/engine/internals.d.ts +125 -13
  130. package/dist/core/engine/lease-codec.d.ts +35 -0
  131. package/dist/core/engine/lease-codec.js +32 -0
  132. package/dist/core/engine/lease-deposition.d.ts +66 -0
  133. package/dist/core/engine/lease-deposition.js +10 -0
  134. package/dist/core/engine/lease-errors.d.ts +99 -0
  135. package/dist/core/engine/lease-errors.js +30 -0
  136. package/dist/core/engine/lease-manager.d.ts +114 -0
  137. package/dist/core/engine/lease-manager.js +135 -0
  138. package/dist/core/engine/lifecycle/fork-helpers.js +1 -7
  139. package/dist/core/engine/lifecycle/persist.js +15 -52
  140. package/dist/core/engine/lifecycle/recovered-services.d.ts +8 -6
  141. package/dist/core/engine/lifecycle/recovered-services.js +18 -3
  142. package/dist/core/engine/lifecycle/resume.js +39 -11
  143. package/dist/core/engine/lifecycle/shared.d.ts +8 -1
  144. package/dist/core/engine/lifecycle/start-batch.d.ts +1 -1
  145. package/dist/core/engine/lifecycle/start-batch.js +2 -1
  146. package/dist/core/engine/lifecycle/start-commit.d.ts +56 -0
  147. package/dist/core/engine/lifecycle/start-commit.js +69 -0
  148. package/dist/core/engine/lifecycle/start-exec.d.ts +30 -2
  149. package/dist/core/engine/lifecycle/start-exec.js +38 -0
  150. package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +58 -0
  151. package/dist/core/engine/lifecycle/start-or-signal-create.js +95 -0
  152. package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +79 -0
  153. package/dist/core/engine/lifecycle/start-or-signal-resolution.js +60 -0
  154. package/dist/core/engine/lifecycle/start-or-signal.d.ts +46 -0
  155. package/dist/core/engine/lifecycle/start-or-signal.js +71 -0
  156. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +39 -0
  157. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +28 -0
  158. package/dist/core/engine/lifecycle/start.d.ts +6 -6
  159. package/dist/core/engine/lifecycle/start.js +47 -45
  160. package/dist/core/engine/lifecycle/transition.js +17 -5
  161. package/dist/core/engine/lifecycle.d.ts +3 -2
  162. package/dist/core/engine/lifecycle.js +9 -2
  163. package/dist/core/engine/list-candidate-resolution.js +2 -2
  164. package/dist/core/engine/listing.js +10 -6
  165. package/dist/core/engine/operations-activity.d.ts +4 -11
  166. package/dist/core/engine/operations-activity.js +22 -49
  167. package/dist/core/engine/operations-coordination.d.ts +10 -0
  168. package/dist/core/engine/operations-coordination.js +43 -8
  169. package/dist/core/engine/operations-router.d.ts +6 -0
  170. package/dist/core/engine/operations-router.js +2 -0
  171. package/dist/core/engine/operations-speculate.js +6 -2
  172. package/dist/core/engine/operations-stream.js +12 -2
  173. package/dist/core/engine/operations-time.d.ts +4 -2
  174. package/dist/core/engine/operations-time.js +14 -2
  175. package/dist/core/engine/operations-wait-condition.d.ts +23 -0
  176. package/dist/core/engine/operations-wait-condition.js +62 -0
  177. package/dist/core/engine/ownership-options.d.ts +23 -0
  178. package/dist/core/engine/ownership-options.js +26 -0
  179. package/dist/core/engine/payload-size-policy.d.ts +3 -0
  180. package/dist/core/engine/payload-size-policy.js +4 -0
  181. package/dist/core/engine/pending-updates.d.ts +17 -0
  182. package/dist/core/engine/pending-updates.js +33 -11
  183. package/dist/core/engine/persisted-data-version.d.ts +5 -9
  184. package/dist/core/engine/persisted-data-version.js +4 -5
  185. package/dist/core/engine/queries.js +1 -1
  186. package/dist/core/engine/registration.d.ts +1 -0
  187. package/dist/core/engine/registration.js +18 -3
  188. package/dist/core/engine/schedule-handle.d.ts +45 -0
  189. package/dist/core/engine/schedule-handle.js +26 -0
  190. package/dist/core/engine/schedule-jitter.d.ts +5 -0
  191. package/dist/core/engine/schedule-jitter.js +10 -0
  192. package/dist/core/engine/schedule-run.d.ts +17 -0
  193. package/dist/core/engine/schedule-run.js +38 -0
  194. package/dist/core/engine/schedule-timer.js +81 -17
  195. package/dist/core/engine/schedules.d.ts +8 -5
  196. package/dist/core/engine/schedules.js +44 -19
  197. package/dist/core/engine/search-attribute-records.d.ts +4 -0
  198. package/dist/core/engine/search-attribute-records.js +17 -0
  199. package/dist/core/engine/second-instance-detector.d.ts +96 -0
  200. package/dist/core/engine/second-instance-detector.js +108 -0
  201. package/dist/core/engine/signals.d.ts +38 -0
  202. package/dist/core/engine/signals.js +55 -19
  203. package/dist/core/engine/state-utilities.d.ts +49 -2
  204. package/dist/core/engine/state-utilities.js +114 -3
  205. package/dist/core/engine/storage-io.d.ts +16 -2
  206. package/dist/core/engine/storage-io.js +26 -5
  207. package/dist/core/engine/stream-chunk-loading.d.ts +2 -0
  208. package/dist/core/engine/stream-chunk-loading.js +24 -1
  209. package/dist/core/engine/sub-operation.js +22 -3
  210. package/dist/core/engine/termination/cleanup.d.ts +28 -1
  211. package/dist/core/engine/termination/cleanup.js +44 -2
  212. package/dist/core/engine/termination/complete.js +48 -9
  213. package/dist/core/engine/termination/finalizer-activity.d.ts +53 -0
  214. package/dist/core/engine/termination/finalizer-activity.js +30 -0
  215. package/dist/core/engine/termination/finalizer-claim.d.ts +110 -0
  216. package/dist/core/engine/termination/finalizer-claim.js +80 -0
  217. package/dist/core/engine/termination/finalizer.d.ts +48 -0
  218. package/dist/core/engine/termination/finalizer.js +159 -0
  219. package/dist/core/engine/termination/suspend.d.ts +70 -0
  220. package/dist/core/engine/termination/suspend.js +41 -0
  221. package/dist/core/engine/termination.d.ts +5 -2
  222. package/dist/core/engine/termination.js +6 -0
  223. package/dist/core/engine/updates.js +5 -25
  224. package/dist/core/engine/validation/schedule.d.ts +2 -1
  225. package/dist/core/engine/validation/schedule.js +51 -2
  226. package/dist/core/engine/validation.js +54 -3
  227. package/dist/core/engine/waiting-update-response.d.ts +8 -0
  228. package/dist/core/engine/waiting-update-response.js +22 -0
  229. package/dist/core/engine/workflow-concurrency.d.ts +10 -0
  230. package/dist/core/engine/workflow-concurrency.js +136 -0
  231. package/dist/core/engine/workflow-feed.d.ts +9 -8
  232. package/dist/core/engine/workflow-feed.js +4 -1
  233. package/dist/core/engine/workflow-indexes.d.ts +9 -0
  234. package/dist/core/engine/workflow-indexes.js +10 -0
  235. package/dist/core/engine/workflow-state-stream.js +33 -13
  236. package/dist/core/engine/workflow-visibility-queries.d.ts +2 -2
  237. package/dist/core/engine-helpers.js +1 -0
  238. package/dist/core/events/activity-events.d.ts +43 -12
  239. package/dist/core/events/activity-events.js +28 -0
  240. package/dist/core/events/attribute-events.d.ts +2 -3
  241. package/dist/core/events/event-map.d.ts +19 -12
  242. package/dist/core/events/index.d.ts +1 -0
  243. package/dist/core/events/index.js +1 -0
  244. package/dist/core/events/schedule-events.d.ts +71 -0
  245. package/dist/core/events/schedule-events.js +29 -0
  246. package/dist/core/events/signal-events.d.ts +4 -6
  247. package/dist/core/events/system-events.d.ts +29 -19
  248. package/dist/core/events/system-events.js +26 -0
  249. package/dist/core/events/update-events.d.ts +6 -8
  250. package/dist/core/events/workflow-events.d.ts +108 -20
  251. package/dist/core/events/workflow-events.js +35 -0
  252. package/dist/core/failure-categories.js +5 -17
  253. package/dist/core/fault-code.d.ts +9 -3
  254. package/dist/core/fault-code.js +1 -0
  255. package/dist/core/inline-execution-strategy.context-options.d.ts +69 -0
  256. package/dist/core/inline-execution-strategy.context-options.js +56 -0
  257. package/dist/core/inline-execution-strategy.d.ts +31 -36
  258. package/dist/core/inline-execution-strategy.js +16 -27
  259. package/dist/core/list-filter-validation.d.ts +1 -1
  260. package/dist/core/list-filter-validation.js +2 -1
  261. package/dist/core/payload-size.d.ts +1 -1
  262. package/dist/core/persisted-data-incompatible-error.d.ts +9 -7
  263. package/dist/core/review/events.d.ts +6 -8
  264. package/dist/core/scheduler/scheduler-class.d.ts +10 -1
  265. package/dist/core/scheduler/scheduler-class.js +38 -11
  266. package/dist/core/scheduler/timer-batch.js +9 -1
  267. package/dist/core/scheduler/timer-sources.d.ts +1 -0
  268. package/dist/core/scheduler/timer-sources.js +11 -5
  269. package/dist/core/session-state.d.ts +0 -1
  270. package/dist/core/session-state.js +2 -2
  271. package/dist/core/start-workflow-validation.d.ts +56 -0
  272. package/dist/core/start-workflow-validation.js +30 -1
  273. package/dist/core/step-context.d.ts +10 -6
  274. package/dist/core/step-context.js +7 -15
  275. package/dist/core/types/activity-verification.d.ts +67 -0
  276. package/dist/core/types/activity-verification.js +0 -0
  277. package/dist/core/types/activity.d.ts +86 -64
  278. package/dist/core/types/bulk.d.ts +50 -9
  279. package/dist/core/types/checkpoint.d.ts +44 -8
  280. package/dist/core/types/identity.d.ts +8 -1
  281. package/dist/core/types/launch-metadata.d.ts +33 -0
  282. package/dist/core/types/launch-metadata.js +0 -0
  283. package/dist/core/types/list-options.d.ts +146 -0
  284. package/dist/core/types/list-options.js +0 -0
  285. package/dist/core/types/message-handles.d.ts +25 -0
  286. package/dist/core/types/options.d.ts +165 -215
  287. package/dist/core/types/reviews.d.ts +2 -1
  288. package/dist/core/types/schedules.d.ts +39 -3
  289. package/dist/core/types/services-resolution.d.ts +47 -0
  290. package/dist/core/types/services-resolution.js +0 -0
  291. package/dist/core/types/state.d.ts +11 -11
  292. package/dist/core/types/workflow-builder-runtime.d.ts +12 -3
  293. package/dist/core/types/workflow-builder-runtime.js +11 -2
  294. package/dist/core/types/workflow-builder.d.ts +47 -15
  295. package/dist/core/types/workflow-concurrency.d.ts +39 -0
  296. package/dist/core/types/workflow-concurrency.js +0 -0
  297. package/dist/core/types/workflow-context.d.ts +157 -14
  298. package/dist/core/types/workflow-definition.d.ts +53 -10
  299. package/dist/core/types/workflow-function.d.ts +101 -9
  300. package/dist/core/types/workflow-log.d.ts +98 -0
  301. package/dist/core/types/workflow-log.js +0 -0
  302. package/dist/core/types/workflow-registries.d.ts +14 -3
  303. package/dist/core/types/workflow-registry.d.ts +3 -0
  304. package/dist/core/types/workflow-snapshot.d.ts +29 -0
  305. package/dist/core/types/workflow-snapshot.js +0 -0
  306. package/dist/core/types.d.ts +7 -0
  307. package/dist/core/types.js +7 -0
  308. package/dist/core/versioning.d.ts +9 -39
  309. package/dist/core/versioning.js +2 -12
  310. package/dist/core/weft-error.d.ts +44 -1
  311. package/dist/core/weft-error.js +19 -1
  312. package/dist/core/worker-execution-strategy-options.d.ts +26 -0
  313. package/dist/core/worker-execution-strategy.js +40 -36
  314. package/dist/core/worker-inbound-message.d.ts +38 -0
  315. package/dist/core/worker-inbound-message.js +37 -0
  316. package/dist/core/worker-log-abuse-counter.d.ts +175 -0
  317. package/dist/core/worker-log-abuse-counter.js +107 -0
  318. package/dist/core/worker-message-helpers.d.ts +47 -0
  319. package/dist/core/worker-message-helpers.js +26 -0
  320. package/dist/core/worker-protocol-guard.js +1 -1
  321. package/dist/core/worker-protocol-log.d.ts +56 -0
  322. package/dist/core/worker-protocol-log.js +18 -0
  323. package/dist/core/worker-protocol.d.ts +23 -0
  324. package/dist/core/worker-protocol.js +12 -2
  325. package/dist/core/workflow-version-tuple.d.ts +3 -9
  326. package/dist/core/workflow-version-tuple.js +2 -3
  327. package/dist/diagnostics/doctor.js +6 -3
  328. package/dist/diagnostics/format.js +3 -8
  329. package/dist/diagnostics/types.d.ts +5 -5
  330. package/dist/diagnostics/validate.d.ts +0 -1
  331. package/dist/diagnostics/version-check.d.ts +1 -1
  332. package/dist/diagnostics/version-check.js +10 -13
  333. package/dist/index.d.ts +13 -11
  334. package/dist/index.js +39 -4
  335. package/dist/json-schema.js +3 -3
  336. package/dist/mcp/cli.js +35 -35
  337. package/dist/mcp/dispatcher.js +1 -1
  338. package/dist/mcp/http.js +16 -6
  339. package/dist/mcp/list-filter.js +2 -1
  340. package/dist/mcp/protocol.d.ts +2 -0
  341. package/dist/mcp/protocol.js +1 -1
  342. package/dist/mcp/session.d.ts +16 -0
  343. package/dist/mcp/session.js +60 -6
  344. package/dist/mcp/tools.js +73 -6
  345. package/dist/observability/index.js +2 -2
  346. package/dist/server/asyncapi-channels.js +5 -2
  347. package/dist/server/attribute-filters.d.ts +8 -3
  348. package/dist/server/attribute-filters.js +6 -1
  349. package/dist/server/authentication/api-key.d.ts +2 -1
  350. package/dist/server/authentication/api-key.js +5 -2
  351. package/dist/server/authentication/constant-time-api-key.d.ts +15 -0
  352. package/dist/server/authentication/constant-time-api-key.js +24 -0
  353. package/dist/server/authentication/index.d.ts +1 -1
  354. package/dist/server/authentication/index.js +7 -4
  355. package/dist/server/authentication/rotating-api-key-store.d.ts +5 -3
  356. package/dist/server/authentication/rotating-api-key-store.js +19 -11
  357. package/dist/server/engine-event-feed-backend.d.ts +4 -5
  358. package/dist/server/fault-to-http.js +8 -1
  359. package/dist/server/fault-to-json-rpc.js +1 -0
  360. package/dist/server/fleet-event-feed.d.ts +31 -0
  361. package/dist/server/fleet-event-feed.js +157 -0
  362. package/dist/server/handler/index.js +1 -1
  363. package/dist/server/handler/response-helpers.js +2 -1
  364. package/dist/server/handler/route-dispatch.d.ts +6 -3
  365. package/dist/server/handler/route-dispatch.js +2 -2
  366. package/dist/server/handler.js +31 -31
  367. package/dist/server/index.d.ts +32 -2
  368. package/dist/server/index.js +35 -35
  369. package/dist/server/interactive-operations.js +1 -0
  370. package/dist/server/json-rpc-transport-helpers.d.ts +1 -0
  371. package/dist/server/json-rpc-transport-helpers.js +2 -1
  372. package/dist/server/json-rpc-websocket-runtime.d.ts +11 -2
  373. package/dist/server/json-rpc-websocket-runtime.js +1 -0
  374. package/dist/server/json-rpc-websocket-subscriptions.d.ts +10 -0
  375. package/dist/server/json-rpc-websocket-subscriptions.js +29 -0
  376. package/dist/server/json-rpc-websocket-types.d.ts +22 -0
  377. package/dist/server/json-rpc-websocket-types.js +0 -0
  378. package/dist/server/json-rpc-websocket-validation.js +20 -4
  379. package/dist/server/json-rpc-websocket.d.ts +2 -43
  380. package/dist/server/json-rpc-websocket.js +57 -74
  381. package/dist/server/openapi.d.ts +2 -1
  382. package/dist/server/openapi.js +1 -3
  383. package/dist/server/openrpc-document-schema.d.ts +78 -0
  384. package/dist/server/openrpc-document-schema.js +27 -1
  385. package/dist/server/openrpc-errors.d.ts +3 -0
  386. package/dist/server/openrpc-errors.js +2 -1
  387. package/dist/server/openrpc.js +32 -0
  388. package/dist/server/operation-catalog/index.d.ts +1 -1
  389. package/dist/server/operation-catalog/pipeline-helpers.js +1 -0
  390. package/dist/server/operation-catalog/pipeline-stages.js +26 -12
  391. package/dist/server/operation-catalog/pipeline.js +8 -1
  392. package/dist/server/operation-catalog/registry.js +13 -0
  393. package/dist/server/operation-catalog/types.d.ts +20 -9
  394. package/dist/server/operation-fault.d.ts +10 -0
  395. package/dist/server/operation-fault.js +2 -0
  396. package/dist/server/operation-registry.d.ts +12 -11
  397. package/dist/server/operation-registry.js +12 -3
  398. package/dist/server/operations/aggregate-workflows.d.ts +15 -15
  399. package/dist/server/operations/async-activity.d.ts +2 -2
  400. package/dist/server/operations/async-activity.js +12 -7
  401. package/dist/server/operations/bulk-cancel-workflows.d.ts +1 -1
  402. package/dist/server/operations/bulk-cancel-workflows.js +2 -2
  403. package/dist/server/operations/bulk-delete-workflows.d.ts +1 -1
  404. package/dist/server/operations/bulk-delete-workflows.js +2 -2
  405. package/dist/server/operations/bulk-filter-helpers.d.ts +8 -6
  406. package/dist/server/operations/bulk-filter-helpers.js +54 -24
  407. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +11 -9
  408. package/dist/server/operations/bulk-mutate-workflow-tags.js +2 -2
  409. package/dist/server/operations/bulk-operation-helpers.d.ts +2 -2
  410. package/dist/server/operations/bulk-retry-failed-workflows.d.ts +7 -0
  411. package/dist/server/operations/bulk-retry-failed-workflows.js +64 -0
  412. package/dist/server/operations/bulk-signal-workflows.d.ts +11 -9
  413. package/dist/server/operations/bulk-signal-workflows.js +2 -2
  414. package/dist/server/operations/cancel-schedule.d.ts +1 -1
  415. package/dist/server/operations/create-schedule.d.ts +3 -1
  416. package/dist/server/operations/create-schedule.js +29 -11
  417. package/dist/server/operations/fleet-events-subscription.d.ts +54 -0
  418. package/dist/server/operations/fleet-events-subscription.js +99 -0
  419. package/dist/server/operations/fork-workflow.d.ts +1 -1
  420. package/dist/server/operations/fork-workflow.js +3 -2
  421. package/dist/server/operations/get-checkpoint-at.d.ts +1 -1
  422. package/dist/server/operations/get-registry.d.ts +1 -1
  423. package/dist/server/operations/get-retention-overview.d.ts +1 -1
  424. package/dist/server/operations/get-review.d.ts +1 -1
  425. package/dist/server/operations/get-schedule.d.ts +1 -1
  426. package/dist/server/operations/get-stream-chunks.d.ts +1 -1
  427. package/dist/server/operations/get-system-metrics.d.ts +2 -2
  428. package/dist/server/operations/get-task-diagnostics.d.ts +45 -6
  429. package/dist/server/operations/get-task-diagnostics.js +101 -7
  430. package/dist/server/operations/get-update-result.d.ts +1 -1
  431. package/dist/server/operations/get-workflow-attributes.d.ts +1 -1
  432. package/dist/server/operations/get-workflow-events.d.ts +1 -1
  433. package/dist/server/operations/get-workflow-result.d.ts +1 -1
  434. package/dist/server/operations/get-workflow-timeline.d.ts +1 -1
  435. package/dist/server/operations/get-workflow.d.ts +1 -1
  436. package/dist/server/operations/list-checkpoints.d.ts +1 -1
  437. package/dist/server/operations/list-reviews.d.ts +1 -1
  438. package/dist/server/operations/list-schedules.d.ts +1 -1
  439. package/dist/server/operations/list-task-queues.d.ts +2 -2
  440. package/dist/server/operations/list-workers.d.ts +2 -2
  441. package/dist/server/operations/list-workflows.d.ts +1 -1
  442. package/dist/server/operations/operation-helpers.d.ts +16 -1
  443. package/dist/server/operations/operation-helpers.js +15 -3
  444. package/dist/server/operations/pause-schedule.d.ts +1 -1
  445. package/dist/server/operations/purge-workflows.d.ts +5 -5
  446. package/dist/server/operations/purge-workflows.js +2 -2
  447. package/dist/server/operations/query-workflow.d.ts +1 -1
  448. package/dist/server/operations/query-workflow.js +3 -2
  449. package/dist/server/operations/recover-all.d.ts +1 -1
  450. package/dist/server/operations/replay-workflow.d.ts +1 -1
  451. package/dist/server/operations/resume-schedule.d.ts +1 -1
  452. package/dist/server/operations/resume-workflow.js +2 -2
  453. package/dist/server/operations/set-workflow-attributes.d.ts +1 -1
  454. package/dist/server/operations/set-workflow-attributes.js +6 -3
  455. package/dist/server/operations/signal-workflow.js +8 -3
  456. package/dist/server/operations/single-workflow-tag-mutation.js +13 -3
  457. package/dist/server/operations/start-or-signal-workflow.d.ts +44 -0
  458. package/dist/server/operations/start-or-signal-workflow.js +130 -0
  459. package/dist/server/operations/start-workflow-options.d.ts +38 -0
  460. package/dist/server/operations/start-workflow-options.js +63 -0
  461. package/dist/server/operations/start-workflow-rest-input.d.ts +14 -0
  462. package/dist/server/operations/start-workflow-rest-input.js +31 -0
  463. package/dist/server/operations/start-workflow.d.ts +1 -1
  464. package/dist/server/operations/start-workflow.js +15 -92
  465. package/dist/server/operations/storage.d.ts +6 -6
  466. package/dist/server/operations/storage.js +24 -14
  467. package/dist/server/operations/stream-workflow-sse.d.ts +1 -1
  468. package/dist/server/operations/submit-review-decision.d.ts +1 -1
  469. package/dist/server/operations/submit-review-decision.js +6 -3
  470. package/dist/server/operations/suspend-workflow.d.ts +13 -0
  471. package/dist/server/operations/suspend-workflow.js +36 -0
  472. package/dist/server/operations/update-schedule.d.ts +1 -1
  473. package/dist/server/operations/update-schedule.js +7 -4
  474. package/dist/server/operations/update-workflow.d.ts +1 -1
  475. package/dist/server/operations/update-workflow.js +7 -3
  476. package/dist/server/operations/worker-drain.d.ts +8 -8
  477. package/dist/server/operations/worker-drain.js +11 -8
  478. package/dist/server/operations/workflow-events-subscription.d.ts +7 -8
  479. package/dist/server/operations/workflow-events-subscription.js +43 -8
  480. package/dist/server/rest-binding.d.ts +21 -8
  481. package/dist/server/rest-bindings.js +24 -0
  482. package/dist/server/rest-body.d.ts +10 -0
  483. package/dist/server/rest-body.js +80 -0
  484. package/dist/server/runtime/authentication-bridge.d.ts +1 -0
  485. package/dist/server/runtime/authentication-bridge.js +33 -6
  486. package/dist/server/runtime/client-visible-events.d.ts +3 -0
  487. package/dist/server/runtime/client-visible-events.js +65 -0
  488. package/dist/server/runtime/context.d.ts +7 -0
  489. package/dist/server/runtime/event-broadcasting.d.ts +6 -0
  490. package/dist/server/runtime/event-broadcasting.js +72 -38
  491. package/dist/server/runtime/retry.d.ts +1 -0
  492. package/dist/server/runtime/retry.js +14 -0
  493. package/dist/server/runtime/shutdown.d.ts +7 -6
  494. package/dist/server/runtime/shutdown.js +6 -1
  495. package/dist/server/runtime/task-dispatch.js +5 -3
  496. package/dist/server/runtime/task-polling.d.ts +16 -2
  497. package/dist/server/runtime/task-polling.js +80 -24
  498. package/dist/server/runtime/task-reconciliation.js +9 -1
  499. package/dist/server/runtime/task-result-resolution.d.ts +15 -0
  500. package/dist/server/runtime/task-result-resolution.js +81 -0
  501. package/dist/server/runtime/websocket-stream.d.ts +20 -1
  502. package/dist/server/runtime/websocket-stream.js +173 -7
  503. package/dist/server/runtime/websocket-upgrade.js +22 -3
  504. package/dist/server/runtime/websocket-worker.d.ts +1 -1
  505. package/dist/server/runtime/websocket-worker.js +46 -30
  506. package/dist/server/serve-internals.d.ts +11 -1
  507. package/dist/server/serve-internals.js +20 -2
  508. package/dist/server/task-state.d.ts +38 -0
  509. package/dist/server/task-state.js +28 -0
  510. package/dist/server/workflow-event-feed.d.ts +36 -115
  511. package/dist/server/workflow-event-feed.js +92 -27
  512. package/dist/service-worker/index.js +31 -31
  513. package/dist/storage/auto.js +1 -1
  514. package/dist/storage/bun-sql.js +24 -0
  515. package/dist/storage/capabilities.d.ts +10 -2
  516. package/dist/storage/capabilities.js +2 -2
  517. package/dist/storage/compressed-storage.js +1 -1
  518. package/dist/storage/default-scope.d.ts +7 -4
  519. package/dist/storage/http.js +2 -2
  520. package/dist/storage/index.d.ts +81 -4
  521. package/dist/storage/indexeddb.js +1 -1
  522. package/dist/storage/interface.d.ts +189 -0
  523. package/dist/storage/interface.js +1 -1
  524. package/dist/storage/key-prefixes.d.ts +1 -1
  525. package/dist/storage/key-prefixes.js +12 -0
  526. package/dist/storage/lmdb.d.ts +4 -3
  527. package/dist/storage/lmdb.js +1 -1
  528. package/dist/storage/memory.js +1 -1
  529. package/dist/storage/neon-batch.d.ts +30 -0
  530. package/dist/storage/neon-batch.js +30 -0
  531. package/dist/storage/neon-value-mapping.d.ts +74 -0
  532. package/dist/storage/neon-value-mapping.js +23 -0
  533. package/dist/storage/neon.d.ts +124 -0
  534. package/dist/storage/neon.js +15 -0
  535. package/dist/storage/node-sqlite-loader.d.ts +71 -0
  536. package/dist/storage/node-sqlite-loader.js +41 -0
  537. package/dist/storage/node-sqlite.d.ts +1 -19
  538. package/dist/storage/node-sqlite.js +61 -32
  539. package/dist/storage/postgres-key-value-queries.d.ts +104 -0
  540. package/dist/storage/postgres-key-value-queries.js +101 -0
  541. package/dist/storage/resolve.d.ts +2 -165
  542. package/dist/storage/resolve.js +1 -1
  543. package/dist/storage/scoped-storage.js +1 -1
  544. package/dist/storage/storage-configuration.d.ts +209 -0
  545. package/dist/storage/storage-configuration.js +0 -0
  546. package/dist/storage/testing.d.ts +168 -0
  547. package/dist/storage/testing.js +2 -0
  548. package/dist/storage/text-value-store.d.ts +9 -9
  549. package/dist/storage/turso.d.ts +8 -0
  550. package/dist/storage/turso.js +2 -2
  551. package/dist/storage/typed-storage.js +1 -1
  552. package/dist/storage/web-extension.js +1 -1
  553. package/dist/testing/index.js +35 -35
  554. package/dist/version.d.ts +1 -1
  555. package/dist/version.js +1 -1
  556. package/dist/worker/index.js +9 -5
  557. package/dist/worker/long-poll.js +4 -0
  558. package/dist/worker/protocol-messages.d.ts +20 -0
  559. package/dist/worker/protocol-schemas.d.ts +32 -0
  560. package/dist/worker/protocol-schemas.js +8 -4
  561. package/dist/worker/protocol-task-result.d.ts +28 -0
  562. package/dist/worker/protocol-task-result.js +76 -0
  563. package/dist/worker/protocol.d.ts +4 -15
  564. package/dist/worker/protocol.js +1 -1
  565. package/dist/worker/registry/fair-share.d.ts +29 -0
  566. package/dist/worker/registry/fair-share.js +30 -0
  567. package/dist/worker/registry/routing.d.ts +18 -0
  568. package/dist/worker/registry/routing.js +14 -0
  569. package/dist/worker/registry/types.d.ts +7 -0
  570. package/dist/worker/registry.d.ts +16 -1
  571. package/dist/worker/registry.js +24 -36
  572. package/dist/workers/worker-replay-state.d.ts +32 -0
  573. package/dist/workers/worker-replay-state.js +35 -0
  574. package/dist/workers/worker-state-namespace.d.ts +21 -0
  575. package/dist/workers/worker-state-namespace.js +13 -0
  576. package/dist/workers/workflow-runner.d.ts +19 -15
  577. package/dist/workers/workflow-runner.js +72 -60
  578. package/dist/workers/workflow-worker-entry.js +5 -2
  579. package/package.json +21 -4
@@ -0,0 +1,175 @@
1
+ import type { FailureCategory } from './types.ts';
2
+ import type { WorkflowLogRecord } from './types/workflow-log.ts';
3
+ import type { WorkerExecutionStrategyOptions } from './worker-execution-strategy-options.ts';
4
+ import { type ForwardedWorkerLogOutcome } from './worker-message-helpers.ts';
5
+ import type { WorkerLogMessageCandidate } from './worker-protocol-log.ts';
6
+ /**
7
+ * The verdict the abuse counter returns after recording one forwarded-log outcome:
8
+ * whether the strategy should DISCARD the sending worker for sustained abuse.
9
+ * `'tolerate'` means a single anomaly or an in-budget burst that does not discard.
10
+ * `'discard'` means a threshold was crossed (flood within the window, or accumulated
11
+ * lifetime strikes) and the worker should be discarded as the hardened-worker threat
12
+ * model prescribes.
13
+ */
14
+ export type WorkerLogAbuseVerdict = 'tolerate' | 'discard';
15
+ /**
16
+ * Configuration for {@link WorkerLogAbuseCounter}. All three thresholds are internal:
17
+ * the engine fixes them to generous defaults rather than exposing operator tuning,
18
+ * because a false discard fails a real user's in-flight workflows (an asymmetric harm).
19
+ * The flood window/threshold are large so honest high-log workflows never trip them; the
20
+ * strike threshold is a small constant because oversize/invalid records are never produced
21
+ * by a well-behaved logger, so a handful in a worker's lifetime already signals abuse.
22
+ */
23
+ export interface WorkerLogAbuseCounterOptions {
24
+ /** Fixed/anchored window length in milliseconds for the flood budget. */
25
+ readonly floodWindowMs: number;
26
+ /**
27
+ * Maximum forwarded-log ARRIVALS tolerated per worker within `floodWindowMs`
28
+ * before the worker is discarded. Counts every `type:'log'` arrival for a worker
29
+ * — valid, oversize, invalid, or wrong-owner — because the host paid the clone
30
+ * cost on receipt regardless of the record's fate.
31
+ */
32
+ readonly floodThreshold: number;
33
+ /**
34
+ * Maximum cumulative anomalous (oversize OR invalid) records tolerated over a
35
+ * worker's whole lifetime before discard. NOT window-scoped and NOT reset, so a
36
+ * worker cannot evade by spacing anomalies across windows.
37
+ */
38
+ readonly strikeThreshold: number;
39
+ /** Monotonic-enough wall clock (ms), injected so tests advance time deterministically. */
40
+ readonly getNow: () => number;
41
+ }
42
+ /**
43
+ * Per-worker forwarded-log abuse accounting for the hardened worker path (#545).
44
+ *
45
+ * The #529 host-sink routing forwards a worker's `ctx.log` records to the engine's
46
+ * `EngineOptions.onLog` sink through a deliberately LENIENT lane that bypasses the
47
+ * strict turn watchdog, so a single malformed/oversize/wrong-owner log drops the
48
+ * record without discarding the worker. That leniency leaves two availability gaps
49
+ * a compromised or buggy worker can exploit:
50
+ *
51
+ * 1. **Flooding** — unlimited valid, in-budget logs apply host CPU / sink-buffer
52
+ * pressure without ever tripping the watchdog.
53
+ * 2. **Repeat oversize/invalid** — each forwarded log is structured-cloned by the
54
+ * runtime on receipt (a platform-inherent cost paid before any handler runs), so
55
+ * a worker can repeatedly force large/garbage allocations that the lenient lane
56
+ * then drops.
57
+ *
58
+ * This counter closes both by keeping per-worker state (keyed by the {@link Worker}
59
+ * reference in a {@link WeakMap}, so a discarded/GC'd worker's state is reclaimed
60
+ * automatically). It exposes two record paths the strategy calls and returns a
61
+ * {@link WorkerLogAbuseVerdict} telling the strategy whether to discard:
62
+ *
63
+ * - {@link recordArrival} is called for EVERY `type:'log'` message a worker sends,
64
+ * at the top of the log branch BEFORE the ownership gate — so a worker flooding
65
+ * logs for workflows it does not own is still counted (the host paid the clone
66
+ * cost). It drives the windowed flood budget.
67
+ * - {@link recordOutcome} is called after the ownership gate, with the delivery
68
+ * {@link ForwardedWorkerLogOutcome}, to drive the lifetime strike bucket on
69
+ * anomalous (oversize/invalid) records.
70
+ *
71
+ * Granularity is per-worker (not per-workflow): a pooled worker runs many workflows
72
+ * over its lifetime, the remediation ({@link Worker} discard) is worker-scoped, and
73
+ * the threat model treats the whole worker as the adversary, so per-worker both
74
+ * matches the remediation and defeats spreading abuse thin across many workflows.
75
+ */
76
+ export declare class WorkerLogAbuseCounter {
77
+ #private;
78
+ constructor(options: WorkerLogAbuseCounterOptions);
79
+ /**
80
+ * Record one forwarded-log ARRIVAL for `worker` and return whether the worker
81
+ * should be discarded for flooding. Called for every `type:'log'` message before
82
+ * the ownership gate. This is a fixed/anchored window (not a true rolling window): an
83
+ * arrival at or beyond `floodWindowMs` after the window's start anchors a fresh window
84
+ * (count resets to 1). Within a window, the verdict is `discard` once arrivals exceed
85
+ * `floodThreshold`. A backwards clock jump (`now < windowStartedAt`, e.g. an NTP step
86
+ * when `getNow` is wall-clock) also re-anchors the window, so clock regression can never
87
+ * hold a window open and accumulate toward a premature discard.
88
+ */
89
+ recordArrival(worker: Worker): WorkerLogAbuseVerdict;
90
+ /**
91
+ * Record the delivery `outcome` for one forwarded log from `worker` and return
92
+ * whether the worker should be discarded for accumulated anomalies. An
93
+ * `accepted-valid` outcome is a no-op (valid logs are accounted only by the flood
94
+ * budget). An oversize or invalid outcome adds one lifetime strike; the verdict is
95
+ * `discard` once lifetime strikes reach `strikeThreshold`. The `switch` is exhaustive
96
+ * (the `never` default) so that adding a future non-strike dropped outcome forces the
97
+ * strike-vs-no-strike policy decision to be made here rather than defaulting to a strike.
98
+ */
99
+ recordOutcome(worker: Worker, outcome: ForwardedWorkerLogOutcome): WorkerLogAbuseVerdict;
100
+ /** Drop a worker's accounting (called when the worker is discarded/forgotten). */
101
+ forget(worker: Worker): void;
102
+ }
103
+ /**
104
+ * Narrow construction config for {@link ForwardedLogGate} — decoupled from
105
+ * `WorkerExecutionStrategyOptions` so the gate names only what it consumes. The
106
+ * threshold fields are `| undefined` (the gate applies each default); build this from
107
+ * a strategy's options with {@link forwardedLogGateFromStrategyOptions}.
108
+ */
109
+ export interface ForwardedLogGateOptions {
110
+ readonly onLog: ((record: WorkflowLogRecord) => void) | undefined;
111
+ readonly maxProtocolMessageBytes: number | undefined;
112
+ readonly getNow: (() => number) | undefined;
113
+ readonly floodWindowMs: number | undefined;
114
+ readonly floodThreshold: number | undefined;
115
+ readonly strikeThreshold: number | undefined;
116
+ }
117
+ /**
118
+ * The complete forwarded-log lane for the hardened worker path: #529 delivery
119
+ * orchestration plus the #545 per-worker abuse counter. Extracted from
120
+ * `WorkerExecutionStrategy` so the strategy's message branch is a one-line delegate
121
+ * and this whole concern — counting policy, ownership-gated delivery, discard
122
+ * decisions — lives in one focused, independently tested module.
123
+ *
124
+ * {@link handle} is the single entry point. It counts EVERY arrival toward the flood
125
+ * budget BEFORE the ownership gate (a worker flooding logs for workflows it does not
126
+ * own is still counted — the host already paid the structured-clone cost on receipt),
127
+ * applies the trust-boundary ownership gate (a worker may forward logs only for a
128
+ * workflow it owns, checked by the injected `ownedByWorker` predicate), delivers
129
+ * owned records to the sink, and feeds the delivery outcome to the lifetime strike
130
+ * bucket. It returns a human-readable discard reason when sustained abuse (flooding
131
+ * OR repeated anomalies) crosses a threshold, or `null` to tolerate. The caller owns
132
+ * the actual worker discard; this gate only decides.
133
+ */
134
+ export declare class ForwardedLogGate {
135
+ #private;
136
+ /**
137
+ * Construct from a narrow gate-local config (decoupled from the strategy). Defaults
138
+ * are applied here so this is the one place every forwarded-log default lives: `getNow`
139
+ * → `Date.now`, flood window/threshold → the generous worker-protocol constants, strike
140
+ * threshold → the small non-configurable constant. Build it from a strategy's options
141
+ * with {@link forwardedLogGateFromStrategyOptions}.
142
+ */
143
+ constructor(config: ForwardedLogGateOptions);
144
+ /** Whether a host `onLog` sink is installed (drives the worker's `hostHasLogSink` flag). */
145
+ get hasSink(): boolean;
146
+ /**
147
+ * Process one forwarded `log` from `worker`. `ownedByWorker` reports whether the
148
+ * sending worker owns `message.workflowId` (active or parked) — the strategy's
149
+ * ownership state stays the source of truth. Returns ready-to-use discard options on
150
+ * sustained abuse (the strategy passes them straight to its worker-discard path), or
151
+ * `null` to tolerate this occurrence.
152
+ */
153
+ handle(worker: Worker, message: WorkerLogMessageCandidate, ownedByWorker: (workflowId: string) => boolean): LogAbuseDiscardOptions | null;
154
+ /** Drop a worker's accounting (called when the worker is discarded/forgotten). */
155
+ forget(worker: Worker): void;
156
+ }
157
+ /**
158
+ * The discard options {@link ForwardedLogGate.handle} returns for an abusive worker —
159
+ * a `system`-category discard whose target and other failures carry the same reason.
160
+ * Structurally a subset of the strategy's worker-discard options, so the strategy
161
+ * passes it straight through.
162
+ */
163
+ export interface LogAbuseDiscardOptions {
164
+ readonly targetCategory: FailureCategory;
165
+ readonly targetError: string;
166
+ readonly otherCategory: FailureCategory;
167
+ readonly otherError: string;
168
+ }
169
+ /**
170
+ * Build a {@link ForwardedLogGate} from a strategy's options. This is the one place that
171
+ * names {@link WorkerExecutionStrategyOptions} (type-only), so the gate class itself stays
172
+ * decoupled from the broader strategy surface. `maxProtocolMessageBytes` is passed
173
+ * separately because the strategy also consumes it for its protocol guard.
174
+ */
175
+ export declare function forwardedLogGateFromStrategyOptions(options: WorkerExecutionStrategyOptions | undefined, maxProtocolMessageBytes: number | undefined): ForwardedLogGate;
@@ -0,0 +1,107 @@
1
+ import {
2
+ deliverForwardedWorkerLog
3
+ } from "./worker-message-helpers.js";
4
+ import {
5
+ DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD,
6
+ DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS,
7
+ FORWARDED_LOG_STRIKE_THRESHOLD
8
+ } from "./worker-protocol.js";
9
+
10
+ export class WorkerLogAbuseCounter {
11
+ #floodWindowMs;
12
+ #floodThreshold;
13
+ #strikeThreshold;
14
+ #getNow;
15
+ #stateByWorker = new WeakMap;
16
+ constructor(options) {
17
+ this.#floodWindowMs = options.floodWindowMs;
18
+ this.#floodThreshold = options.floodThreshold;
19
+ this.#strikeThreshold = options.strikeThreshold;
20
+ this.#getNow = options.getNow;
21
+ }
22
+ recordArrival(worker) {
23
+ const now = this.#getNow(), state = this.#stateFor(worker), elapsed = now - state.windowStartedAt;
24
+ if (elapsed >= this.#floodWindowMs || elapsed < 0) {
25
+ state.windowStartedAt = now;
26
+ state.arrivalsInWindow = 0;
27
+ }
28
+ state.arrivalsInWindow += 1;
29
+ return state.arrivalsInWindow > this.#floodThreshold ? "discard" : "tolerate";
30
+ }
31
+ recordOutcome(worker, outcome) {
32
+ switch (outcome) {
33
+ case "accepted-valid":
34
+ return "tolerate";
35
+ case "dropped-oversize":
36
+ case "dropped-invalid": {
37
+ const state = this.#stateFor(worker);
38
+ state.lifetimeStrikes += 1;
39
+ return state.lifetimeStrikes >= this.#strikeThreshold ? "discard" : "tolerate";
40
+ }
41
+ default:
42
+ throw Error(`Unknown forwarded-log outcome: ${String(outcome)}`);
43
+ }
44
+ }
45
+ forget(worker) {
46
+ this.#stateByWorker.delete(worker);
47
+ }
48
+ #stateFor(worker) {
49
+ let state = this.#stateByWorker.get(worker);
50
+ if (!state) {
51
+ state = { windowStartedAt: this.#getNow(), arrivalsInWindow: 0, lifetimeStrikes: 0 };
52
+ this.#stateByWorker.set(worker, state);
53
+ }
54
+ return state;
55
+ }
56
+ }
57
+
58
+ export class ForwardedLogGate {
59
+ #counter;
60
+ #onLog;
61
+ #maxProtocolMessageBytes;
62
+ constructor(config) {
63
+ this.#onLog = config.onLog;
64
+ this.#maxProtocolMessageBytes = config.maxProtocolMessageBytes;
65
+ this.#counter = new WorkerLogAbuseCounter({
66
+ floodWindowMs: config.floodWindowMs ?? DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS,
67
+ floodThreshold: config.floodThreshold ?? DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD,
68
+ strikeThreshold: config.strikeThreshold ?? FORWARDED_LOG_STRIKE_THRESHOLD,
69
+ getNow: config.getNow ?? Date.now
70
+ });
71
+ }
72
+ get hasSink() {
73
+ return this.#onLog !== void 0;
74
+ }
75
+ handle(worker, message, ownedByWorker) {
76
+ if (this.#counter.recordArrival(worker) === "discard")
77
+ return discardForLogAbuse("forwarded-log flooding");
78
+ if (typeof message.workflowId !== "string" || !ownedByWorker(message.workflowId))
79
+ return null;
80
+ const outcome = deliverForwardedWorkerLog(message, this.#onLog, this.#maxProtocolMessageBytes);
81
+ if (this.#counter.recordOutcome(worker, outcome) === "discard")
82
+ return discardForLogAbuse("repeated oversize/invalid forwarded logs");
83
+ return null;
84
+ }
85
+ forget(worker) {
86
+ this.#counter.forget(worker);
87
+ }
88
+ }
89
+ function discardForLogAbuse(reason) {
90
+ const error = `Worker discarded for log abuse: ${reason}`;
91
+ return {
92
+ targetCategory: "system",
93
+ targetError: error,
94
+ otherCategory: "system",
95
+ otherError: error
96
+ };
97
+ }
98
+ export function forwardedLogGateFromStrategyOptions(options, maxProtocolMessageBytes) {
99
+ return new ForwardedLogGate({
100
+ onLog: options?.onLog,
101
+ maxProtocolMessageBytes,
102
+ getNow: options?.getNow,
103
+ floodWindowMs: options?.forwardedLogFloodWindowMs,
104
+ floodThreshold: options?.forwardedLogFloodThreshold,
105
+ strikeThreshold: options?.forwardedLogStrikeThreshold
106
+ });
107
+ }
@@ -1,5 +1,52 @@
1
1
  import type { WorkerOutboundMessage } from './types.ts';
2
+ import type { WorkflowLogRecord } from './types/workflow-log.ts';
3
+ import { type WorkerLogMessageCandidate } from './worker-protocol-log.ts';
4
+ /**
5
+ * The outcome of attempting to deliver one forwarded worker `ctx.log` (#545), produced
6
+ * by {@link deliverForwardedWorkerLog} and consumed by the abuse counter, which
7
+ * classifies each forwarded log by this outcome to feed its two buckets independently:
8
+ *
9
+ * - `accepted-valid`: a structurally valid, in-budget record. Counted toward the flood
10
+ * budget (every owned arrival is) but never a strike. Returned even when no host sink
11
+ * is installed — a valid log still consumes flood budget, because the host already
12
+ * paid the structured-clone cost on receipt regardless of the sink.
13
+ * - `dropped-oversize`: the record exceeded the protocol size cap. An anomaly — a
14
+ * well-behaved worker-side logger never emits oversize records — so it is a strike.
15
+ * - `dropped-invalid`: the record is not a structurally valid {@link WorkflowLogRecord},
16
+ * or its `workflowId` does not match the envelope. Also a strike: a legitimate logger
17
+ * always emits a well-formed record whose id matches the workflow it owns.
18
+ *
19
+ * `dropped-oversize` and `dropped-invalid` both feed the SAME lifetime strike bucket;
20
+ * the distinction is retained only for diagnostics/console fidelity.
21
+ */
22
+ export type ForwardedWorkerLogOutcome = 'accepted-valid' | 'dropped-oversize' | 'dropped-invalid';
2
23
  export declare function emitWorkerMessageToEngine(handler: ((message: WorkerOutboundMessage) => void | Promise<void>) | null, message: WorkerOutboundMessage): boolean | Promise<boolean>;
3
24
  export declare function isParkableWaitSignalCheckpoint(message: Extract<WorkerOutboundMessage, {
4
25
  type: 'checkpoint';
5
26
  }>): boolean;
27
+ /**
28
+ * Deliver a forwarded worker `ctx.log` to the host `onLog` sink (#529), AFTER the
29
+ * caller has verified the sending worker owns `message.workflowId` (the trust-boundary
30
+ * ownership gate stays inline in the strategy). This is the mechanical tail: DROP unless
31
+ * the message is within the size cap AND the record is a structurally valid
32
+ * {@link WorkflowLogRecord} whose `workflowId` matches the envelope; then deliver to
33
+ * `onLog`. The log lane is non-fatal per delivery — malformed, identity-mismatched,
34
+ * oversize, throwing-sink — so a SINGLE occurrence never throws and never discards the
35
+ * worker. A throwing host sink falls back to the console via the shared
36
+ * {@link logRecordToConsole}, mirroring the inline sink, so a logging error can never
37
+ * fail the workflow.
38
+ *
39
+ * The size check is intentionally performed BEFORE the structural check so that a huge
40
+ * but otherwise-encodable malformed record is classified `dropped-oversize` rather than
41
+ * `dropped-invalid` (#545): the dominant abuse cost of an oversize record — the runtime's
42
+ * structured clone on receipt — is paid regardless of whether the payload is well-formed.
43
+ * Only a genuine size-cap breach ({@link WorkerProtocolMessageSizeError}) is oversize; the
44
+ * estimator's other throw (cyclic / non-cloneable payloads) is classified `dropped-invalid`.
45
+ *
46
+ * The returned {@link ForwardedWorkerLogOutcome} is what the strategy feeds to the
47
+ * per-worker abuse counter (#545): `accepted-valid` counts a delivered (or, with no
48
+ * sink, would-be-delivered) record; `dropped-oversize`/`dropped-invalid` are anomalies
49
+ * that accumulate lifetime strikes. The helper still NEVER discards a worker — that
50
+ * remediation decision belongs to the counter and the strategy.
51
+ */
52
+ export declare function deliverForwardedWorkerLog(message: WorkerLogMessageCandidate, onLog: ((record: WorkflowLogRecord) => void) | undefined, maxProtocolMessageBytes: number | undefined): ForwardedWorkerLogOutcome;
@@ -1,3 +1,9 @@
1
+ import { logRecordToConsole } from "./context/workflow-logger.js";
2
+ import { isValidWorkerLogRecord } from "./worker-protocol-log.js";
3
+ import {
4
+ assertWorkerProtocolMessageWithinLimit,
5
+ WorkerProtocolMessageSizeError
6
+ } from "./worker-protocol.js";
1
7
  export function emitWorkerMessageToEngine(handler, message) {
2
8
  try {
3
9
  const emitResult = handler?.(message);
@@ -12,3 +18,23 @@ export function isParkableWaitSignalCheckpoint(message) {
12
18
  const operationRequest = message.operationRequest;
13
19
  return operationRequest.type === "wait-signal" || operationRequest.kind === "signal-wait";
14
20
  }
21
+ export function deliverForwardedWorkerLog(message, onLog, maxProtocolMessageBytes) {
22
+ if (maxProtocolMessageBytes !== void 0)
23
+ try {
24
+ assertWorkerProtocolMessageWithinLimit(message, maxProtocolMessageBytes);
25
+ } catch (error) {
26
+ return error instanceof WorkerProtocolMessageSizeError ? "dropped-oversize" : "dropped-invalid";
27
+ }
28
+ if (!isValidWorkerLogRecord(message.record))
29
+ return "dropped-invalid";
30
+ const record = message.record;
31
+ if (record.workflowId !== message.workflowId)
32
+ return "dropped-invalid";
33
+ if (onLog !== void 0)
34
+ try {
35
+ onLog(record);
36
+ } catch {
37
+ logRecordToConsole(record);
38
+ }
39
+ return "accepted-valid";
40
+ }
@@ -49,7 +49,7 @@ export class WorkerProtocolGuard {
49
49
  const turn = this.#turnWatchdog.get(worker);
50
50
  if (!turn)
51
51
  throw new WorkerProtocolError("Worker message arrived outside an active turn");
52
- if (message.turnId !== turn.turnId || message.workflowId !== turn.workflowId)
52
+ if ((message.type === "log" ? void 0 : message.turnId) !== turn.turnId || message.workflowId !== turn.workflowId)
53
53
  throw new WorkerProtocolError("Worker message did not match the active turn");
54
54
  }
55
55
  }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Pure structural validators for worker `log` protocol messages (#529). These have
3
+ * NO dependency on the rest of `worker-protocol.ts` — they are leaf predicates so
4
+ * `worker-protocol.ts` (which owns `WorkerProtocolError` and the strict asserters)
5
+ * can import them without an import cycle. The strict, throwing path
6
+ * (`assertWorkerLogOutbound` in `worker-protocol.ts`) wraps {@link isValidWorkerLogRecord},
7
+ * and the host's lenient delivery path routes on {@link isWorkerLogMessage}, so both
8
+ * paths share one definition of "valid worker log".
9
+ *
10
+ * The `log` lane is intentionally version-tolerant: a `log` carries no turn-protocol
11
+ * state and is best-effort observability, so it bypasses the strict protocol-version
12
+ * negotiation that gates state-changing messages. That is safe while only protocol v1
13
+ * exists; a future incompatible protocol would still send `type: 'log'` and have its
14
+ * record validated structurally here rather than rejected on version. This is the one
15
+ * place that decision lives — see {@link isWorkerLogMessage}.
16
+ *
17
+ * @module core/worker-protocol-log
18
+ */
19
+ import type { WorkflowLogRecord } from './types/workflow-log.ts';
20
+ /**
21
+ * A candidate `log` outbound message: every field is `unknown` because this lane
22
+ * accepts the message by `type` ALONE and validates the payload separately. Narrowing
23
+ * to this (rather than the final `Extract<WorkerOutboundMessage, { type: 'log' }>`)
24
+ * keeps {@link isWorkerLogMessage} a SOUND predicate — it promises only what it
25
+ * checks. The record is treated as a {@link WorkflowLogRecord} only after
26
+ * {@link isValidWorkerLogRecord} succeeds.
27
+ */
28
+ export interface WorkerLogMessageCandidate {
29
+ readonly type: 'log';
30
+ readonly protocolVersion?: unknown;
31
+ readonly workflowId?: unknown;
32
+ readonly record?: unknown;
33
+ }
34
+ /**
35
+ * Whether `record` is a structurally complete {@link WorkflowLogRecord} — the single
36
+ * source of truth for "valid worker log payload", shared by the strict-protocol
37
+ * asserter (which throws) and the host's lenient delivery path (which drops). Because
38
+ * the host sink is typed to receive a `WorkflowLogRecord`, this validates the FULL
39
+ * envelope an untrusted worker must supply: `level` (allowed literal), `message`,
40
+ * `workflowId`, `workflowType` (strings), `timestamp` (finite number), and — when
41
+ * present — `attributes` (a plain object). A record missing any required field or
42
+ * carrying a wrong-typed field is rejected so a malformed wire payload can never reach
43
+ * a strongly typed host sink.
44
+ */
45
+ export declare function isValidWorkerLogRecord(record: unknown): record is WorkflowLogRecord;
46
+ /**
47
+ * Structural type-guard that routes a message into the host's LENIENT log lane: any
48
+ * message whose `type` is `'log'`. It matches on `type` ALONE and narrows only to
49
+ * {@link WorkerLogMessageCandidate} (all payload fields `unknown`) — payload validity
50
+ * is decided later by {@link isValidWorkerLogRecord}, so a malformed log is DROPPED,
51
+ * not sent to the strict accept-or-discard gate. A `log` is best-effort observability
52
+ * and carries no turn-protocol state, so no malformed/oversize/out-of-turn log may
53
+ * ever discard the worker. A non-`log` message returns `false` and flows on to the
54
+ * strict gate unchanged.
55
+ */
56
+ export declare function isWorkerLogMessage(message: unknown): message is WorkerLogMessageCandidate;
@@ -0,0 +1,18 @@
1
+ const WORKFLOW_LOG_LEVELS = new Set(["debug", "info", "warn", "error"]);
2
+ function isValidLogAttributes(attributes) {
3
+ if (attributes === void 0)
4
+ return !0;
5
+ if (typeof attributes !== "object" || attributes === null)
6
+ return !1;
7
+ const prototype = Object.getPrototypeOf(attributes);
8
+ return prototype === Object.prototype || prototype === null;
9
+ }
10
+ export function isValidWorkerLogRecord(record) {
11
+ if (typeof record !== "object" || record === null)
12
+ return !1;
13
+ const candidate = record;
14
+ return WORKFLOW_LOG_LEVELS.has(candidate.level) && typeof candidate.message === "string" && typeof candidate.workflowId === "string" && typeof candidate.workflowType === "string" && typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp) && isValidLogAttributes(candidate.attributes);
15
+ }
16
+ export function isWorkerLogMessage(message) {
17
+ return typeof message === "object" && message !== null && message.type === "log";
18
+ }
@@ -6,6 +6,29 @@ export declare const WORKER_PROTOCOL_VERSION = 1;
6
6
  export declare const DEFAULT_WORKER_TURN_TIMEOUT_MS = 1000;
7
7
  export declare const DEFAULT_WORKER_PROTOCOL_MESSAGE_BYTES = 1048576;
8
8
  export declare const MIN_WORKER_PROTOCOL_MESSAGE_BYTES = 4096;
9
+ /**
10
+ * Default fixed-window length (ms) for the forwarded-log flood budget (#545). Paired
11
+ * with {@link DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD} over this window.
12
+ */
13
+ export declare const DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS = 60000;
14
+ /**
15
+ * Default maximum forwarded-log arrivals per worker within
16
+ * {@link DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS} before the worker is discarded for
17
+ * flooding (#545). This budget is AGGREGATE per (pooled) worker, across every workflow
18
+ * the worker currently owns — not per workflow. Set deliberately high (~83 arrivals/sec
19
+ * sustained) because the harm is asymmetric: a false discard fails ALL of that worker's
20
+ * in-flight workflows, while a real flood from a compromised worker runs at thousands per
21
+ * second and still trips comfortably. Honest high-log workflows stay well under it.
22
+ */
23
+ export declare const DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD = 5000;
24
+ /**
25
+ * Cumulative lifetime anomalous (oversize OR structurally invalid) forwarded-log
26
+ * records tolerated per worker before discard (#545). A small constant — a well-behaved
27
+ * worker-side logger never emits oversize or malformed records, so a few in a worker's
28
+ * whole lifetime already signal abuse, and there is no legitimate-traffic reason to make
29
+ * this configurable. Not window-scoped and never reset.
30
+ */
31
+ export declare const FORWARDED_LOG_STRIKE_THRESHOLD = 5;
9
32
  export declare class WorkerProtocolError extends Error {
10
33
  constructor(message: string);
11
34
  }
@@ -1,11 +1,13 @@
1
+ import { copyBytesToArrayBuffer } from "./byte-arrays.js";
1
2
  import { encode, validateCloneable } from "./codec.js";
2
3
  import {
3
4
  WORKER_REPLAY_SIGNATURE_FORMAT
4
5
  } from "./types/checkpoint.js";
6
+ import { isValidWorkerLogRecord } from "./worker-protocol-log.js";
5
7
  export {
6
8
  WORKER_REPLAY_SIGNATURE_FORMAT
7
9
  } from "./types/checkpoint.js";
8
- export const WORKER_PROTOCOL_VERSION = 1, DEFAULT_WORKER_TURN_TIMEOUT_MS = 1000, DEFAULT_WORKER_PROTOCOL_MESSAGE_BYTES = 1048576, MIN_WORKER_PROTOCOL_MESSAGE_BYTES = 4096;
10
+ export const WORKER_PROTOCOL_VERSION = 1, DEFAULT_WORKER_TURN_TIMEOUT_MS = 1000, DEFAULT_WORKER_PROTOCOL_MESSAGE_BYTES = 1048576, MIN_WORKER_PROTOCOL_MESSAGE_BYTES = 4096, DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS = 60000, DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD = 5000, FORWARDED_LOG_STRIKE_THRESHOLD = 5;
9
11
  const BINARY_MARKER = "__weftBinaryBytes", DATE_MARKER = "__weftDate", ERROR_MARKER = "__weftError", MAP_MARKER = "__weftMap", SET_MARKER = "__weftSet", MAX_BOUNDED_ERROR_LENGTH = 512, WORKER_SIGNATURE_EXCLUDED_FIELDS = new Set([
10
12
  "attempt",
11
13
  "callerStack",
@@ -21,6 +23,7 @@ const BINARY_MARKER = "__weftBinaryBytes", DATE_MARKER = "__weftDate", ERROR_MAR
21
23
  "activity",
22
24
  "archive",
23
25
  "child-workflow",
26
+ "get-version",
24
27
  "load",
25
28
  "memo",
26
29
  "offload",
@@ -107,6 +110,9 @@ function assertWorkerOutboundVariant(record) {
107
110
  case "failed":
108
111
  assertWorkerFailedOutbound(record);
109
112
  return;
113
+ case "log":
114
+ assertWorkerLogOutbound(record);
115
+ return;
110
116
  default:
111
117
  throw new WorkerProtocolError("Worker outbound message has an unsupported type");
112
118
  }
@@ -121,11 +127,15 @@ function assertWorkerFailedOutbound(record) {
121
127
  if (typeof record.error !== "string")
122
128
  throw new WorkerProtocolError("Worker failed message must include an error string");
123
129
  }
130
+ function assertWorkerLogOutbound(record) {
131
+ if (!isValidWorkerLogRecord(record.record))
132
+ throw new WorkerProtocolError("Worker log message must include a valid log record");
133
+ }
124
134
  export async function createWorkerReplayOperationSignature(operation, maxStableFieldsBytes) {
125
135
  const operationType = workerOperationType(operation), stableFields = stableWorkerOperationFields(operation, operationType), encodedStableFields = encode(stableFields);
126
136
  if (encodedStableFields.byteLength > maxStableFieldsBytes)
127
137
  throw new WorkerProtocolError(`Worker replay signature input is ${encodedStableFields.byteLength} bytes, exceeding limit ${maxStableFieldsBytes}`);
128
- const digestBytes = await crypto.subtle.digest("SHA-256", encodedStableFields);
138
+ const digestBytes = await crypto.subtle.digest("SHA-256", copyBytesToArrayBuffer(encodedStableFields));
129
139
  return {
130
140
  format: WORKER_REPLAY_SIGNATURE_FORMAT,
131
141
  operationType,
@@ -38,19 +38,13 @@ export type WorkflowVersionDiff = {
38
38
  /**
39
39
  * Collect sorted `"${name}@${version}"` version strings from a tool array.
40
40
  *
41
- * Each element must expose a flat `name` or the old internal
42
- * `definition.name` compatibility shape, plus an optional `version`. Missing
43
- * versions default to `"0.0.0"`. The returned array is sorted alphabetically
44
- * so comparisons are order-independent.
41
+ * Each element exposes a `name` plus an optional `version`. Missing versions
42
+ * default to `"0.0.0"`. The returned array is sorted alphabetically so
43
+ * comparisons are order-independent.
45
44
  */
46
45
  export declare function collectToolVersions(tools: Array<{
47
46
  name: string;
48
47
  version?: string | undefined;
49
- } | {
50
- definition: {
51
- name: string;
52
- };
53
- version?: string | undefined;
54
48
  }>): string[];
55
49
  /**
56
50
  * Compare two {@link WorkflowVersionTuple}s and return structured field-level diffs.
@@ -1,9 +1,8 @@
1
1
  export function collectToolVersions(tools) {
2
2
  return tools.map((tool) => {
3
- const name = "name" in tool ? tool.name : tool.definition.name;
4
- if (!name)
3
+ if (!tool.name)
5
4
  throw Error("collectToolVersions: tool is missing a required name field");
6
- return `${name}@${tool.version ?? "0.0.0"}`;
5
+ return `${tool.name}@${tool.version ?? "0.0.0"}`;
7
6
  }).toSorted();
8
7
  }
9
8
  export function diffWorkflowVersionTuples(stored, registered) {
@@ -1,4 +1,6 @@
1
1
  import { decode } from "../core/codec.js";
2
+ import { decodeWorkflowState } from "../core/engine/validation.js";
3
+ import { isTopLevelWorkflowStateKey } from "../core/engine/workflow-state-stream.js";
2
4
  import { fileSize } from "../runtime/portable.js";
3
5
  import { KEYS } from "../storage/interface.js";
4
6
  import { generateRecommendations } from "./recommendations.js";
@@ -89,13 +91,14 @@ async function aggregateWorkflowScan(storage, now) {
89
91
  completed: 0,
90
92
  failed: 0,
91
93
  cancelled: 0,
92
- timedOut: 0
94
+ timedOut: 0,
95
+ suspended: 0
93
96
  };
94
97
  let total = 0, longestRunning = null, earliestCreatedAt = 1 / 0;
95
98
  for await (const [key, value] of storage.scan("wf:")) {
96
- if (key.includes(":ckpt"))
99
+ if (!isTopLevelWorkflowStateKey(key))
97
100
  continue;
98
- const state = decode(value);
101
+ const state = decodeWorkflowState(value);
99
102
  total++;
100
103
  statusCounts[mapStatusKey(state.status)]++;
101
104
  if (state.status === "running" && state.createdAt < earliestCreatedAt) {
@@ -1,6 +1,5 @@
1
1
  const supportsColor = typeof process < "u" && process.stdout?.isTTY && !process.env.NO_COLOR, color = {
2
2
  green: (text) => supportsColor ? `\x1B[32m${text}\x1B[0m` : text,
3
- yellow: (text) => supportsColor ? `\x1B[33m${text}\x1B[0m` : text,
4
3
  red: (text) => supportsColor ? `\x1B[31m${text}\x1B[0m` : text,
5
4
  bold: (text) => supportsColor ? `\x1B[1m${text}\x1B[0m` : text
6
5
  };
@@ -47,8 +46,8 @@ function appendWorkflowsSection(lines, workflows) {
47
46
  lines.push(" Total: 0 (no workflows)");
48
47
  return;
49
48
  }
50
- const counts = workflows.statusCounts;
51
- lines.push(` Total: ${workflows.total} (${counts.running} running, ${counts.completed} completed, ${counts.failed} failed)`);
49
+ const counts = workflows.statusCounts, suspendedSummary = counts.suspended > 0 ? `, ${counts.suspended} suspended` : "";
50
+ lines.push(` Total: ${workflows.total} (${counts.running} running, ${counts.completed} completed, ${counts.failed} failed${suspendedSummary})`);
52
51
  if (workflows.longestRunning) {
53
52
  const longest = workflows.longestRunning;
54
53
  lines.push(` Longest running: ${longest.id} (started ${formatDuration(longest.elapsedMilliseconds)} ago, step ${longest.currentStep})`);
@@ -96,18 +95,14 @@ export function formatVersionCheckReport(report) {
96
95
  lines.push(`${typeReport.type} (${typeReport.storedVersion} \u2192 ${typeReport.registeredVersion}):`);
97
96
  lines.push(` ${typeReport.runningCount} running workflows`);
98
97
  lines.push(` Compatibility: ${typeReport.compatibility}`);
99
- lines.push(` Migration: ${typeReport.hasMigration ? "provided" : "not provided"}`);
100
98
  lines.push("");
101
99
  }
102
100
  switch (report.overallVerdict) {
103
101
  case "safe":
104
102
  lines.push(`Result: ${color.green("Safe to deploy.")}`);
105
103
  break;
106
- case "needs-migration":
107
- lines.push(`Result: ${color.yellow("Needs migration. Migration functions provided.")}`);
108
- break;
109
104
  case "unsafe":
110
- lines.push(`Result: ${color.red("UNSAFE: missing migration functions.")}`);
105
+ lines.push(`Result: ${color.red("UNSAFE: version mismatches found.")}`);
111
106
  break;
112
107
  }
113
108
  return lines.join(`