@lostgradient/weft 0.6.0 → 0.8.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 (135) hide show
  1. package/README.md +7 -5
  2. package/dist/cli/generated/operation-client.generated.d.ts +1 -0
  3. package/dist/cli-main.js +63 -63
  4. package/dist/client/event-stream-options.d.ts +58 -0
  5. package/dist/client/event-stream-options.js +0 -0
  6. package/dist/client/event-stream.d.ts +27 -44
  7. package/dist/client/event-stream.js +21 -56
  8. package/dist/client/event-tail-lifecycle.d.ts +21 -0
  9. package/dist/client/event-tail-lifecycle.js +71 -0
  10. package/dist/client/event-tail.d.ts +3 -1
  11. package/dist/client/http-client.d.ts +4 -5
  12. package/dist/client/http-client.js +4 -1
  13. package/dist/client/http-handle.d.ts +4 -5
  14. package/dist/client/http-request.d.ts +7 -0
  15. package/dist/client/index.d.ts +2 -1
  16. package/dist/client/interface.d.ts +23 -7
  17. package/dist/client/local-handles.d.ts +2 -0
  18. package/dist/client/local-handles.js +10 -1
  19. package/dist/client/local.d.ts +3 -3
  20. package/dist/client/open-event-subscription.d.ts +3 -2
  21. package/dist/client/open-event-subscription.js +28 -1
  22. package/dist/client/sse-event-stream.d.ts +27 -0
  23. package/dist/client/sse-event-stream.js +276 -0
  24. package/dist/client/start-body.d.ts +2 -2
  25. package/dist/client/start-body.js +1 -0
  26. package/dist/core/context/activity-retry-state.d.ts +6 -5
  27. package/dist/core/context/activity-retry-state.js +31 -21
  28. package/dist/core/context/durable-activity.d.ts +117 -0
  29. package/dist/core/context/durable-activity.js +79 -0
  30. package/dist/core/context/operation-request.d.ts +15 -0
  31. package/dist/core/context/parallel-operations.js +1 -0
  32. package/dist/core/context/run-operation-cached-request.d.ts +8 -0
  33. package/dist/core/context/run-operation-cached-request.js +59 -0
  34. package/dist/core/context/run-operation.d.ts +23 -5
  35. package/dist/core/context/run-operation.js +62 -47
  36. package/dist/core/engine/activity-heartbeat-tracking.d.ts +8 -17
  37. package/dist/core/engine/activity-heartbeat-tracking.js +7 -1
  38. package/dist/core/engine/activity-reconciliation.d.ts +1 -0
  39. package/dist/core/engine/activity-reconciliation.js +7 -2
  40. package/dist/core/engine/anonymous-signal-sequence.js +6 -4
  41. package/dist/core/engine/async-activity-completion.d.ts +5 -7
  42. package/dist/core/engine/async-activity-completion.js +13 -9
  43. package/dist/core/engine/bulk-operations-purge.js +2 -1
  44. package/dist/core/engine/bulk-operations.js +8 -7
  45. package/dist/core/engine/callback-checkpoint-persistence.d.ts +3 -0
  46. package/dist/core/engine/callback-checkpoint-persistence.js +25 -0
  47. package/dist/core/engine/callback-creators-bundles.js +4 -1
  48. package/dist/core/engine/checkpoint-io.d.ts +4 -1
  49. package/dist/core/engine/checkpoint-io.js +19 -10
  50. package/dist/core/engine/completed-review-storage.d.ts +2 -1
  51. package/dist/core/engine/completed-review-storage.js +4 -3
  52. package/dist/core/engine/construction.js +3 -1
  53. package/dist/core/engine/engine-internal-types.d.ts +2 -0
  54. package/dist/core/engine/errors.d.ts +6 -6
  55. package/dist/core/engine/errors.js +1 -1
  56. package/dist/core/engine/handles.js +1 -1
  57. package/dist/core/engine/index.d.ts +37 -5
  58. package/dist/core/engine/index.js +7 -1
  59. package/dist/core/engine/internals.d.ts +2 -1
  60. package/dist/core/engine/lease-manager.js +2 -2
  61. package/dist/core/engine/lifecycle/recovered-services.js +8 -1
  62. package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +2 -2
  63. package/dist/core/engine/lifecycle/start-or-signal-create.js +17 -15
  64. package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +1 -1
  65. package/dist/core/engine/lifecycle/start-or-signal-resolution.js +23 -5
  66. package/dist/core/engine/lifecycle/start-or-signal.d.ts +6 -4
  67. package/dist/core/engine/lifecycle/start-or-signal.js +21 -4
  68. package/dist/core/engine/memo-durable-activity.d.ts +11 -0
  69. package/dist/core/engine/memo-durable-activity.js +282 -0
  70. package/dist/core/engine/operations-activity.d.ts +5 -1
  71. package/dist/core/engine/operations-activity.js +19 -7
  72. package/dist/core/engine/operations-data.d.ts +4 -1
  73. package/dist/core/engine/operations-data.js +3 -3
  74. package/dist/core/engine/reviews.js +7 -4
  75. package/dist/core/engine/schedule-run.js +12 -3
  76. package/dist/core/engine/schedule-timer.js +2 -0
  77. package/dist/core/engine/storage-io.js +2 -2
  78. package/dist/core/engine/termination/complete.js +3 -3
  79. package/dist/core/json.js +1 -1
  80. package/dist/core/scheduler/scheduler-class.js +2 -1
  81. package/dist/core/start-workflow-validation.d.ts +3 -4
  82. package/dist/core/start-workflow-validation.js +1 -1
  83. package/dist/core/timeouts.d.ts +13 -1
  84. package/dist/core/timeouts.js +4 -1
  85. package/dist/core/types/constants.d.ts +16 -0
  86. package/dist/core/types/options.d.ts +60 -12
  87. package/dist/core/types/services-resolution.d.ts +49 -3
  88. package/dist/core/weft-error.d.ts +1 -1
  89. package/dist/core/weft-error.js +3 -0
  90. package/dist/index.d.ts +5 -4
  91. package/dist/index.js +7 -0
  92. package/dist/json-schema.js +1 -1
  93. package/dist/mcp/cli.js +26 -26
  94. package/dist/server/asyncapi-channels.js +82 -16
  95. package/dist/server/handler/auth-context-principal.d.ts +19 -0
  96. package/dist/server/handler/auth-context-principal.js +25 -0
  97. package/dist/server/handler/index.d.ts +2 -1
  98. package/dist/server/handler/index.js +35 -18
  99. package/dist/server/handler/route-dispatch.d.ts +12 -22
  100. package/dist/server/handler/route-dispatch.js +30 -36
  101. package/dist/server/handler/sse-route-dispatch.d.ts +25 -0
  102. package/dist/server/handler/sse-route-dispatch.js +45 -0
  103. package/dist/server/handler.js +28 -28
  104. package/dist/server/index.d.ts +8 -7
  105. package/dist/server/index.js +17 -17
  106. package/dist/server/operations/fleet-events-sse.d.ts +11 -0
  107. package/dist/server/operations/fleet-events-sse.js +164 -0
  108. package/dist/server/operations/sse-stream.d.ts +43 -0
  109. package/dist/server/operations/sse-stream.js +152 -7
  110. package/dist/server/operations/start-or-signal-workflow.d.ts +2 -0
  111. package/dist/server/operations/start-or-signal-workflow.js +25 -14
  112. package/dist/server/operations/start-workflow-options.d.ts +9 -6
  113. package/dist/server/operations/start-workflow-options.js +13 -0
  114. package/dist/server/operations/workflow-events-sse.d.ts +17 -0
  115. package/dist/server/operations/workflow-events-sse.js +200 -0
  116. package/dist/server/rest-bindings.js +12 -0
  117. package/dist/server/runtime/authentication-bridge.js +4 -0
  118. package/dist/server/runtime/cors.d.ts +1 -1
  119. package/dist/server/runtime/cors.js +6 -1
  120. package/dist/server/runtime/websocket-stream.d.ts +4 -0
  121. package/dist/server/runtime/websocket-stream.js +20 -3
  122. package/dist/server/runtime/websocket-worker.js +7 -2
  123. package/dist/server/serve-internals.d.ts +28 -0
  124. package/dist/server/serve-internals.js +4 -2
  125. package/dist/server/workflow-event-feed.d.ts +1 -0
  126. package/dist/server/workflow-event-feed.js +17 -6
  127. package/dist/service-worker/index.js +28 -28
  128. package/dist/service-worker/setup.d.ts +18 -1
  129. package/dist/service-worker/setup.js +7 -4
  130. package/dist/storage/typed-storage.d.ts +1 -1
  131. package/dist/storage/typed-storage.js +1 -1
  132. package/dist/testing/index.js +27 -27
  133. package/dist/version.d.ts +1 -1
  134. package/dist/version.js +1 -1
  135. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Weft
2
2
 
3
- A Bun-native durable execution engine. Current release: `0.6.0`.
3
+ A Bun-native durable execution engine. Current release: `0.8.0`.
4
4
 
5
5
  Install the library from npm as `@lostgradient/weft`:
6
6
 
@@ -101,7 +101,7 @@ const result = await handle.result();
101
101
 
102
102
  That's the core loop: `workflow({ name })` is a **chained builder** that co-locates the workflow's side-effecting steps inside `.activities({...})`, and `.execute(fn)` seals it all together and returns a `WorkflowDefinition`. Inside the generator, `ctx.run('formatGreeting', input)` autocompletes from the workflow's own activity table, typechecks the input, and infers the output. Every `yield*` is a checkpoint boundary; `handle.result()` waits for the output. Checkpoints are written to `./weft.db`, so running workflows survive process crashes.
103
103
 
104
- `Engine.create()` does the registration dance for you: it constructs the engine and registers each workflow in the `workflows` map, pulling in all the activities each workflow declares. It then **recovers by default** — `engine.recoverAll()` runs after registration, so any workflows still running from a previous process pick up where they left off. That's the point of durable storage, so you don't have to ask for it. Pass `recover: false` to opt out (handy for tests, for `ScopedStorage`-isolated engines, or when you want to inspect a store before migrating it). Durability is separate: each step is persisted before it commits no matter what `recover` is set to — `recover` only decides whether _this_ engine resumes that persisted work on boot. Run a single engine per durable store; pointing two at the same store is not yet coordinated and can double-resume a workflow.
104
+ `Engine.create()` does the registration dance for you: it constructs the engine and registers each workflow in the `workflows` map, pulling in all the activities each workflow declares. It then **recovers by default** — `engine.recoverAll()` runs after registration, so any workflows still running from a previous process pick up where they left off. That's the point of durable storage, so you don't have to ask for it. Pass `recover: false` to opt out (handy for tests, for `ScopedStorage`-isolated engines, or when you want to inspect a store before migrating it). Durability is separate: each step is persisted before it commits no matter what `recover` is set to — `recover` only decides whether _this_ engine resumes that persisted work on boot. If a host owns recovery but still needs durable timers, use `startScheduler: true`; otherwise `recover: false` also leaves the real-time scheduler stopped. Run a single engine per durable store; pointing two at the same store is not yet coordinated and can double-resume a workflow.
105
105
 
106
106
  Passing an explicitly empty workflow map is the same default-registry boot shape as omitting `workflows`: `Engine.create({ workflows: {} })` recovers after registration and returns an engine whose TypeScript type is compatible with default-registry consumers such as `serve({ engine })`. Use a non-empty `workflows` map when you want TypeScript to narrow `engine.start(...)` to the registered names.
107
107
 
@@ -147,7 +147,7 @@ Because recovery never re-executes the workflow from the beginning, your workflo
147
147
 
148
148
  ### Durable Workflows
149
149
 
150
- Generator functions with automatic checkpointing at every `yield*` boundary. Activities, sleeps, signals, condition gates with `ctx.waitUntil()`, queries, updates, structured logs with `ctx.log`, parallel execution via `ctx.all()`, race semantics via `ctx.race()`, memoization via `ctx.memo()`, sagas via `ctx.saga()`, child workflows, and forks. `ctx.all()` and `ctx.race()` can branch over activities, sleeps, and signal waits; use `ctx.race([ctx.waitForSignal(name), ctx.sleep(timeout)])` for signal timeouts instead of placing an unbounded signal wait directly in `ctx.all()`.
150
+ Generator functions with automatic checkpointing at every `yield*` boundary. Activities, sleeps, signals, condition gates with `ctx.waitUntil()`, queries, updates, structured logs with `ctx.log`, parallel execution via `ctx.all()`, race semantics via `ctx.race()`, memoization via `ctx.memo()`, sagas via `ctx.saga()`, child workflows, and forks. Plain async helpers called from inline `ctx.memo()` callbacks can use `durableActivity()` for activity-level retry, heartbeat, reconciliation, and observability without converting the helper stack to generators. `ctx.all()` and `ctx.race()` can branch over activities, sleeps, and signal waits; use `ctx.race([ctx.waitForSignal(name), ctx.sleep(timeout)])` for signal timeouts instead of placing an unbounded signal wait directly in `ctx.all()`.
151
151
 
152
152
  Every workflow context exposes `ctx.workflowId` and `ctx.workflowType`. `workflowType` is the registered name from `workflow({ name })`, so shared workflow code can log, tag, or branch on the current workflow type without closing over definition-site state.
153
153
 
@@ -216,7 +216,7 @@ const quorum = workflow({ name: 'quorum' })
216
216
 
217
217
  ### Live Workflow Events
218
218
 
219
- Workflow handles expose lifecycle events through `addEventListener`, and client handles can open a live tail for progress UIs or operators. `LocalClient` reads from the in-process engine stream; `HttpClient` uses the per-workflow `/v1/workflows/:id/watch` WebSocket channel with history catch-up on connect and reconnect, so `addEventListener`, `client.tail(id)`, and `handle.tail()` are push-based rather than a polling loop. JSON-RPC clients can subscribe over WebSocket with `weft.workflows.subscribe` for one workflow or `weft.events.subscribe` for the fleet-wide event feed. Client code that receives a workflow id from another process can call `client.getHandle(id)` to re-attach a `ClientHandle` or get `null` when the run does not exist.
219
+ Workflow handles expose lifecycle events through `addEventListener`, and client handles can open a live tail for progress UIs or operators. `LocalClient` reads from the in-process engine stream; `HttpClient` defaults to the per-workflow `/v1/workflows/:id/watch` WebSocket channel when the runtime can carry authentication headers, and falls back to fetch-based SSE at `/v1/workflows/:id/events/sse` when it cannot. Both transports run history catch-up on connect and reconnect, so `addEventListener`, `client.tail(id)`, and `handle.tail()` are push-based rather than a polling loop. JSON-RPC clients can subscribe over WebSocket with `weft.workflows.subscribe` for one workflow or `weft.events.subscribe` for the fleet-wide event feed. Client code that receives a workflow id from another process can call `client.getHandle(id)` to re-attach a `ClientHandle` or get `null` when the run does not exist.
220
220
 
221
221
  ```typescript
222
222
  const handle = await client.start('checkout', order);
@@ -229,7 +229,7 @@ for await (const event of tail) {
229
229
  }
230
230
  ```
231
231
 
232
- The tail is single-consumer and stops on terminal workflow events or `tail.close()`. In runtimes without a built-in WebSocket, or where authenticated WebSockets need headers the platform constructor cannot send, provide `HttpClientOptions.webSocketFactory`.
232
+ The tail is single-consumer and stops on terminal workflow events or `tail.close()`. Pass `eventTransport: 'websocket'` to require WebSocket, `eventTransport: 'sse'` to require SSE, or `HttpClientOptions.webSocketFactory` to provide a runtime-specific WebSocket constructor.
233
233
 
234
234
  ### Idempotent Starts and Signal-With-Start
235
235
 
@@ -248,6 +248,8 @@ console.log(handle.id, outcome); // outcome is 'started' or 'signalled'
248
248
 
249
249
  The idempotency mapping intentionally outlives terminal cleanup. If retention removes the workflow record, the key is spent and future calls return a conflict instead of starting a replacement.
250
250
 
251
+ For stable-id re-sync flows, `engine.startOrSignal()` can replace a terminal prior run with `{ id, onTerminalConflict: 'start-new' }` when the initial signal also carries a deterministic `signalId`. Non-terminal runs are still signalled, not replaced, and restart-capable calls reject `idempotencyKey` because idempotency keys are permanent at-most-once mappings. Signal identifiers are treated as opaque user identifiers before storage-key construction, so caller-provided values that contain separator-looking text such as `anonymous:` stay explicit signal IDs instead of colliding with Weft's generated anonymous-signal sequence.
252
+
251
253
  ### Search Attributes
252
254
 
253
255
  Attach indexed metadata to a workflow at runtime, then list and filter on it.
@@ -560,6 +560,7 @@ export type CatalogOperationTypes = {
560
560
  readonly id?: unknown;
561
561
  readonly idempotencyKey?: unknown;
562
562
  readonly input?: unknown;
563
+ readonly onTerminalConflict?: unknown;
563
564
  readonly searchAttributes?: unknown;
564
565
  readonly signalId?: string;
565
566
  readonly signalName: string;