@hotmeshio/hotmesh 0.7.0 → 0.9.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 (138) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/README.md +158 -38
  3. package/build/index.d.ts +1 -3
  4. package/build/index.js +1 -5
  5. package/build/modules/utils.js +3 -31
  6. package/build/package.json +63 -79
  7. package/build/services/activities/activity.d.ts +97 -9
  8. package/build/services/activities/activity.js +323 -86
  9. package/build/services/activities/await.d.ts +101 -0
  10. package/build/services/activities/await.js +103 -2
  11. package/build/services/activities/cycle.d.ts +82 -0
  12. package/build/services/activities/cycle.js +86 -8
  13. package/build/services/activities/hook.d.ts +144 -1
  14. package/build/services/activities/hook.js +162 -21
  15. package/build/services/activities/interrupt.d.ts +112 -0
  16. package/build/services/activities/interrupt.js +134 -29
  17. package/build/services/activities/signal.d.ts +111 -4
  18. package/build/services/activities/signal.js +136 -28
  19. package/build/services/activities/trigger.d.ts +56 -4
  20. package/build/services/activities/trigger.js +119 -35
  21. package/build/services/activities/worker.d.ts +107 -0
  22. package/build/services/activities/worker.js +109 -2
  23. package/build/services/collator/index.d.ts +116 -30
  24. package/build/services/collator/index.js +211 -115
  25. package/build/services/connector/factory.d.ts +1 -1
  26. package/build/services/connector/factory.js +1 -11
  27. package/build/services/engine/index.d.ts +22 -6
  28. package/build/services/engine/index.js +49 -18
  29. package/build/services/exporter/index.d.ts +2 -0
  30. package/build/services/exporter/index.js +1 -0
  31. package/build/services/hotmesh/index.d.ts +471 -236
  32. package/build/services/hotmesh/index.js +473 -238
  33. package/build/services/memflow/client.js +2 -2
  34. package/build/services/memflow/handle.js +1 -1
  35. package/build/services/memflow/index.d.ts +1 -1
  36. package/build/services/memflow/index.js +1 -1
  37. package/build/services/memflow/workflow/all.d.ts +28 -3
  38. package/build/services/memflow/workflow/all.js +28 -3
  39. package/build/services/memflow/workflow/context.d.ts +44 -1
  40. package/build/services/memflow/workflow/context.js +44 -1
  41. package/build/services/memflow/workflow/didRun.d.ts +23 -3
  42. package/build/services/memflow/workflow/didRun.js +23 -3
  43. package/build/services/memflow/workflow/emit.d.ts +43 -4
  44. package/build/services/memflow/workflow/emit.js +43 -4
  45. package/build/services/memflow/workflow/enrich.d.ts +32 -4
  46. package/build/services/memflow/workflow/enrich.js +32 -4
  47. package/build/services/memflow/workflow/entityMethods.d.ts +54 -7
  48. package/build/services/memflow/workflow/entityMethods.js +54 -7
  49. package/build/services/memflow/workflow/execChild.d.ts +96 -8
  50. package/build/services/memflow/workflow/execChild.js +96 -8
  51. package/build/services/memflow/workflow/execHook.d.ts +54 -39
  52. package/build/services/memflow/workflow/execHook.js +52 -38
  53. package/build/services/memflow/workflow/execHookBatch.d.ts +82 -29
  54. package/build/services/memflow/workflow/execHookBatch.js +80 -28
  55. package/build/services/memflow/workflow/hook.d.ts +68 -3
  56. package/build/services/memflow/workflow/hook.js +69 -4
  57. package/build/services/memflow/workflow/index.d.ts +65 -10
  58. package/build/services/memflow/workflow/index.js +65 -10
  59. package/build/services/memflow/workflow/interrupt.d.ts +50 -4
  60. package/build/services/memflow/workflow/interrupt.js +50 -4
  61. package/build/services/memflow/workflow/interruption.d.ts +49 -16
  62. package/build/services/memflow/workflow/interruption.js +49 -16
  63. package/build/services/memflow/workflow/isSideEffectAllowed.d.ts +21 -4
  64. package/build/services/memflow/workflow/isSideEffectAllowed.js +21 -4
  65. package/build/services/memflow/workflow/proxyActivities.d.ts +70 -42
  66. package/build/services/memflow/workflow/proxyActivities.js +70 -42
  67. package/build/services/memflow/workflow/random.d.ts +33 -3
  68. package/build/services/memflow/workflow/random.js +33 -3
  69. package/build/services/memflow/workflow/searchMethods.d.ts +49 -2
  70. package/build/services/memflow/workflow/searchMethods.js +49 -2
  71. package/build/services/memflow/workflow/signal.d.ts +51 -22
  72. package/build/services/memflow/workflow/signal.js +52 -23
  73. package/build/services/memflow/workflow/sleepFor.d.ts +57 -18
  74. package/build/services/memflow/workflow/sleepFor.js +57 -18
  75. package/build/services/memflow/workflow/trace.d.ts +39 -6
  76. package/build/services/memflow/workflow/trace.js +39 -6
  77. package/build/services/memflow/workflow/waitFor.d.ts +55 -18
  78. package/build/services/memflow/workflow/waitFor.js +55 -18
  79. package/build/services/router/consumption/index.js +1 -1
  80. package/build/services/search/factory.js +1 -9
  81. package/build/services/store/factory.js +1 -9
  82. package/build/services/store/index.d.ts +6 -1
  83. package/build/services/store/providers/postgres/kvsql.d.ts +4 -0
  84. package/build/services/store/providers/postgres/kvsql.js +4 -0
  85. package/build/services/store/providers/postgres/kvtransaction.d.ts +2 -0
  86. package/build/services/store/providers/postgres/kvtransaction.js +23 -0
  87. package/build/services/store/providers/postgres/kvtypes/hash/basic.d.ts +51 -0
  88. package/build/services/store/providers/postgres/kvtypes/hash/basic.js +193 -1
  89. package/build/services/store/providers/postgres/kvtypes/hash/index.d.ts +4 -0
  90. package/build/services/store/providers/postgres/kvtypes/hash/index.js +6 -0
  91. package/build/services/store/providers/postgres/postgres.d.ts +21 -1
  92. package/build/services/store/providers/postgres/postgres.js +42 -4
  93. package/build/services/stream/factory.js +1 -17
  94. package/build/services/stream/providers/postgres/scout.js +2 -2
  95. package/build/services/sub/factory.js +1 -9
  96. package/build/services/sub/index.d.ts +1 -1
  97. package/build/services/sub/providers/postgres/postgres.d.ts +1 -1
  98. package/build/services/sub/providers/postgres/postgres.js +25 -10
  99. package/build/services/task/index.d.ts +1 -1
  100. package/build/services/task/index.js +2 -6
  101. package/build/services/telemetry/index.js +6 -0
  102. package/build/types/activity.d.ts +1 -1
  103. package/build/types/hotmesh.d.ts +1 -1
  104. package/build/types/index.d.ts +0 -1
  105. package/build/types/index.js +1 -4
  106. package/build/types/job.d.ts +1 -1
  107. package/build/types/memflow.d.ts +1 -1
  108. package/build/types/provider.d.ts +1 -1
  109. package/build/types/quorum.d.ts +2 -2
  110. package/build/vitest.config.d.ts +2 -0
  111. package/build/vitest.config.js +18 -0
  112. package/index.ts +0 -4
  113. package/package.json +63 -79
  114. package/vitest.config.ts +17 -0
  115. package/build/services/connector/providers/ioredis.d.ts +0 -9
  116. package/build/services/connector/providers/ioredis.js +0 -26
  117. package/build/services/connector/providers/redis.d.ts +0 -9
  118. package/build/services/connector/providers/redis.js +0 -38
  119. package/build/services/search/providers/redis/ioredis.d.ts +0 -23
  120. package/build/services/search/providers/redis/ioredis.js +0 -189
  121. package/build/services/search/providers/redis/redis.d.ts +0 -23
  122. package/build/services/search/providers/redis/redis.js +0 -202
  123. package/build/services/store/providers/redis/_base.d.ts +0 -137
  124. package/build/services/store/providers/redis/_base.js +0 -980
  125. package/build/services/store/providers/redis/ioredis.d.ts +0 -20
  126. package/build/services/store/providers/redis/ioredis.js +0 -190
  127. package/build/services/store/providers/redis/redis.d.ts +0 -18
  128. package/build/services/store/providers/redis/redis.js +0 -199
  129. package/build/services/stream/providers/redis/ioredis.d.ts +0 -61
  130. package/build/services/stream/providers/redis/ioredis.js +0 -272
  131. package/build/services/stream/providers/redis/redis.d.ts +0 -61
  132. package/build/services/stream/providers/redis/redis.js +0 -305
  133. package/build/services/sub/providers/redis/ioredis.d.ts +0 -20
  134. package/build/services/sub/providers/redis/ioredis.js +0 -161
  135. package/build/services/sub/providers/redis/redis.d.ts +0 -18
  136. package/build/services/sub/providers/redis/redis.js +0 -148
  137. package/build/types/redis.d.ts +0 -258
  138. package/build/types/redis.js +0 -11
@@ -4,47 +4,99 @@ exports.execHookBatch = void 0;
4
4
  const hook_1 = require("./hook");
5
5
  const waitFor_1 = require("./waitFor");
6
6
  /**
7
- * Executes multiple hooks in parallel and awaits all their signal responses.
8
- * This solves the race condition where Promise.all() with execHook() would prevent
9
- * all waitFor() registrations from completing.
7
+ * Executes multiple hooks in parallel and awaits all their signal responses,
8
+ * returning a keyed object of results. This is the recommended way to run
9
+ * concurrent hooks it solves a race condition where calling
10
+ * `Promise.all([execHook(), execHook()])` would throw before all `waitFor`
11
+ * registrations complete.
10
12
  *
11
- * The method ensures all waitFor() registrations happen before any hooks execute,
12
- * preventing signals from being sent before the framework is ready to receive them.
13
+ * ## Three-Phase Execution
13
14
  *
14
- * @template T - Object type with keys matching the batch hook keys and values as expected response types
15
- * @param {BatchHookConfig[]} hookConfigs - Array of hook configurations with unique keys
16
- * @returns {Promise<T>} Object with keys from hookConfigs and values as the signal responses
15
+ * 1. **Fire all hooks** via `Promise.all` (registers streams immediately).
16
+ * 2. **Await all signals** via `Promise.all` (all `waitFor` registrations
17
+ * happen together before any `MemFlowWaitForError` is thrown).
18
+ * 3. **Combine results** into a `{ [key]: result }` map.
19
+ *
20
+ * ## Examples
21
+ *
22
+ * ```typescript
23
+ * import { MemFlow } from '@hotmeshio/hotmesh';
24
+ *
25
+ * // Fan-out to multiple AI agents, gather all perspectives
26
+ * export async function researchWorkflow(query: string): Promise<Summary> {
27
+ * const perspectives = await MemFlow.workflow.execHookBatch<{
28
+ * optimistic: PerspectiveResult;
29
+ * skeptical: PerspectiveResult;
30
+ * neutral: PerspectiveResult;
31
+ * }>([
32
+ * {
33
+ * key: 'optimistic',
34
+ * options: {
35
+ * taskQueue: 'agents',
36
+ * workflowName: 'analyzeOptimistic',
37
+ * args: [query],
38
+ * },
39
+ * },
40
+ * {
41
+ * key: 'skeptical',
42
+ * options: {
43
+ * taskQueue: 'agents',
44
+ * workflowName: 'analyzeSkeptical',
45
+ * args: [query],
46
+ * },
47
+ * },
48
+ * {
49
+ * key: 'neutral',
50
+ * options: {
51
+ * taskQueue: 'agents',
52
+ * workflowName: 'analyzeNeutral',
53
+ * args: [query],
54
+ * },
55
+ * },
56
+ * ]);
57
+ *
58
+ * // All three results are available as typed properties
59
+ * const { synthesize } = MemFlow.workflow.proxyActivities<typeof activities>();
60
+ * return await synthesize(
61
+ * perspectives.optimistic,
62
+ * perspectives.skeptical,
63
+ * perspectives.neutral,
64
+ * );
65
+ * }
66
+ * ```
17
67
  *
18
- * @example
19
68
  * ```typescript
20
- * // Execute multiple research perspectives in parallel
21
- * const results = await MemFlow.workflow.execHookBatch<{
22
- * optimistic: OptimisticResult;
23
- * skeptical: SkepticalResult;
69
+ * // Parallel validation with different services
70
+ * const checks = await MemFlow.workflow.execHookBatch<{
71
+ * fraud: { safe: boolean };
72
+ * compliance: { approved: boolean };
24
73
  * }>([
25
74
  * {
26
- * key: 'optimistic',
75
+ * key: 'fraud',
27
76
  * options: {
28
- * taskQueue: 'agents',
29
- * workflowName: 'optimisticPerspective',
30
- * args: [query],
31
- * signalId: 'optimistic-complete'
32
- * }
77
+ * taskQueue: 'fraud-detection',
78
+ * workflowName: 'checkFraud',
79
+ * args: [transactionId],
80
+ * },
33
81
  * },
34
82
  * {
35
- * key: 'skeptical',
83
+ * key: 'compliance',
36
84
  * options: {
37
- * taskQueue: 'agents',
38
- * workflowName: 'skepticalPerspective',
39
- * args: [query],
40
- * signalId: 'skeptical-complete'
41
- * }
42
- * }
85
+ * taskQueue: 'compliance',
86
+ * workflowName: 'checkCompliance',
87
+ * args: [transactionId],
88
+ * },
89
+ * },
43
90
  * ]);
44
91
  *
45
- * // results.optimistic contains the OptimisticResult
46
- * // results.skeptical contains the SkepticalResult
92
+ * if (checks.fraud.safe && checks.compliance.approved) {
93
+ * // proceed with transaction
94
+ * }
47
95
  * ```
96
+ *
97
+ * @template T - Object type with keys matching the batch hook keys.
98
+ * @param {BatchHookConfig[]} hookConfigs - Array of hook configurations with unique keys.
99
+ * @returns {Promise<T>} Object mapping each config's `key` to its signal response.
48
100
  */
49
101
  async function execHookBatch(hookConfigs) {
50
102
  // Generate signal IDs for hooks that don't have them
@@ -1,9 +1,74 @@
1
1
  import { HookOptions } from './common';
2
2
  /**
3
- * Spawns a hook from the main thread or a hook thread.
4
- * If entity/workflowName are not provided, defaults to the current workflow.
3
+ * Spawns a hook execution against an existing workflow job. The hook runs
4
+ * in an isolated dimensional thread within the target job's namespace,
5
+ * allowing it to read/write the same job state without interfering with
6
+ * the main workflow thread.
5
7
  *
6
- * @param {HookOptions} options - Hook configuration options.
8
+ * This is the low-level primitive behind `execHook()`. Use `hook()`
9
+ * directly when you need fire-and-forget hook execution or when you
10
+ * manage signal coordination yourself.
11
+ *
12
+ * ## Target Resolution
13
+ *
14
+ * - If `taskQueue` and `workflowName` (or `entity`) are provided, the
15
+ * hook targets that specific workflow type.
16
+ * - If neither is provided, the hook targets the **current** workflow.
17
+ * However, targeting the same topic as the current workflow is
18
+ * rejected to prevent infinite loops.
19
+ *
20
+ * ## Idempotency
21
+ *
22
+ * The `isSideEffectAllowed` guard ensures hooks fire exactly once —
23
+ * on replay, the hook is not re-spawned.
24
+ *
25
+ * ## Examples
26
+ *
27
+ * ```typescript
28
+ * import { MemFlow } from '@hotmeshio/hotmesh';
29
+ *
30
+ * // Fire-and-forget: spawn a hook without waiting for its result
31
+ * export async function notifyWorkflow(userId: string): Promise<void> {
32
+ * await MemFlow.workflow.hook({
33
+ * taskQueue: 'notifications',
34
+ * workflowName: 'sendNotification',
35
+ * args: [userId, 'Your order has shipped'],
36
+ * });
37
+ * // Continues immediately, does not wait for the hook
38
+ * }
39
+ * ```
40
+ *
41
+ * ```typescript
42
+ * // Manual signal coordination (equivalent to execHook)
43
+ * export async function manualHookPattern(itemId: string): Promise<string> {
44
+ * const signalId = `process-${itemId}`;
45
+ *
46
+ * await MemFlow.workflow.hook({
47
+ * taskQueue: 'processors',
48
+ * workflowName: 'processItem',
49
+ * args: [itemId, signalId],
50
+ * });
51
+ *
52
+ * // Manually wait for the hook to signal back
53
+ * return await MemFlow.workflow.waitFor<string>(signalId);
54
+ * }
55
+ * ```
56
+ *
57
+ * ```typescript
58
+ * // Hook with retry configuration
59
+ * await MemFlow.workflow.hook({
60
+ * taskQueue: 'enrichment',
61
+ * workflowName: 'enrichProfile',
62
+ * args: [profileId],
63
+ * config: {
64
+ * maximumAttempts: 5,
65
+ * backoffCoefficient: 2,
66
+ * maximumInterval: '1m',
67
+ * },
68
+ * });
69
+ * ```
70
+ *
71
+ * @param {HookOptions} options - Hook configuration including target workflow and arguments.
7
72
  * @returns {Promise<string>} The resulting hook/stream ID.
8
73
  */
9
74
  export declare function hook(options: HookOptions): Promise<string>;
@@ -5,10 +5,75 @@ const common_1 = require("./common");
5
5
  const context_1 = require("./context");
6
6
  const isSideEffectAllowed_1 = require("./isSideEffectAllowed");
7
7
  /**
8
- * Spawns a hook from the main thread or a hook thread.
9
- * If entity/workflowName are not provided, defaults to the current workflow.
8
+ * Spawns a hook execution against an existing workflow job. The hook runs
9
+ * in an isolated dimensional thread within the target job's namespace,
10
+ * allowing it to read/write the same job state without interfering with
11
+ * the main workflow thread.
10
12
  *
11
- * @param {HookOptions} options - Hook configuration options.
13
+ * This is the low-level primitive behind `execHook()`. Use `hook()`
14
+ * directly when you need fire-and-forget hook execution or when you
15
+ * manage signal coordination yourself.
16
+ *
17
+ * ## Target Resolution
18
+ *
19
+ * - If `taskQueue` and `workflowName` (or `entity`) are provided, the
20
+ * hook targets that specific workflow type.
21
+ * - If neither is provided, the hook targets the **current** workflow.
22
+ * However, targeting the same topic as the current workflow is
23
+ * rejected to prevent infinite loops.
24
+ *
25
+ * ## Idempotency
26
+ *
27
+ * The `isSideEffectAllowed` guard ensures hooks fire exactly once —
28
+ * on replay, the hook is not re-spawned.
29
+ *
30
+ * ## Examples
31
+ *
32
+ * ```typescript
33
+ * import { MemFlow } from '@hotmeshio/hotmesh';
34
+ *
35
+ * // Fire-and-forget: spawn a hook without waiting for its result
36
+ * export async function notifyWorkflow(userId: string): Promise<void> {
37
+ * await MemFlow.workflow.hook({
38
+ * taskQueue: 'notifications',
39
+ * workflowName: 'sendNotification',
40
+ * args: [userId, 'Your order has shipped'],
41
+ * });
42
+ * // Continues immediately, does not wait for the hook
43
+ * }
44
+ * ```
45
+ *
46
+ * ```typescript
47
+ * // Manual signal coordination (equivalent to execHook)
48
+ * export async function manualHookPattern(itemId: string): Promise<string> {
49
+ * const signalId = `process-${itemId}`;
50
+ *
51
+ * await MemFlow.workflow.hook({
52
+ * taskQueue: 'processors',
53
+ * workflowName: 'processItem',
54
+ * args: [itemId, signalId],
55
+ * });
56
+ *
57
+ * // Manually wait for the hook to signal back
58
+ * return await MemFlow.workflow.waitFor<string>(signalId);
59
+ * }
60
+ * ```
61
+ *
62
+ * ```typescript
63
+ * // Hook with retry configuration
64
+ * await MemFlow.workflow.hook({
65
+ * taskQueue: 'enrichment',
66
+ * workflowName: 'enrichProfile',
67
+ * args: [profileId],
68
+ * config: {
69
+ * maximumAttempts: 5,
70
+ * backoffCoefficient: 2,
71
+ * maximumInterval: '1m',
72
+ * },
73
+ * });
74
+ * ```
75
+ *
76
+ * @param {HookOptions} options - Hook configuration including target workflow and arguments.
12
77
  * @returns {Promise<string>} The resulting hook/stream ID.
13
78
  */
14
79
  async function hook(options) {
@@ -52,7 +117,7 @@ async function hook(options) {
52
117
  maximumAttempts: options.config?.maximumAttempts || common_1.HMSH_MEMFLOW_MAX_ATTEMPTS,
53
118
  maximumInterval: (0, common_1.s)(options?.config?.maximumInterval ?? common_1.HMSH_MEMFLOW_MAX_INTERVAL),
54
119
  };
55
- return await hotMeshClient.hook(`${namespace}.flow.signal`, payload, common_1.StreamStatus.PENDING, 202);
120
+ return await hotMeshClient.signal(`${namespace}.flow.signal`, payload, common_1.StreamStatus.PENDING, 202);
56
121
  }
57
122
  }
58
123
  exports.hook = hook;
@@ -20,20 +20,75 @@ import { waitFor } from './waitFor';
20
20
  import { HotMesh } from './common';
21
21
  import { entity } from './entityMethods';
22
22
  /**
23
- * The WorkflowService class provides a set of static methods to be used within a workflow function.
24
- * These methods ensure deterministic replay, persistence of state, and error handling across
25
- * re-entrant workflow executions.
23
+ * The workflow-internal API surface, exposed as `MemFlow.workflow`. Every
24
+ * method on this class is designed to be called **inside** a workflow
25
+ * function they participate in deterministic replay and durable state
26
+ * management.
27
+ *
28
+ * ## Core Primitives
29
+ *
30
+ * | Method | Purpose |
31
+ * |--------|---------|
32
+ * | {@link proxyActivities} | Create durable activity proxies with retry |
33
+ * | {@link sleepFor} | Durable, crash-safe sleep |
34
+ * | {@link waitFor} | Pause until a signal is received |
35
+ * | {@link signal} | Send data to a waiting workflow |
36
+ * | {@link execChild} | Spawn and await a child workflow |
37
+ * | {@link startChild} | Spawn a child workflow (fire-and-forget) |
38
+ * | {@link execHook} | Spawn a hook and await its signal response |
39
+ * | {@link execHookBatch} | Spawn multiple hooks in parallel |
40
+ * | {@link hook} | Low-level hook spawning |
41
+ * | {@link interrupt} | Terminate a running workflow |
42
+ *
43
+ * ## Data & Observability
44
+ *
45
+ * | Method | Purpose |
46
+ * |--------|---------|
47
+ * | {@link search} | Read/write flat HASH key-value data |
48
+ * | {@link enrich} | One-shot HASH enrichment |
49
+ * | {@link entity} | Structured JSONB document storage |
50
+ * | {@link emit} | Publish events to the event bus |
51
+ * | {@link trace} | Emit OpenTelemetry trace spans |
52
+ *
53
+ * ## Utilities
54
+ *
55
+ * | Method | Purpose |
56
+ * |--------|---------|
57
+ * | {@link getContext} | Access workflow ID, namespace, replay state |
58
+ * | {@link random} | Deterministic pseudo-random numbers |
59
+ * | {@link all} | Workflow-safe `Promise.all` |
60
+ * | {@link didInterrupt} | Type guard for engine control-flow errors |
61
+ *
62
+ * ## Example
26
63
  *
27
- * @example
28
64
  * ```typescript
29
65
  * import { MemFlow } from '@hotmeshio/hotmesh';
66
+ * import * as activities from './activities';
67
+ *
68
+ * export async function orderWorkflow(orderId: string): Promise<string> {
69
+ * // Proxy activities for durable execution
70
+ * const { validateOrder, processPayment, sendReceipt } =
71
+ * MemFlow.workflow.proxyActivities<typeof activities>({
72
+ * activities,
73
+ * retryPolicy: { maximumAttempts: 3 },
74
+ * });
75
+ *
76
+ * await validateOrder(orderId);
77
+ *
78
+ * // Durable sleep (survives restarts)
79
+ * await MemFlow.workflow.sleepFor('5 seconds');
80
+ *
81
+ * const receipt = await processPayment(orderId);
82
+ *
83
+ * // Store searchable metadata
84
+ * await MemFlow.workflow.enrich({ orderId, status: 'paid' });
85
+ *
86
+ * // Wait for external approval signal
87
+ * const approval = await MemFlow.workflow.waitFor<{ ok: boolean }>('approve');
88
+ * if (!approval.ok) return 'cancelled';
30
89
  *
31
- * export async function waitForExample(): Promise<[boolean, number]> {
32
- * const [s1, s2] = await Promise.all([
33
- * MemFlow.workflow.waitFor<boolean>('my-sig-nal-1'),
34
- * MemFlow.workflow.waitFor<number>('my-sig-nal-2')
35
- * ]);
36
- * return [s1, s2];
90
+ * await sendReceipt(orderId, receipt);
91
+ * return receipt;
37
92
  * }
38
93
  * ```
39
94
  */
@@ -23,20 +23,75 @@ const waitFor_1 = require("./waitFor");
23
23
  const common_1 = require("./common");
24
24
  const entityMethods_1 = require("./entityMethods");
25
25
  /**
26
- * The WorkflowService class provides a set of static methods to be used within a workflow function.
27
- * These methods ensure deterministic replay, persistence of state, and error handling across
28
- * re-entrant workflow executions.
26
+ * The workflow-internal API surface, exposed as `MemFlow.workflow`. Every
27
+ * method on this class is designed to be called **inside** a workflow
28
+ * function they participate in deterministic replay and durable state
29
+ * management.
30
+ *
31
+ * ## Core Primitives
32
+ *
33
+ * | Method | Purpose |
34
+ * |--------|---------|
35
+ * | {@link proxyActivities} | Create durable activity proxies with retry |
36
+ * | {@link sleepFor} | Durable, crash-safe sleep |
37
+ * | {@link waitFor} | Pause until a signal is received |
38
+ * | {@link signal} | Send data to a waiting workflow |
39
+ * | {@link execChild} | Spawn and await a child workflow |
40
+ * | {@link startChild} | Spawn a child workflow (fire-and-forget) |
41
+ * | {@link execHook} | Spawn a hook and await its signal response |
42
+ * | {@link execHookBatch} | Spawn multiple hooks in parallel |
43
+ * | {@link hook} | Low-level hook spawning |
44
+ * | {@link interrupt} | Terminate a running workflow |
45
+ *
46
+ * ## Data & Observability
47
+ *
48
+ * | Method | Purpose |
49
+ * |--------|---------|
50
+ * | {@link search} | Read/write flat HASH key-value data |
51
+ * | {@link enrich} | One-shot HASH enrichment |
52
+ * | {@link entity} | Structured JSONB document storage |
53
+ * | {@link emit} | Publish events to the event bus |
54
+ * | {@link trace} | Emit OpenTelemetry trace spans |
55
+ *
56
+ * ## Utilities
57
+ *
58
+ * | Method | Purpose |
59
+ * |--------|---------|
60
+ * | {@link getContext} | Access workflow ID, namespace, replay state |
61
+ * | {@link random} | Deterministic pseudo-random numbers |
62
+ * | {@link all} | Workflow-safe `Promise.all` |
63
+ * | {@link didInterrupt} | Type guard for engine control-flow errors |
64
+ *
65
+ * ## Example
29
66
  *
30
- * @example
31
67
  * ```typescript
32
68
  * import { MemFlow } from '@hotmeshio/hotmesh';
69
+ * import * as activities from './activities';
70
+ *
71
+ * export async function orderWorkflow(orderId: string): Promise<string> {
72
+ * // Proxy activities for durable execution
73
+ * const { validateOrder, processPayment, sendReceipt } =
74
+ * MemFlow.workflow.proxyActivities<typeof activities>({
75
+ * activities,
76
+ * retryPolicy: { maximumAttempts: 3 },
77
+ * });
78
+ *
79
+ * await validateOrder(orderId);
80
+ *
81
+ * // Durable sleep (survives restarts)
82
+ * await MemFlow.workflow.sleepFor('5 seconds');
83
+ *
84
+ * const receipt = await processPayment(orderId);
85
+ *
86
+ * // Store searchable metadata
87
+ * await MemFlow.workflow.enrich({ orderId, status: 'paid' });
88
+ *
89
+ * // Wait for external approval signal
90
+ * const approval = await MemFlow.workflow.waitFor<{ ok: boolean }>('approve');
91
+ * if (!approval.ok) return 'cancelled';
33
92
  *
34
- * export async function waitForExample(): Promise<[boolean, number]> {
35
- * const [s1, s2] = await Promise.all([
36
- * MemFlow.workflow.waitFor<boolean>('my-sig-nal-1'),
37
- * MemFlow.workflow.waitFor<number>('my-sig-nal-2')
38
- * ]);
39
- * return [s1, s2];
93
+ * await sendReceipt(orderId, receipt);
94
+ * return receipt;
40
95
  * }
41
96
  * ```
42
97
  */
@@ -1,9 +1,55 @@
1
1
  import { JobInterruptOptions } from './common';
2
2
  /**
3
- * Interrupts a running job by sending an interruption request.
3
+ * Terminates a running workflow job by its ID. The target job's status
4
+ * is set to an error code indicating abnormal termination, and any
5
+ * pending activities or timers are cancelled.
4
6
  *
5
- * @param {string} jobId - The ID of the job to interrupt.
6
- * @param {JobInterruptOptions} options - Additional interruption options.
7
- * @returns {Promise<string|void>} Result of the interruption, if any.
7
+ * This is the workflow-internal interrupt it can only be called from
8
+ * within a workflow function. For external interruption, use
9
+ * `hotMesh.interrupt()` directly.
10
+ *
11
+ * The interrupt fires exactly once per workflow execution — the
12
+ * `isSideEffectAllowed` guard prevents re-interrupting on replay.
13
+ *
14
+ * ## Examples
15
+ *
16
+ * ```typescript
17
+ * import { MemFlow } from '@hotmeshio/hotmesh';
18
+ *
19
+ * // Cancel a child workflow from the parent
20
+ * export async function supervisorWorkflow(): Promise<void> {
21
+ * const childId = await MemFlow.workflow.startChild({
22
+ * taskQueue: 'workers',
23
+ * workflowName: 'longTask',
24
+ * args: [],
25
+ * });
26
+ *
27
+ * // Wait for a timeout, then cancel the child
28
+ * await MemFlow.workflow.sleepFor('5 minutes');
29
+ * await MemFlow.workflow.interrupt(childId, {
30
+ * reason: 'Timed out waiting for child',
31
+ * descend: true, // also interrupt any grandchild workflows
32
+ * });
33
+ * }
34
+ * ```
35
+ *
36
+ * ```typescript
37
+ * // Self-interrupt on validation failure
38
+ * export async function validatedWorkflow(input: string): Promise<void> {
39
+ * const { workflowId } = MemFlow.workflow.getContext();
40
+ * const { validate } = MemFlow.workflow.proxyActivities<typeof activities>();
41
+ *
42
+ * const isValid = await validate(input);
43
+ * if (!isValid) {
44
+ * await MemFlow.workflow.interrupt(workflowId, {
45
+ * reason: 'Invalid input',
46
+ * });
47
+ * }
48
+ * }
49
+ * ```
50
+ *
51
+ * @param {string} jobId - The ID of the workflow job to interrupt.
52
+ * @param {JobInterruptOptions} [options={}] - Interruption options (`reason`, `descend`, etc.).
53
+ * @returns {Promise<string | void>} The result of the interruption, if any.
8
54
  */
9
55
  export declare function interrupt(jobId: string, options?: JobInterruptOptions): Promise<string | void>;
@@ -5,11 +5,57 @@ const common_1 = require("./common");
5
5
  const context_1 = require("./context");
6
6
  const isSideEffectAllowed_1 = require("./isSideEffectAllowed");
7
7
  /**
8
- * Interrupts a running job by sending an interruption request.
8
+ * Terminates a running workflow job by its ID. The target job's status
9
+ * is set to an error code indicating abnormal termination, and any
10
+ * pending activities or timers are cancelled.
9
11
  *
10
- * @param {string} jobId - The ID of the job to interrupt.
11
- * @param {JobInterruptOptions} options - Additional interruption options.
12
- * @returns {Promise<string|void>} Result of the interruption, if any.
12
+ * This is the workflow-internal interrupt it can only be called from
13
+ * within a workflow function. For external interruption, use
14
+ * `hotMesh.interrupt()` directly.
15
+ *
16
+ * The interrupt fires exactly once per workflow execution — the
17
+ * `isSideEffectAllowed` guard prevents re-interrupting on replay.
18
+ *
19
+ * ## Examples
20
+ *
21
+ * ```typescript
22
+ * import { MemFlow } from '@hotmeshio/hotmesh';
23
+ *
24
+ * // Cancel a child workflow from the parent
25
+ * export async function supervisorWorkflow(): Promise<void> {
26
+ * const childId = await MemFlow.workflow.startChild({
27
+ * taskQueue: 'workers',
28
+ * workflowName: 'longTask',
29
+ * args: [],
30
+ * });
31
+ *
32
+ * // Wait for a timeout, then cancel the child
33
+ * await MemFlow.workflow.sleepFor('5 minutes');
34
+ * await MemFlow.workflow.interrupt(childId, {
35
+ * reason: 'Timed out waiting for child',
36
+ * descend: true, // also interrupt any grandchild workflows
37
+ * });
38
+ * }
39
+ * ```
40
+ *
41
+ * ```typescript
42
+ * // Self-interrupt on validation failure
43
+ * export async function validatedWorkflow(input: string): Promise<void> {
44
+ * const { workflowId } = MemFlow.workflow.getContext();
45
+ * const { validate } = MemFlow.workflow.proxyActivities<typeof activities>();
46
+ *
47
+ * const isValid = await validate(input);
48
+ * if (!isValid) {
49
+ * await MemFlow.workflow.interrupt(workflowId, {
50
+ * reason: 'Invalid input',
51
+ * });
52
+ * }
53
+ * }
54
+ * ```
55
+ *
56
+ * @param {string} jobId - The ID of the workflow job to interrupt.
57
+ * @param {JobInterruptOptions} [options={}] - Interruption options (`reason`, `descend`, etc.).
58
+ * @returns {Promise<string | void>} The result of the interruption, if any.
13
59
  */
14
60
  async function interrupt(jobId, options = {}) {
15
61
  const { workflowTopic, connection, namespace } = (0, context_1.getContext)();
@@ -1,28 +1,61 @@
1
1
  /**
2
- * Checks if an error is a HotMesh reserved error type that indicates
3
- * a HotMesh interruption rather than a true error condition.
2
+ * Type guard that returns `true` if an error is a MemFlow engine
3
+ * control-flow signal rather than a genuine application error.
4
4
  *
5
- * When this returns true, you can safely return rethrow the error.
6
- * The workflow engine will handle the interruption automatically.
5
+ * MemFlow uses thrown errors internally to suspend workflow execution
6
+ * for durable operations like `sleepFor`, `waitFor`, `proxyActivities`,
7
+ * and `execChild`. These errors must be re-thrown (not swallowed) so
8
+ * the engine can persist state and schedule the next step.
9
+ *
10
+ * **Always use `didInterrupt` in `catch` blocks inside workflow
11
+ * functions** to avoid accidentally swallowing engine signals.
12
+ *
13
+ * ## Recognized Error Types
14
+ *
15
+ * `MemFlowChildError`, `MemFlowFatalError`, `MemFlowMaxedError`,
16
+ * `MemFlowProxyError`, `MemFlowRetryError`, `MemFlowSleepError`,
17
+ * `MemFlowTimeoutError`, `MemFlowWaitForError`, `MemFlowWaitForAllError`
18
+ *
19
+ * ## Examples
7
20
  *
8
- * @example
9
21
  * ```typescript
10
22
  * import { MemFlow } from '@hotmeshio/hotmesh';
11
23
  *
12
- * try {
13
- * await someWorkflowOperation();
14
- * } catch (error) {
15
- * // Check if this is a HotMesh interruption
16
- * if (MemFlow.workflow.didInterrupt(error)) {
17
- * // Rethrow the error
18
- * throw error;
24
+ * export async function safeWorkflow(): Promise<string> {
25
+ * const { riskyOperation } = MemFlow.workflow.proxyActivities<typeof activities>();
26
+ *
27
+ * try {
28
+ * return await riskyOperation();
29
+ * } catch (error) {
30
+ * // CRITICAL: re-throw engine signals
31
+ * if (MemFlow.workflow.didInterrupt(error)) {
32
+ * throw error;
33
+ * }
34
+ * // Handle real application errors
35
+ * return 'fallback-value';
19
36
  * }
20
- * // Handle actual error
21
- * console.error('Workflow failed:', error);
22
37
  * }
23
38
  * ```
24
39
  *
25
- * @param error - The error to check
26
- * @returns true if the error is a HotMesh interruption
40
+ * ```typescript
41
+ * // Common pattern in interceptors
42
+ * const interceptor: WorkflowInterceptor = {
43
+ * async execute(ctx, next) {
44
+ * try {
45
+ * return await next();
46
+ * } catch (error) {
47
+ * if (MemFlow.workflow.didInterrupt(error)) {
48
+ * throw error; // always re-throw engine signals
49
+ * }
50
+ * // Log and re-throw application errors
51
+ * console.error('Workflow failed:', error);
52
+ * throw error;
53
+ * }
54
+ * },
55
+ * };
56
+ * ```
57
+ *
58
+ * @param {Error} error - The error to check.
59
+ * @returns {boolean} `true` if the error is a MemFlow engine interruption signal.
27
60
  */
28
61
  export declare function didInterrupt(error: Error): boolean;