@workflow/core 4.0.1-beta.9 → 4.1.0-beta.52

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 (184) hide show
  1. package/dist/builtins.js +1 -1
  2. package/dist/class-serialization.d.ts +26 -0
  3. package/dist/class-serialization.d.ts.map +1 -0
  4. package/dist/class-serialization.js +66 -0
  5. package/dist/create-hook.js +1 -1
  6. package/dist/define-hook.d.ts +40 -25
  7. package/dist/define-hook.d.ts.map +1 -1
  8. package/dist/define-hook.js +22 -27
  9. package/dist/events-consumer.d.ts.map +1 -1
  10. package/dist/events-consumer.js +5 -1
  11. package/dist/flushable-stream.d.ts +82 -0
  12. package/dist/flushable-stream.d.ts.map +1 -0
  13. package/dist/flushable-stream.js +214 -0
  14. package/dist/global.d.ts +4 -1
  15. package/dist/global.d.ts.map +1 -1
  16. package/dist/global.js +21 -9
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +2 -2
  20. package/dist/logger.js +1 -1
  21. package/dist/observability.d.ts +60 -0
  22. package/dist/observability.d.ts.map +1 -1
  23. package/dist/observability.js +265 -32
  24. package/dist/private.d.ts +10 -1
  25. package/dist/private.d.ts.map +1 -1
  26. package/dist/private.js +6 -1
  27. package/dist/runtime/helpers.d.ts +52 -0
  28. package/dist/runtime/helpers.d.ts.map +1 -0
  29. package/dist/runtime/helpers.js +264 -0
  30. package/dist/runtime/resume-hook.d.ts +17 -12
  31. package/dist/runtime/resume-hook.d.ts.map +1 -1
  32. package/dist/runtime/resume-hook.js +79 -64
  33. package/dist/runtime/run.d.ts +100 -0
  34. package/dist/runtime/run.d.ts.map +1 -0
  35. package/dist/runtime/run.js +132 -0
  36. package/dist/runtime/start.d.ts +15 -1
  37. package/dist/runtime/start.d.ts.map +1 -1
  38. package/dist/runtime/start.js +72 -46
  39. package/dist/runtime/step-handler.d.ts +7 -0
  40. package/dist/runtime/step-handler.d.ts.map +1 -0
  41. package/dist/runtime/step-handler.js +337 -0
  42. package/dist/runtime/suspension-handler.d.ts +25 -0
  43. package/dist/runtime/suspension-handler.d.ts.map +1 -0
  44. package/dist/runtime/suspension-handler.js +182 -0
  45. package/dist/runtime/world.d.ts.map +1 -1
  46. package/dist/runtime/world.js +20 -21
  47. package/dist/runtime.d.ts +4 -105
  48. package/dist/runtime.d.ts.map +1 -1
  49. package/dist/runtime.js +97 -531
  50. package/dist/schemas.d.ts +1 -15
  51. package/dist/schemas.d.ts.map +1 -1
  52. package/dist/schemas.js +2 -15
  53. package/dist/serialization.d.ts +112 -21
  54. package/dist/serialization.d.ts.map +1 -1
  55. package/dist/serialization.js +469 -85
  56. package/dist/sleep.d.ts +10 -0
  57. package/dist/sleep.d.ts.map +1 -1
  58. package/dist/sleep.js +1 -1
  59. package/dist/source-map.d.ts +10 -0
  60. package/dist/source-map.d.ts.map +1 -0
  61. package/dist/source-map.js +56 -0
  62. package/dist/step/context-storage.d.ts +2 -1
  63. package/dist/step/context-storage.d.ts.map +1 -1
  64. package/dist/step/context-storage.js +1 -1
  65. package/dist/step/get-closure-vars.d.ts +9 -0
  66. package/dist/step/get-closure-vars.d.ts.map +1 -0
  67. package/dist/step/get-closure-vars.js +16 -0
  68. package/dist/step/get-step-metadata.js +1 -1
  69. package/dist/step/get-workflow-metadata.js +1 -1
  70. package/dist/step/writable-stream.d.ts +10 -2
  71. package/dist/step/writable-stream.d.ts.map +1 -1
  72. package/dist/step/writable-stream.js +6 -5
  73. package/dist/step.d.ts +1 -1
  74. package/dist/step.d.ts.map +1 -1
  75. package/dist/step.js +93 -47
  76. package/dist/symbols.d.ts +6 -0
  77. package/dist/symbols.d.ts.map +1 -1
  78. package/dist/symbols.js +7 -1
  79. package/dist/telemetry/semantic-conventions.d.ts +66 -38
  80. package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
  81. package/dist/telemetry/semantic-conventions.js +16 -3
  82. package/dist/telemetry.d.ts +8 -4
  83. package/dist/telemetry.d.ts.map +1 -1
  84. package/dist/telemetry.js +39 -6
  85. package/dist/types.js +1 -1
  86. package/dist/util.d.ts +5 -24
  87. package/dist/util.d.ts.map +1 -1
  88. package/dist/util.js +19 -38
  89. package/dist/version.d.ts +2 -0
  90. package/dist/version.d.ts.map +1 -0
  91. package/dist/version.js +3 -0
  92. package/dist/vm/index.js +2 -2
  93. package/dist/vm/uuid.js +1 -1
  94. package/dist/workflow/create-hook.js +1 -1
  95. package/dist/workflow/define-hook.d.ts +3 -3
  96. package/dist/workflow/define-hook.d.ts.map +1 -1
  97. package/dist/workflow/define-hook.js +1 -1
  98. package/dist/workflow/get-workflow-metadata.js +1 -1
  99. package/dist/workflow/hook.d.ts.map +1 -1
  100. package/dist/workflow/hook.js +49 -14
  101. package/dist/workflow/index.d.ts +1 -1
  102. package/dist/workflow/index.d.ts.map +1 -1
  103. package/dist/workflow/index.js +2 -2
  104. package/dist/workflow/sleep.d.ts +1 -1
  105. package/dist/workflow/sleep.d.ts.map +1 -1
  106. package/dist/workflow/sleep.js +26 -39
  107. package/dist/workflow/writable-stream.d.ts +1 -1
  108. package/dist/workflow/writable-stream.d.ts.map +1 -1
  109. package/dist/workflow/writable-stream.js +1 -1
  110. package/dist/workflow.d.ts +1 -1
  111. package/dist/workflow.d.ts.map +1 -1
  112. package/dist/workflow.js +72 -9
  113. package/docs/api-reference/create-hook.mdx +134 -0
  114. package/docs/api-reference/create-webhook.mdx +226 -0
  115. package/docs/api-reference/define-hook.mdx +207 -0
  116. package/docs/api-reference/fatal-error.mdx +38 -0
  117. package/docs/api-reference/fetch.mdx +140 -0
  118. package/docs/api-reference/get-step-metadata.mdx +77 -0
  119. package/docs/api-reference/get-workflow-metadata.mdx +45 -0
  120. package/docs/api-reference/get-writable.mdx +292 -0
  121. package/docs/api-reference/index.mdx +56 -0
  122. package/docs/api-reference/meta.json +3 -0
  123. package/docs/api-reference/retryable-error.mdx +107 -0
  124. package/docs/api-reference/sleep.mdx +60 -0
  125. package/docs/foundations/common-patterns.mdx +254 -0
  126. package/docs/foundations/errors-and-retries.mdx +191 -0
  127. package/docs/foundations/hooks.mdx +456 -0
  128. package/docs/foundations/idempotency.mdx +56 -0
  129. package/docs/foundations/index.mdx +33 -0
  130. package/docs/foundations/meta.json +14 -0
  131. package/docs/foundations/serialization.mdx +158 -0
  132. package/docs/foundations/starting-workflows.mdx +212 -0
  133. package/docs/foundations/streaming.mdx +570 -0
  134. package/docs/foundations/workflows-and-steps.mdx +198 -0
  135. package/docs/how-it-works/code-transform.mdx +335 -0
  136. package/docs/how-it-works/event-sourcing.mdx +255 -0
  137. package/docs/how-it-works/framework-integrations.mdx +438 -0
  138. package/docs/how-it-works/meta.json +10 -0
  139. package/docs/how-it-works/understanding-directives.mdx +612 -0
  140. package/package.json +31 -25
  141. package/dist/builtins.js.map +0 -1
  142. package/dist/create-hook.js.map +0 -1
  143. package/dist/define-hook.js.map +0 -1
  144. package/dist/events-consumer.js.map +0 -1
  145. package/dist/global.js.map +0 -1
  146. package/dist/index.js.map +0 -1
  147. package/dist/logger.js.map +0 -1
  148. package/dist/observability.js.map +0 -1
  149. package/dist/parse-name.d.ts +0 -25
  150. package/dist/parse-name.d.ts.map +0 -1
  151. package/dist/parse-name.js +0 -40
  152. package/dist/parse-name.js.map +0 -1
  153. package/dist/private.js.map +0 -1
  154. package/dist/runtime/resume-hook.js.map +0 -1
  155. package/dist/runtime/start.js.map +0 -1
  156. package/dist/runtime/world.js.map +0 -1
  157. package/dist/runtime.js.map +0 -1
  158. package/dist/schemas.js.map +0 -1
  159. package/dist/serialization.js.map +0 -1
  160. package/dist/sleep.js.map +0 -1
  161. package/dist/step/context-storage.js.map +0 -1
  162. package/dist/step/get-step-metadata.js.map +0 -1
  163. package/dist/step/get-workflow-metadata.js.map +0 -1
  164. package/dist/step/writable-stream.js.map +0 -1
  165. package/dist/step.js.map +0 -1
  166. package/dist/symbols.js.map +0 -1
  167. package/dist/telemetry/semantic-conventions.js.map +0 -1
  168. package/dist/telemetry.js.map +0 -1
  169. package/dist/types.js.map +0 -1
  170. package/dist/util.js.map +0 -1
  171. package/dist/vm/index.js.map +0 -1
  172. package/dist/vm/uuid.js.map +0 -1
  173. package/dist/workflow/create-hook.js.map +0 -1
  174. package/dist/workflow/define-hook.js.map +0 -1
  175. package/dist/workflow/get-workflow-metadata.js.map +0 -1
  176. package/dist/workflow/hook.js.map +0 -1
  177. package/dist/workflow/index.js.map +0 -1
  178. package/dist/workflow/sleep.js.map +0 -1
  179. package/dist/workflow/writable-stream.js.map +0 -1
  180. package/dist/workflow.js.map +0 -1
  181. package/dist/writable-stream.d.ts +0 -23
  182. package/dist/writable-stream.d.ts.map +0 -1
  183. package/dist/writable-stream.js +0 -17
  184. package/dist/writable-stream.js.map +0 -1
package/dist/builtins.js CHANGED
@@ -10,4 +10,4 @@ export async function __builtin_response_text(res) {
10
10
  'use step';
11
11
  return res.text();
12
12
  }
13
- //# sourceMappingURL=builtins.js.map
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbHRpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYnVpbHRpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxDQUFDLEtBQUssVUFBVSwrQkFBK0IsQ0FBQyxHQUFhO0lBQ2pFLFVBQVUsQ0FBQztJQUNYLE9BQU8sR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQzNCLENBQUM7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLHVCQUF1QixDQUFDLEdBQWE7SUFDekQsVUFBVSxDQUFDO0lBQ1gsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDcEIsQ0FBQztBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsdUJBQXVCLENBQUMsR0FBYTtJQUN6RCxVQUFVLENBQUM7SUFDWCxPQUFPLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUNwQixDQUFDIn0=
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Class serialization utilities.
3
+ *
4
+ * This module is separate from private.ts to avoid pulling in Node.js-only
5
+ * dependencies (like async_hooks via get-closure-vars.ts) when used in
6
+ * workflow bundles.
7
+ */
8
+ /**
9
+ * Register a class constructor for serialization.
10
+ * This allows class constructors to be deserialized by looking up the classId.
11
+ * Called by the SWC plugin in both step mode and workflow mode.
12
+ *
13
+ * Also sets the `classId` property on the class so the serializer can find it
14
+ * when serializing instances (e.g., step return values).
15
+ */
16
+ export declare function registerSerializationClass(classId: string, cls: Function): void;
17
+ /**
18
+ * Find a registered class constructor by ID (used during deserialization)
19
+ *
20
+ * @param classId - The class ID to look up
21
+ * @param global - The global object to check first. Defaults to globalThis.
22
+ * If the class is not found and `global` differs from `globalThis`,
23
+ * it will also check `globalThis` as a fallback.
24
+ */
25
+ export declare function getSerializationClass(classId: string, global?: Record<string, any>): Function | undefined;
26
+ //# sourceMappingURL=class-serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-serialization.d.ts","sourceRoot":"","sources":["../src/class-serialization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuBH;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,QASxE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAc,GAEvC,QAAQ,GAAG,SAAS,CAatB"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Class serialization utilities.
3
+ *
4
+ * This module is separate from private.ts to avoid pulling in Node.js-only
5
+ * dependencies (like async_hooks via get-closure-vars.ts) when used in
6
+ * workflow bundles.
7
+ */
8
+ import { WORKFLOW_CLASS_REGISTRY } from './symbols.js';
9
+ /**
10
+ * Get or create the class registry on the given global object.
11
+ * This works isomorphically in both step mode (main context) and workflow mode (VM context).
12
+ *
13
+ * @param global - The global object to use. Defaults to globalThis, but can be a VM's global.
14
+ */
15
+ function getRegistry(global = globalThis) {
16
+ const g = global;
17
+ let registry = g[WORKFLOW_CLASS_REGISTRY];
18
+ if (!registry) {
19
+ registry = new Map();
20
+ g[WORKFLOW_CLASS_REGISTRY] = registry;
21
+ }
22
+ return registry;
23
+ }
24
+ /**
25
+ * Register a class constructor for serialization.
26
+ * This allows class constructors to be deserialized by looking up the classId.
27
+ * Called by the SWC plugin in both step mode and workflow mode.
28
+ *
29
+ * Also sets the `classId` property on the class so the serializer can find it
30
+ * when serializing instances (e.g., step return values).
31
+ */
32
+ // biome-ignore lint/complexity/noBannedTypes: We need to use Function to represent class constructors
33
+ export function registerSerializationClass(classId, cls) {
34
+ getRegistry().set(classId, cls);
35
+ // Set classId on the class for serialization
36
+ Object.defineProperty(cls, 'classId', {
37
+ value: classId,
38
+ writable: false,
39
+ enumerable: false,
40
+ configurable: false,
41
+ });
42
+ }
43
+ /**
44
+ * Find a registered class constructor by ID (used during deserialization)
45
+ *
46
+ * @param classId - The class ID to look up
47
+ * @param global - The global object to check first. Defaults to globalThis.
48
+ * If the class is not found and `global` differs from `globalThis`,
49
+ * it will also check `globalThis` as a fallback.
50
+ */
51
+ export function getSerializationClass(classId, global = globalThis
52
+ // biome-ignore lint/complexity/noBannedTypes: We need to use Function to represent class constructors
53
+ ) {
54
+ // Check the provided global first
55
+ const cls = getRegistry(global).get(classId);
56
+ if (cls)
57
+ return cls;
58
+ // Fallback: check globalThis if it differs from the provided global
59
+ // This handles the case where classes are registered in the host context
60
+ // but deserialization happens in a VM context
61
+ if (global !== globalThis) {
62
+ return getRegistry(globalThis).get(classId);
63
+ }
64
+ return undefined;
65
+ }
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Mtc2VyaWFsaXphdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jbGFzcy1zZXJpYWxpemF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUt2RDs7Ozs7R0FLRztBQUNILFNBQVMsV0FBVyxDQUFDLFNBQThCLFVBQVU7SUFDM0QsTUFBTSxDQUFDLEdBQUcsTUFBYSxDQUFDO0lBQ3hCLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQyx1QkFBdUIsQ0FBOEIsQ0FBQztJQUN2RSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDZCxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNyQixDQUFDLENBQUMsdUJBQXVCLENBQUMsR0FBRyxRQUFRLENBQUM7SUFDeEMsQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsc0dBQXNHO0FBQ3RHLE1BQU0sVUFBVSwwQkFBMEIsQ0FBQyxPQUFlLEVBQUUsR0FBYTtJQUN2RSxXQUFXLEVBQUUsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ2hDLDZDQUE2QztJQUM3QyxNQUFNLENBQUMsY0FBYyxDQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUU7UUFDcEMsS0FBSyxFQUFFLE9BQU87UUFDZCxRQUFRLEVBQUUsS0FBSztRQUNmLFVBQVUsRUFBRSxLQUFLO1FBQ2pCLFlBQVksRUFBRSxLQUFLO0tBQ3BCLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLHFCQUFxQixDQUNuQyxPQUFlLEVBQ2YsU0FBOEIsVUFBVTtBQUN4QyxzR0FBc0c7O0lBRXRHLGtDQUFrQztJQUNsQyxNQUFNLEdBQUcsR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzdDLElBQUksR0FBRztRQUFFLE9BQU8sR0FBRyxDQUFDO0lBRXBCLG9FQUFvRTtJQUNwRSx5RUFBeUU7SUFDekUsOENBQThDO0lBQzlDLElBQUksTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO1FBQzFCLE9BQU8sV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRUQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyJ9
@@ -29,4 +29,4 @@ export function createWebhook(
29
29
  options) {
30
30
  throw new Error('`createWebhook()` can only be called inside a workflow function');
31
31
  }
32
- //# sourceMappingURL=create-hook.js.map
32
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLWhvb2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY3JlYXRlLWhvb2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBK0ZBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxvREFBb0Q7QUFDcEQsTUFBTSxVQUFVLFVBQVUsQ0FBVSxPQUFxQjtJQUN2RCxNQUFNLElBQUksS0FBSyxDQUNiLDhEQUE4RCxDQUMvRCxDQUFDO0FBQ0osQ0FBQztBQWFELE1BQU0sVUFBVSxhQUFhO0FBQzNCLG9EQUFvRDtBQUNwRCxPQUF3QjtJQUV4QixNQUFNLElBQUksS0FBSyxDQUNiLGlFQUFpRSxDQUNsRSxDQUFDO0FBQ0osQ0FBQyJ9
@@ -1,12 +1,44 @@
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
1
2
  import type { Hook as HookEntity } from '@workflow/world';
2
3
  import type { Hook, HookOptions } from './create-hook.js';
4
+ /**
5
+ * A typed hook interface for type-safe hook creation and resumption.
6
+ */
7
+ export interface TypedHook<TInput, TOutput> {
8
+ /**
9
+ * Creates a new hook with the defined output type.
10
+ *
11
+ * Note: This method is not available in runtime bundles. Use it from workflow contexts only.
12
+ *
13
+ * @param options - Optional hook configuration
14
+ * @returns A Hook that resolves to the defined output type
15
+ */
16
+ create(options?: HookOptions): Hook<TOutput>;
17
+ /**
18
+ * Resumes a hook by sending a payload with the defined input type.
19
+ * This is a type-safe wrapper around the `resumeHook` runtime function.
20
+ *
21
+ * @param token - The unique token identifying the hook
22
+ * @param payload - The payload to send; if a `schema` is configured it is validated/transformed before resuming
23
+ * @returns Promise resolving to the hook entity
24
+ * @throws Error if the hook is not found or if there's an error during the process
25
+ */
26
+ resume(token: string, payload: TInput): Promise<HookEntity>;
27
+ }
28
+ export declare namespace TypedHook {
29
+ /**
30
+ * Extracts the input type from a {@link TypedHook}
31
+ */
32
+ type Input<T extends TypedHook<any, any>> = T extends TypedHook<infer I, any> ? I : never;
33
+ }
3
34
  /**
4
35
  * Defines a typed hook for type-safe hook creation and resumption.
5
36
  *
6
- * This helper provides type safety by allowing you to define the payload type once
7
- * and reuse it when creating hooks and resuming them.
37
+ * This helper provides type safety by allowing you to define the input and output types
38
+ * for the hook's payload, with optional validation and transformation via a schema.
8
39
  *
9
- * @returns An object with `create` and `resume` functions pre-typed with the payload type
40
+ * @param schema - Schema used to validate and transform the input payload before resuming
41
+ * @returns An object with `create` and `resume` functions pre-typed with the input and output types
10
42
  *
11
43
  * @example
12
44
  *
@@ -19,35 +51,18 @@ import type { Hook, HookOptions } from './create-hook.js';
19
51
  * "use workflow";
20
52
  *
21
53
  * const hook = approvalHook.create();
22
- * const result = await hook; // Fully typed as { approved: boolean; comment: string }
54
+ * const result = await hook; // Fully typed as { approved: boolean; comment: string; }
23
55
  * }
24
56
  *
25
57
  * // In an API route
26
58
  * export async function POST(request: Request) {
27
59
  * const { token, approved, comment } = await request.json();
28
- * await approvalHook.resume(token, { approved, comment });
60
+ * await approvalHook.resume(token, { approved, comment }); // Input type
29
61
  * return Response.json({ success: true });
30
62
  * }
31
63
  * ```
32
64
  */
33
- export declare function defineHook<T>(): {
34
- /**
35
- * Creates a new hook with the defined payload type.
36
- *
37
- * Note: This method is not available in runtime bundles. Use it from workflow contexts only.
38
- *
39
- * @param _options - Optional hook configuration
40
- * @returns A Hook that resolves to the defined payload type
41
- */
42
- create(options?: HookOptions): Hook<T>;
43
- /**
44
- * Resumes a hook by sending a payload with the defined type.
45
- * This is a type-safe wrapper around the `resumeHook` runtime function.
46
- *
47
- * @param token - The unique token identifying the hook
48
- * @param payload - The payload to send (must match the defined type)
49
- * @returns Promise resolving to the hook entity, or null if the hook doesn't exist
50
- */
51
- resume(token: string, payload: T): Promise<HookEntity | null>;
52
- };
65
+ export declare function defineHook<TInput, TOutput = TInput>({ schema, }?: {
66
+ schema?: StandardSchemaV1<TInput, TOutput>;
67
+ }): TypedHook<TInput, TOutput>;
53
68
  //# sourceMappingURL=define-hook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"define-hook.d.ts","sourceRoot":"","sources":["../src/define-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,UAAU,CAAC,CAAC;IAExB;;;;;;;OAOG;qBAEc,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;IAMtC;;;;;;;OAOG;kBACW,MAAM,WAAW,CAAC,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;EAIhE"}
1
+ {"version":3,"file":"define-hook.d.ts","sourceRoot":"","sources":["../src/define-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG1D;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,MAAM,EAAE,OAAO;IACxC;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC7D;AAED,yBAAiB,SAAS,CAAC;IACzB;;OAEG;IACH,KAAY,KAAK,CAAC,CAAC,SAAS,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,SAAS,CACpE,MAAM,CAAC,EACP,GAAG,CACJ,GACG,CAAC,GACD,KAAK,CAAC;CACX;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,EACnD,MAAM,GACP,GAAE;IACD,MAAM,CAAC,EAAE,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBlC"}
@@ -2,10 +2,11 @@ import { resumeHook } from './runtime/resume-hook.js';
2
2
  /**
3
3
  * Defines a typed hook for type-safe hook creation and resumption.
4
4
  *
5
- * This helper provides type safety by allowing you to define the payload type once
6
- * and reuse it when creating hooks and resuming them.
5
+ * This helper provides type safety by allowing you to define the input and output types
6
+ * for the hook's payload, with optional validation and transformation via a schema.
7
7
  *
8
- * @returns An object with `create` and `resume` functions pre-typed with the payload type
8
+ * @param schema - Schema used to validate and transform the input payload before resuming
9
+ * @returns An object with `create` and `resume` functions pre-typed with the input and output types
9
10
  *
10
11
  * @example
11
12
  *
@@ -18,42 +19,36 @@ import { resumeHook } from './runtime/resume-hook.js';
18
19
  * "use workflow";
19
20
  *
20
21
  * const hook = approvalHook.create();
21
- * const result = await hook; // Fully typed as { approved: boolean; comment: string }
22
+ * const result = await hook; // Fully typed as { approved: boolean; comment: string; }
22
23
  * }
23
24
  *
24
25
  * // In an API route
25
26
  * export async function POST(request: Request) {
26
27
  * const { token, approved, comment } = await request.json();
27
- * await approvalHook.resume(token, { approved, comment });
28
+ * await approvalHook.resume(token, { approved, comment }); // Input type
28
29
  * return Response.json({ success: true });
29
30
  * }
30
31
  * ```
31
32
  */
32
- export function defineHook() {
33
+ export function defineHook({ schema, } = {}) {
33
34
  return {
34
- /**
35
- * Creates a new hook with the defined payload type.
36
- *
37
- * Note: This method is not available in runtime bundles. Use it from workflow contexts only.
38
- *
39
- * @param _options - Optional hook configuration
40
- * @returns A Hook that resolves to the defined payload type
41
- */
42
- // @ts-expect-error `options` is here for types/docs
43
- create(options) {
35
+ create(_options) {
44
36
  throw new Error('`defineHook().create()` can only be called inside a workflow function.');
45
37
  },
46
- /**
47
- * Resumes a hook by sending a payload with the defined type.
48
- * This is a type-safe wrapper around the `resumeHook` runtime function.
49
- *
50
- * @param token - The unique token identifying the hook
51
- * @param payload - The payload to send (must match the defined type)
52
- * @returns Promise resolving to the hook entity, or null if the hook doesn't exist
53
- */
54
- resume(token, payload) {
55
- return resumeHook(token, payload);
38
+ async resume(token, payload) {
39
+ if (!schema?.['~standard']) {
40
+ return await resumeHook(token, payload);
41
+ }
42
+ let result = schema['~standard'].validate(payload);
43
+ if (result instanceof Promise) {
44
+ result = await result;
45
+ }
46
+ // if the `issues` field exists, the validation failed
47
+ if (result.issues) {
48
+ throw new Error(JSON.stringify(result.issues, null, 2));
49
+ }
50
+ return await resumeHook(token, result.value);
56
51
  },
57
52
  };
58
53
  }
59
- //# sourceMappingURL=define-hook.js.map
54
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmaW5lLWhvb2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZGVmaW5lLWhvb2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBdUN0RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOEJHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBMkIsRUFDbkQsTUFBTSxNQUdKLEVBQUU7SUFDSixPQUFPO1FBQ0wsTUFBTSxDQUFDLFFBQXNCO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQ2Isd0VBQXdFLENBQ3pFLENBQUM7UUFDSixDQUFDO1FBQ0QsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFhLEVBQUUsT0FBZTtZQUN6QyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDM0IsT0FBTyxNQUFNLFVBQVUsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDMUMsQ0FBQztZQUVELElBQUksTUFBTSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDbkQsSUFBSSxNQUFNLFlBQVksT0FBTyxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQztZQUN4QixDQUFDO1lBRUQsc0RBQXNEO1lBQ3RELElBQUksTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNsQixNQUFNLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMxRCxDQUFDO1lBRUQsT0FBTyxNQUFNLFVBQVUsQ0FBVSxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hELENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyJ9
@@ -1 +1 @@
1
- {"version":3,"file":"events-consumer.d.ts","sourceRoot":"","sources":["../src/events-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAG7C,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,QAAQ,IAAA;IACR;;OAEG;IACH,WAAW,IAAA;IACX;;OAEG;IACH,QAAQ,IAAA;CACT;AAED,KAAK,qBAAqB,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,KAAK,mBAAmB,CAAC;AAE1E,qBAAa,cAAc;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAM;IAC9B,QAAQ,CAAC,SAAS,EAAE,qBAAqB,EAAE,CAAM;gBAErC,MAAM,EAAE,KAAK,EAAE;IAO3B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,EAAE,qBAAqB;IAKnC,OAAO,CAAC,OAAO,CAkCb;CACH"}
1
+ {"version":3,"file":"events-consumer.d.ts","sourceRoot":"","sources":["../src/events-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAG7C,oBAAY,mBAAmB;IAC7B;;OAEG;IACH,QAAQ,IAAA;IACR;;OAEG;IACH,WAAW,IAAA;IACX;;OAEG;IACH,QAAQ,IAAA;CACT;AAED,KAAK,qBAAqB,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,KAAK,mBAAmB,CAAC;AAE1E,qBAAa,cAAc;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAM;IAC9B,QAAQ,CAAC,SAAS,EAAE,qBAAqB,EAAE,CAAM;gBAErC,MAAM,EAAE,KAAK,EAAE;IAO3B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,EAAE,qBAAqB;IAKnC,OAAO,CAAC,OAAO,CAuCb;CACH"}
@@ -67,6 +67,10 @@ export class EventsConsumer {
67
67
  return;
68
68
  }
69
69
  }
70
+ // If we reach here, all callbacks returned NotConsumed.
71
+ // We do NOT auto-advance - every event must have a consumer.
72
+ // With proper consumers for run_created/run_started/step_created,
73
+ // this should not cause events to get stuck.
70
74
  };
71
75
  }
72
- //# sourceMappingURL=events-consumer.js.map
76
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLWNvbnN1bWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2V2ZW50cy1jb25zdW1lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTNDLE1BQU0sQ0FBTixJQUFZLG1CQWFYO0FBYkQsV0FBWSxtQkFBbUI7SUFDN0I7O09BRUc7SUFDSCxxRUFBUSxDQUFBO0lBQ1I7O09BRUc7SUFDSCwyRUFBVyxDQUFBO0lBQ1g7O09BRUc7SUFDSCxxRUFBUSxDQUFBO0FBQ1YsQ0FBQyxFQWJXLG1CQUFtQixLQUFuQixtQkFBbUIsUUFhOUI7QUFJRCxNQUFNLE9BQU8sY0FBYztJQUN6QixVQUFVLENBQVM7SUFDVixNQUFNLEdBQVksRUFBRSxDQUFDO0lBQ3JCLFNBQVMsR0FBNEIsRUFBRSxDQUFDO0lBRWpELFlBQVksTUFBZTtRQUN6QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztRQUVwQixZQUFZLENBQUMsS0FBSyxDQUFDLDRCQUE0QixFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxTQUFTLENBQUMsRUFBeUI7UUFDakMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDeEIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVPLE9BQU8sR0FBRyxHQUFHLEVBQUU7UUFDckIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxDQUFDO1FBQzFELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQy9DLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkMsSUFBSSxPQUFPLEdBQUcsbUJBQW1CLENBQUMsV0FBVyxDQUFDO1lBQzlDLElBQUksQ0FBQztnQkFDSCxPQUFPLEdBQUcsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ25DLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLFlBQVksQ0FBQyxLQUFLLENBQUMsdUNBQXVDLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO2dCQUN2RSxzRUFBc0U7Z0JBQ3RFLE9BQU8sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDaEUsQ0FBQztZQUNELFlBQVksQ0FBQyxLQUFLLENBQUMsK0JBQStCLEVBQUU7Z0JBQ2xELE9BQU8sRUFBRSxtQkFBbUIsQ0FBQyxPQUFPLENBQUM7Z0JBQ3JDLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDM0IsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPO2FBQy9CLENBQUMsQ0FBQztZQUNILElBQ0UsT0FBTyxLQUFLLG1CQUFtQixDQUFDLFFBQVE7Z0JBQ3hDLE9BQU8sS0FBSyxtQkFBbUIsQ0FBQyxRQUFRLEVBQ3hDLENBQUM7Z0JBQ0QsMkRBQTJEO2dCQUMzRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBRWxCLHlDQUF5QztnQkFDekMsSUFBSSxPQUFPLEtBQUssbUJBQW1CLENBQUMsUUFBUSxFQUFFLENBQUM7b0JBQzdDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDOUIsQ0FBQztnQkFFRCw2QkFBNkI7Z0JBQzdCLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUMvQixPQUFPO1lBQ1QsQ0FBQztRQUNILENBQUM7UUFFRCx3REFBd0Q7UUFDeEQsNkRBQTZEO1FBQzdELGtFQUFrRTtRQUNsRSw2Q0FBNkM7SUFDL0MsQ0FBQyxDQUFDO0NBQ0gifQ==
@@ -0,0 +1,82 @@
1
+ import { type PromiseWithResolvers } from '@workflow/utils';
2
+ /**
3
+ * Polling interval (in ms) for lock release detection.
4
+ *
5
+ * The Web Streams API does not expose an event for "lock released but stream
6
+ * still open"; we can only distinguish that state by periodically attempting
7
+ * to acquire a reader/writer. For that reason we use polling instead of a
8
+ * fully event-driven approach here.
9
+ *
10
+ * 100ms is a compromise between:
11
+ * - Latency: how quickly we notice that the user has released their lock, and
12
+ * - Cost/CPU usage: how often timers fire, especially with many concurrent
13
+ * streams or in serverless environments where billed time matters.
14
+ *
15
+ * This value should only be changed with care, as decreasing it will
16
+ * increase polling frequency (and thus potential cost), while increasing it
17
+ * will add worst-case delay before the `done` promise resolves after a lock
18
+ * is released.
19
+ */
20
+ export declare const LOCK_POLL_INTERVAL_MS = 100;
21
+ /**
22
+ * State tracker for flushable stream operations.
23
+ * Resolves when either:
24
+ * 1. Stream completes (close/error), OR
25
+ * 2. Lock is released AND all pending operations are flushed
26
+ *
27
+ * Note: `doneResolved` and `streamEnded` are separate:
28
+ * - `doneResolved`: The `done` promise has been resolved (step can complete)
29
+ * - `streamEnded`: The underlying stream has actually closed/errored
30
+ *
31
+ * Once `doneResolved` is set to true, the `done` promise will not resolve
32
+ * again. Re-acquiring locks after release is not supported as a way to
33
+ * trigger additional completion signaling.
34
+ */
35
+ export interface FlushableStreamState extends PromiseWithResolvers<void> {
36
+ /** Number of write operations currently in flight to the server */
37
+ pendingOps: number;
38
+ /** Whether the `done` promise has been resolved */
39
+ doneResolved: boolean;
40
+ /** Whether the underlying stream has actually closed/errored */
41
+ streamEnded: boolean;
42
+ /** Interval ID for writable lock polling (if active) */
43
+ writablePollingInterval?: ReturnType<typeof setInterval>;
44
+ /** Interval ID for readable lock polling (if active) */
45
+ readablePollingInterval?: ReturnType<typeof setInterval>;
46
+ }
47
+ export declare function createFlushableState(): FlushableStreamState;
48
+ /**
49
+ * Polls a WritableStream to check if the user has released their lock.
50
+ * Resolves the done promise when lock is released and no pending ops remain.
51
+ *
52
+ * Note: Only resolves if stream is unlocked but NOT closed. If the user closes
53
+ * the stream, the pump will handle resolution via the stream ending naturally.
54
+ *
55
+ * Protection: If polling is already active on this state, the existing interval
56
+ * is used to avoid creating multiple simultaneous polling operations.
57
+ */
58
+ export declare function pollWritableLock(writable: WritableStream, state: FlushableStreamState): void;
59
+ /**
60
+ * Polls a ReadableStream to check if the user has released their lock.
61
+ * Resolves the done promise when lock is released and no pending ops remain.
62
+ *
63
+ * Note: Only resolves if stream is unlocked but NOT closed. If the user closes
64
+ * the stream, the pump will handle resolution via the stream ending naturally.
65
+ *
66
+ * Protection: If polling is already active on this state, the existing interval
67
+ * is used to avoid creating multiple simultaneous polling operations.
68
+ */
69
+ export declare function pollReadableLock(readable: ReadableStream, state: FlushableStreamState): void;
70
+ /**
71
+ * Creates a flushable pipe from a ReadableStream to a WritableStream.
72
+ * Unlike pipeTo(), this resolves when:
73
+ * 1. The source stream completes (close/error), OR
74
+ * 2. The user releases their lock on userStream AND all pending writes are flushed
75
+ *
76
+ * @param source - The readable stream to read from (e.g., transform's readable)
77
+ * @param sink - The writable stream to write to (e.g., server writable)
78
+ * @param state - The flushable state tracker
79
+ * @returns Promise that resolves when stream ends (not when done promise resolves)
80
+ */
81
+ export declare function flushablePipe(source: ReadableStream, sink: WritableStream, state: FlushableStreamState): Promise<void>;
82
+ //# sourceMappingURL=flushable-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flushable-stream.d.ts","sourceRoot":"","sources":["../src/flushable-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAiB,MAAM,iBAAiB,CAAC;AAE3E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB,CAAC,IAAI,CAAC;IACtE,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,YAAY,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,WAAW,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,uBAAuB,CAAC,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;IACzD,wDAAwD;IACxD,uBAAuB,CAAC,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CAC1D;AAED,wBAAgB,oBAAoB,IAAI,oBAAoB,CAO3D;AA2DD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,oBAAoB,GAC1B,IAAI,CAwBN;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,oBAAoB,GAC1B,IAAI,CAwBN;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAwDf"}
@@ -0,0 +1,214 @@
1
+ import { withResolvers } from '@workflow/utils';
2
+ /**
3
+ * Polling interval (in ms) for lock release detection.
4
+ *
5
+ * The Web Streams API does not expose an event for "lock released but stream
6
+ * still open"; we can only distinguish that state by periodically attempting
7
+ * to acquire a reader/writer. For that reason we use polling instead of a
8
+ * fully event-driven approach here.
9
+ *
10
+ * 100ms is a compromise between:
11
+ * - Latency: how quickly we notice that the user has released their lock, and
12
+ * - Cost/CPU usage: how often timers fire, especially with many concurrent
13
+ * streams or in serverless environments where billed time matters.
14
+ *
15
+ * This value should only be changed with care, as decreasing it will
16
+ * increase polling frequency (and thus potential cost), while increasing it
17
+ * will add worst-case delay before the `done` promise resolves after a lock
18
+ * is released.
19
+ */
20
+ export const LOCK_POLL_INTERVAL_MS = 100;
21
+ export function createFlushableState() {
22
+ return {
23
+ ...withResolvers(),
24
+ pendingOps: 0,
25
+ doneResolved: false,
26
+ streamEnded: false,
27
+ };
28
+ }
29
+ /**
30
+ * Checks if a WritableStream is unlocked (user released lock) vs closed.
31
+ * When a stream is closed, .locked is false but getWriter() throws.
32
+ * We only want to resolve via polling when the stream is unlocked, not closed.
33
+ * If closed, the pump will handle resolution via the stream ending naturally.
34
+ */
35
+ function isWritableUnlockedNotClosed(writable) {
36
+ if (writable.locked)
37
+ return false;
38
+ let writer;
39
+ try {
40
+ // Try to acquire writer - if successful, stream is unlocked (not closed)
41
+ writer = writable.getWriter();
42
+ }
43
+ catch {
44
+ // getWriter() throws if stream is closed/errored - let pump handle it
45
+ return false;
46
+ }
47
+ try {
48
+ writer.releaseLock();
49
+ }
50
+ catch {
51
+ // If releaseLock() throws for any reason, conservatively treat the
52
+ // stream as closed/errored so callers don't assume it's safe to use.
53
+ // The pump will observe the failure via the stream's end state.
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+ /**
59
+ * Checks if a ReadableStream is unlocked (user released lock) vs closed.
60
+ */
61
+ function isReadableUnlockedNotClosed(readable) {
62
+ if (readable.locked)
63
+ return false;
64
+ let reader;
65
+ try {
66
+ // Try to acquire reader - if successful, stream is unlocked (not closed)
67
+ reader = readable.getReader();
68
+ }
69
+ catch {
70
+ // getReader() throws if stream is closed/errored - let pump handle it
71
+ return false;
72
+ }
73
+ try {
74
+ reader.releaseLock();
75
+ }
76
+ catch {
77
+ // If releaseLock() throws for any reason, conservatively treat the
78
+ // stream as closed/errored so callers don't assume it's safe to use.
79
+ // The pump will observe the failure via the stream's end state.
80
+ return false;
81
+ }
82
+ return true;
83
+ }
84
+ /**
85
+ * Polls a WritableStream to check if the user has released their lock.
86
+ * Resolves the done promise when lock is released and no pending ops remain.
87
+ *
88
+ * Note: Only resolves if stream is unlocked but NOT closed. If the user closes
89
+ * the stream, the pump will handle resolution via the stream ending naturally.
90
+ *
91
+ * Protection: If polling is already active on this state, the existing interval
92
+ * is used to avoid creating multiple simultaneous polling operations.
93
+ */
94
+ export function pollWritableLock(writable, state) {
95
+ // Prevent multiple simultaneous polling on the same state
96
+ if (state.writablePollingInterval !== undefined) {
97
+ return;
98
+ }
99
+ const intervalId = setInterval(() => {
100
+ // Stop polling if already resolved or stream ended
101
+ if (state.doneResolved || state.streamEnded) {
102
+ clearInterval(intervalId);
103
+ state.writablePollingInterval = undefined;
104
+ return;
105
+ }
106
+ // Check if lock is released (not closed) and no pending ops
107
+ if (isWritableUnlockedNotClosed(writable) && state.pendingOps === 0) {
108
+ state.doneResolved = true;
109
+ state.resolve();
110
+ clearInterval(intervalId);
111
+ state.writablePollingInterval = undefined;
112
+ }
113
+ }, LOCK_POLL_INTERVAL_MS);
114
+ state.writablePollingInterval = intervalId;
115
+ }
116
+ /**
117
+ * Polls a ReadableStream to check if the user has released their lock.
118
+ * Resolves the done promise when lock is released and no pending ops remain.
119
+ *
120
+ * Note: Only resolves if stream is unlocked but NOT closed. If the user closes
121
+ * the stream, the pump will handle resolution via the stream ending naturally.
122
+ *
123
+ * Protection: If polling is already active on this state, the existing interval
124
+ * is used to avoid creating multiple simultaneous polling operations.
125
+ */
126
+ export function pollReadableLock(readable, state) {
127
+ // Prevent multiple simultaneous polling on the same state
128
+ if (state.readablePollingInterval !== undefined) {
129
+ return;
130
+ }
131
+ const intervalId = setInterval(() => {
132
+ // Stop polling if already resolved or stream ended
133
+ if (state.doneResolved || state.streamEnded) {
134
+ clearInterval(intervalId);
135
+ state.readablePollingInterval = undefined;
136
+ return;
137
+ }
138
+ // Check if lock is released (not closed) and no pending ops
139
+ if (isReadableUnlockedNotClosed(readable) && state.pendingOps === 0) {
140
+ state.doneResolved = true;
141
+ state.resolve();
142
+ clearInterval(intervalId);
143
+ state.readablePollingInterval = undefined;
144
+ }
145
+ }, LOCK_POLL_INTERVAL_MS);
146
+ state.readablePollingInterval = intervalId;
147
+ }
148
+ /**
149
+ * Creates a flushable pipe from a ReadableStream to a WritableStream.
150
+ * Unlike pipeTo(), this resolves when:
151
+ * 1. The source stream completes (close/error), OR
152
+ * 2. The user releases their lock on userStream AND all pending writes are flushed
153
+ *
154
+ * @param source - The readable stream to read from (e.g., transform's readable)
155
+ * @param sink - The writable stream to write to (e.g., server writable)
156
+ * @param state - The flushable state tracker
157
+ * @returns Promise that resolves when stream ends (not when done promise resolves)
158
+ */
159
+ export async function flushablePipe(source, sink, state) {
160
+ const reader = source.getReader();
161
+ const writer = sink.getWriter();
162
+ try {
163
+ while (true) {
164
+ // Check if stream has ended
165
+ if (state.streamEnded) {
166
+ return;
167
+ }
168
+ // Read from source - don't count as pending op since we're just waiting for data
169
+ // The important ops are writes to the sink (server)
170
+ const readResult = await reader.read();
171
+ // Check if stream has ended (e.g., due to error in another path) before processing
172
+ if (state.streamEnded) {
173
+ return;
174
+ }
175
+ if (readResult.done) {
176
+ // Source stream completed - close sink and resolve
177
+ state.streamEnded = true;
178
+ await writer.close();
179
+ // Resolve done promise if not already resolved
180
+ if (!state.doneResolved) {
181
+ state.doneResolved = true;
182
+ state.resolve();
183
+ }
184
+ return;
185
+ }
186
+ // Count write as a pending op - this is what we need to flush
187
+ state.pendingOps++;
188
+ try {
189
+ await writer.write(readResult.value);
190
+ }
191
+ finally {
192
+ state.pendingOps--;
193
+ }
194
+ }
195
+ }
196
+ catch (err) {
197
+ state.streamEnded = true;
198
+ if (!state.doneResolved) {
199
+ state.doneResolved = true;
200
+ state.reject(err);
201
+ }
202
+ // Propagate error through flushablePipe's own promise as well.
203
+ // Callers that rely on the FlushableStreamState should use `state.promise`,
204
+ // while other callers may depend on this rejection. Some known callers
205
+ // explicitly ignore this rejection (`.catch(() => {})`) and rely solely
206
+ // on `state.reject(err)` for error handling.
207
+ throw err;
208
+ }
209
+ finally {
210
+ reader.releaseLock();
211
+ writer.releaseLock();
212
+ }
213
+ }
214
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmx1c2hhYmxlLXN0cmVhbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9mbHVzaGFibGUtc3RyZWFtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBNkIsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFM0U7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBQ0gsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBNkJ6QyxNQUFNLFVBQVUsb0JBQW9CO0lBQ2xDLE9BQU87UUFDTCxHQUFHLGFBQWEsRUFBUTtRQUN4QixVQUFVLEVBQUUsQ0FBQztRQUNiLFlBQVksRUFBRSxLQUFLO1FBQ25CLFdBQVcsRUFBRSxLQUFLO0tBQ25CLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFTLDJCQUEyQixDQUFDLFFBQXdCO0lBQzNELElBQUksUUFBUSxDQUFDLE1BQU07UUFBRSxPQUFPLEtBQUssQ0FBQztJQUVsQyxJQUFJLE1BQStDLENBQUM7SUFDcEQsSUFBSSxDQUFDO1FBQ0gseUVBQXlFO1FBQ3pFLE1BQU0sR0FBRyxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLHNFQUFzRTtRQUN0RSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxJQUFJLENBQUM7UUFDSCxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLG1FQUFtRTtRQUNuRSxxRUFBcUU7UUFDckUsZ0VBQWdFO1FBQ2hFLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUywyQkFBMkIsQ0FBQyxRQUF3QjtJQUMzRCxJQUFJLFFBQVEsQ0FBQyxNQUFNO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFFbEMsSUFBSSxNQUErQyxDQUFDO0lB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
package/dist/global.d.ts CHANGED
@@ -4,6 +4,9 @@ export interface StepInvocationQueueItem {
4
4
  correlationId: string;
5
5
  stepName: string;
6
6
  args: Serializable[];
7
+ closureVars?: Record<string, Serializable>;
8
+ thisVal?: Serializable;
9
+ hasCreatedEvent?: boolean;
7
10
  }
8
11
  export interface HookInvocationQueueItem {
9
12
  type: 'hook';
@@ -30,7 +33,7 @@ export declare class WorkflowSuspension extends Error {
30
33
  stepCount: number;
31
34
  hookCount: number;
32
35
  waitCount: number;
33
- constructor(steps: QueueItem[], global: typeof globalThis);
36
+ constructor(stepsInput: Map<string, QueueItem>, global: typeof globalThis);
34
37
  static is(value: unknown): value is WorkflowSuspension;
35
38
  }
36
39
  export declare function ENOTSUP(): never;
@@ -1 +1 @@
1
- {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../src/global.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,YAAY,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,IAAI,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GACjB,uBAAuB,GACvB,uBAAuB,GACvB,uBAAuB,CAAC;AAE5B;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;gBAEN,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,OAAO,UAAU;IA4CzD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB;CAGvD;AAED,wBAAgB,OAAO,IAAI,KAAK,CAE/B"}
1
+ {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../src/global.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,IAAI,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GACjB,uBAAuB,GACvB,uBAAuB,GACvB,uBAAuB,CAAC;AAE5B;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;gBAEN,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,UAAU;IAqDzE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB;CAGvD;AAED,wBAAgB,OAAO,IAAI,KAAK,CAE/B"}