@hotmeshio/hotmesh 0.8.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 (86) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/README.md +158 -38
  3. package/build/package.json +62 -67
  4. package/build/services/activities/activity.d.ts +58 -7
  5. package/build/services/activities/activity.js +66 -37
  6. package/build/services/activities/await.d.ts +101 -0
  7. package/build/services/activities/await.js +101 -0
  8. package/build/services/activities/cycle.d.ts +82 -0
  9. package/build/services/activities/cycle.js +86 -8
  10. package/build/services/activities/hook.d.ts +139 -1
  11. package/build/services/activities/hook.js +140 -2
  12. package/build/services/activities/interrupt.d.ts +112 -0
  13. package/build/services/activities/interrupt.js +118 -5
  14. package/build/services/activities/signal.d.ts +108 -3
  15. package/build/services/activities/signal.js +113 -8
  16. package/build/services/activities/trigger.d.ts +56 -4
  17. package/build/services/activities/trigger.js +119 -35
  18. package/build/services/activities/worker.d.ts +107 -0
  19. package/build/services/activities/worker.js +107 -0
  20. package/build/services/collator/index.d.ts +3 -15
  21. package/build/services/collator/index.js +7 -34
  22. package/build/services/engine/index.d.ts +18 -2
  23. package/build/services/engine/index.js +14 -4
  24. package/build/services/exporter/index.d.ts +2 -0
  25. package/build/services/exporter/index.js +1 -0
  26. package/build/services/hotmesh/index.d.ts +471 -236
  27. package/build/services/hotmesh/index.js +473 -238
  28. package/build/services/memflow/client.js +2 -2
  29. package/build/services/memflow/handle.js +1 -1
  30. package/build/services/memflow/index.d.ts +1 -1
  31. package/build/services/memflow/index.js +1 -1
  32. package/build/services/memflow/workflow/all.d.ts +28 -3
  33. package/build/services/memflow/workflow/all.js +28 -3
  34. package/build/services/memflow/workflow/context.d.ts +44 -1
  35. package/build/services/memflow/workflow/context.js +44 -1
  36. package/build/services/memflow/workflow/didRun.d.ts +23 -3
  37. package/build/services/memflow/workflow/didRun.js +23 -3
  38. package/build/services/memflow/workflow/emit.d.ts +43 -4
  39. package/build/services/memflow/workflow/emit.js +43 -4
  40. package/build/services/memflow/workflow/enrich.d.ts +32 -4
  41. package/build/services/memflow/workflow/enrich.js +32 -4
  42. package/build/services/memflow/workflow/entityMethods.d.ts +54 -7
  43. package/build/services/memflow/workflow/entityMethods.js +54 -7
  44. package/build/services/memflow/workflow/execChild.d.ts +96 -8
  45. package/build/services/memflow/workflow/execChild.js +96 -8
  46. package/build/services/memflow/workflow/execHook.d.ts +54 -39
  47. package/build/services/memflow/workflow/execHook.js +52 -38
  48. package/build/services/memflow/workflow/execHookBatch.d.ts +82 -29
  49. package/build/services/memflow/workflow/execHookBatch.js +80 -28
  50. package/build/services/memflow/workflow/hook.d.ts +68 -3
  51. package/build/services/memflow/workflow/hook.js +69 -4
  52. package/build/services/memflow/workflow/index.d.ts +65 -10
  53. package/build/services/memflow/workflow/index.js +65 -10
  54. package/build/services/memflow/workflow/interrupt.d.ts +50 -4
  55. package/build/services/memflow/workflow/interrupt.js +50 -4
  56. package/build/services/memflow/workflow/interruption.d.ts +49 -16
  57. package/build/services/memflow/workflow/interruption.js +49 -16
  58. package/build/services/memflow/workflow/isSideEffectAllowed.d.ts +21 -4
  59. package/build/services/memflow/workflow/isSideEffectAllowed.js +21 -4
  60. package/build/services/memflow/workflow/proxyActivities.d.ts +70 -42
  61. package/build/services/memflow/workflow/proxyActivities.js +70 -42
  62. package/build/services/memflow/workflow/random.d.ts +33 -3
  63. package/build/services/memflow/workflow/random.js +33 -3
  64. package/build/services/memflow/workflow/searchMethods.d.ts +49 -2
  65. package/build/services/memflow/workflow/searchMethods.js +49 -2
  66. package/build/services/memflow/workflow/signal.d.ts +51 -22
  67. package/build/services/memflow/workflow/signal.js +52 -23
  68. package/build/services/memflow/workflow/sleepFor.d.ts +57 -18
  69. package/build/services/memflow/workflow/sleepFor.js +57 -18
  70. package/build/services/memflow/workflow/trace.d.ts +39 -6
  71. package/build/services/memflow/workflow/trace.js +39 -6
  72. package/build/services/memflow/workflow/waitFor.d.ts +55 -18
  73. package/build/services/memflow/workflow/waitFor.js +55 -18
  74. package/build/services/store/index.d.ts +1 -1
  75. package/build/services/store/providers/postgres/postgres.d.ts +1 -1
  76. package/build/services/store/providers/postgres/postgres.js +4 -3
  77. package/build/services/telemetry/index.js +6 -0
  78. package/build/types/activity.d.ts +1 -1
  79. package/build/types/hotmesh.d.ts +1 -1
  80. package/build/types/job.d.ts +1 -1
  81. package/build/types/memflow.d.ts +1 -1
  82. package/build/types/quorum.d.ts +2 -2
  83. package/build/vitest.config.d.ts +2 -0
  84. package/build/vitest.config.js +18 -0
  85. package/package.json +62 -67
  86. package/vitest.config.ts +17 -0
@@ -9,7 +9,145 @@ const telemetry_1 = require("../telemetry");
9
9
  const stream_1 = require("../../types/stream");
10
10
  const activity_1 = require("./activity");
11
11
  /**
12
- * Supports `signal hook`, `time hook`, and `cycle hook` patterns
12
+ * A versatile pause/resume activity that supports three distinct patterns:
13
+ * **time hook** (sleep), **web hook** (external signal), and **passthrough**
14
+ * (immediate transition with optional data mapping).
15
+ *
16
+ * The hook activity is the most flexible activity type. Depending on its
17
+ * YAML configuration, it operates in one of the following modes:
18
+ *
19
+ * ## Time Hook (Sleep)
20
+ *
21
+ * Pauses the flow for a specified duration in seconds. The `sleep` value
22
+ * can be a literal number or a `@pipe` expression for dynamic delays
23
+ * (e.g., exponential backoff).
24
+ *
25
+ * ```yaml
26
+ * app:
27
+ * id: myapp
28
+ * version: '1'
29
+ * graphs:
30
+ * - subscribes: job.start
31
+ * expire: 300
32
+ *
33
+ * activities:
34
+ * t1:
35
+ * type: trigger
36
+ *
37
+ * delay:
38
+ * type: hook
39
+ * sleep: 60 # pause for 60 seconds
40
+ * job:
41
+ * maps:
42
+ * paused_at: '{$self.output.metadata.ac}'
43
+ *
44
+ * resume:
45
+ * type: hook
46
+ *
47
+ * transitions:
48
+ * t1:
49
+ * - to: delay
50
+ * delay:
51
+ * - to: resume
52
+ * ```
53
+ *
54
+ * ## Web Hook (External Signal)
55
+ *
56
+ * Registers a webhook listener on a named topic. The flow pauses until
57
+ * an external signal is sent to the hook's topic. The signal data becomes
58
+ * available as `$self.hook.data`. The `hooks` section at the graph level
59
+ * routes incoming signals to the waiting activity.
60
+ *
61
+ * ```yaml
62
+ * app:
63
+ * id: myapp
64
+ * version: '1'
65
+ * graphs:
66
+ * - subscribes: order.placed
67
+ * expire: 3600
68
+ *
69
+ * activities:
70
+ * t1:
71
+ * type: trigger
72
+ *
73
+ * wait_for_approval:
74
+ * type: hook
75
+ * hook:
76
+ * type: object
77
+ * properties:
78
+ * approved: { type: boolean }
79
+ * job:
80
+ * maps:
81
+ * approved: '{$self.hook.data.approved}'
82
+ *
83
+ * done:
84
+ * type: hook
85
+ *
86
+ * transitions:
87
+ * t1:
88
+ * - to: wait_for_approval
89
+ * wait_for_approval:
90
+ * - to: done
91
+ *
92
+ * hooks:
93
+ * order.approval: # external topic that delivers the signal
94
+ * - to: wait_for_approval
95
+ * conditions:
96
+ * match:
97
+ * - expected: '{t1.output.data.id}'
98
+ * actual: '{$self.hook.data.id}'
99
+ * ```
100
+ *
101
+ * ## Passthrough (No Hook)
102
+ *
103
+ * When neither `sleep` nor `hook` is configured, the hook activity acts
104
+ * as a passthrough: it maps data and immediately transitions to children.
105
+ * This is useful for data transformation, convergence points, or as a
106
+ * cycle pivot (with `cycle: true`).
107
+ *
108
+ * ```yaml
109
+ * app:
110
+ * id: myapp
111
+ * version: '1'
112
+ * graphs:
113
+ * - subscribes: job.start
114
+ *
115
+ * activities:
116
+ * t1:
117
+ * type: trigger
118
+ *
119
+ * pivot:
120
+ * type: hook
121
+ * cycle: true # enables re-entry from a cycle activity
122
+ * output:
123
+ * maps:
124
+ * retryCount: 0
125
+ * job:
126
+ * maps:
127
+ * counter: '{$self.output.data.retryCount}'
128
+ *
129
+ * do_work:
130
+ * type: worker
131
+ * topic: work.do
132
+ *
133
+ * transitions:
134
+ * t1:
135
+ * - to: pivot
136
+ * pivot:
137
+ * - to: do_work
138
+ * ```
139
+ *
140
+ * ## Execution Model
141
+ *
142
+ * - **With `sleep` or `hook`**: Category A (duplex). Leg 1 registers the
143
+ * hook and saves state. Leg 2 fires when the timer expires or the
144
+ * external signal arrives (via `processTimeHookEvent` or
145
+ * `processWebHookEvent`).
146
+ * - **Without `sleep` or `hook`**: Category B (passthrough). Uses the
147
+ * crash-safe `executeLeg1StepProtocol` to map data and transition
148
+ * to adjacent activities.
149
+ *
150
+ * @see {@link HookActivity} for the TypeScript interface
13
151
  */
14
152
  class Hook extends activity_1.Activity {
15
153
  constructor(config, data, metadata, hook, engine, context) {
@@ -129,7 +267,7 @@ class Hook extends activity_1.Activity {
129
267
  }
130
268
  else if (this.config.sleep) {
131
269
  const duration = pipe_1.Pipe.resolve(this.config.sleep, this.context);
132
- await this.engine.taskService.registerTimeHook(this.context.metadata.jid, this.context.metadata.gid, `${this.metadata.aid}${this.metadata.dad || ''}`, 'sleep', duration, this.metadata.dad || '');
270
+ await this.engine.taskService.registerTimeHook(this.context.metadata.jid, this.context.metadata.gid, `${this.metadata.aid}${this.metadata.dad || ''}`, 'sleep', duration, this.metadata.dad || '', transaction);
133
271
  return this.context.metadata.jid;
134
272
  }
135
273
  }
@@ -3,6 +3,118 @@ import { TelemetryService } from '../telemetry';
3
3
  import { ActivityData, ActivityMetadata, ActivityType, InterruptActivity } from '../../types/activity';
4
4
  import { JobInterruptOptions, JobState } from '../../types/job';
5
5
  import { Activity } from './activity';
6
+ /**
7
+ * Terminates a flow by sending an interrupt signal. The `interrupt` activity
8
+ * can target the current flow (self-interrupt) or any other flow by its
9
+ * job ID (remote interrupt). Interrupted jobs have their status set to a
10
+ * value less than -100,000,000, indicating abnormal termination.
11
+ *
12
+ * ## YAML Configuration — Self-Interrupt
13
+ *
14
+ * When no `target` is specified, the activity interrupts the current flow.
15
+ * The flow terminates immediately after this activity executes. Use
16
+ * conditional transitions to route to an interrupt only when needed.
17
+ *
18
+ * ```yaml
19
+ * app:
20
+ * id: myapp
21
+ * version: '1'
22
+ * graphs:
23
+ * - subscribes: validation.check
24
+ * expire: 120
25
+ *
26
+ * activities:
27
+ * t1:
28
+ * type: trigger
29
+ *
30
+ * validate:
31
+ * type: worker
32
+ * topic: validate.input
33
+ *
34
+ * cancel:
35
+ * type: interrupt
36
+ * reason: 'Validation failed'
37
+ * throw: true
38
+ * code: 410
39
+ * job:
40
+ * maps:
41
+ * cancelled_at: '{$self.output.metadata.ac}'
42
+ *
43
+ * proceed:
44
+ * type: hook
45
+ *
46
+ * transitions:
47
+ * t1:
48
+ * - to: validate
49
+ * validate:
50
+ * - to: cancel
51
+ * conditions:
52
+ * code: 422 # interrupt only on validation failure
53
+ * - to: proceed
54
+ * ```
55
+ *
56
+ * ## YAML Configuration — Remote Interrupt
57
+ *
58
+ * When `target` is specified, the activity interrupts another flow while
59
+ * the current flow continues to transition to adjacent activities.
60
+ *
61
+ * ```yaml
62
+ * app:
63
+ * id: myapp
64
+ * version: '1'
65
+ * graphs:
66
+ * - subscribes: parent.flow
67
+ * expire: 120
68
+ *
69
+ * activities:
70
+ * t1:
71
+ * type: trigger
72
+ * job:
73
+ * maps:
74
+ * childJobId: '{$self.output.data.childJobId}'
75
+ *
76
+ * stop_child:
77
+ * type: interrupt
78
+ * topic: child.flow.topic # topic of the target flow
79
+ * target: '{t1.output.data.childJobId}'
80
+ * throw: false # do not throw (silent cancellation)
81
+ * descend: true # also interrupt descendant sub-flows
82
+ * job:
83
+ * maps:
84
+ * interrupted: true
85
+ *
86
+ * done:
87
+ * type: hook
88
+ *
89
+ * transitions:
90
+ * t1:
91
+ * - to: stop_child
92
+ * stop_child:
93
+ * - to: done
94
+ * ```
95
+ *
96
+ * ## Configuration Properties
97
+ *
98
+ * | Property | Type | Default | Description |
99
+ * |------------|---------|--------------------|-------------|
100
+ * | `target` | string | (current job) | Job ID to interrupt. Supports `@pipe` expressions. |
101
+ * | `topic` | string | (current topic) | Topic of the target flow |
102
+ * | `reason` | string | `'Job Interrupted'`| Error message attached to the interruption |
103
+ * | `throw` | boolean | `true` | Whether to throw a `JobInterrupted` error |
104
+ * | `descend` | boolean | `false` | Whether to cascade to child/descendant flows |
105
+ * | `code` | number | `410` | Error code attached to the interruption |
106
+ * | `stack` | string | — | Optional stack trace |
107
+ *
108
+ * ## Execution Model
109
+ *
110
+ * - **Self-interrupt (no `target`)**: Category C. Verifies entry, maps job
111
+ * data, sets status to -1, and fires the interrupt. No children.
112
+ * - **Remote interrupt (with `target`)**: Category B. Fires the interrupt
113
+ * best-effort, then uses `executeLeg1StepProtocol` to transition to
114
+ * adjacent activities.
115
+ *
116
+ * @see {@link InterruptActivity} for the TypeScript interface
117
+ */
6
118
  declare class Interrupt extends Activity {
7
119
  config: InterruptActivity;
8
120
  constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
@@ -6,6 +6,118 @@ const collator_1 = require("../collator");
6
6
  const pipe_1 = require("../pipe");
7
7
  const telemetry_1 = require("../telemetry");
8
8
  const activity_1 = require("./activity");
9
+ /**
10
+ * Terminates a flow by sending an interrupt signal. The `interrupt` activity
11
+ * can target the current flow (self-interrupt) or any other flow by its
12
+ * job ID (remote interrupt). Interrupted jobs have their status set to a
13
+ * value less than -100,000,000, indicating abnormal termination.
14
+ *
15
+ * ## YAML Configuration — Self-Interrupt
16
+ *
17
+ * When no `target` is specified, the activity interrupts the current flow.
18
+ * The flow terminates immediately after this activity executes. Use
19
+ * conditional transitions to route to an interrupt only when needed.
20
+ *
21
+ * ```yaml
22
+ * app:
23
+ * id: myapp
24
+ * version: '1'
25
+ * graphs:
26
+ * - subscribes: validation.check
27
+ * expire: 120
28
+ *
29
+ * activities:
30
+ * t1:
31
+ * type: trigger
32
+ *
33
+ * validate:
34
+ * type: worker
35
+ * topic: validate.input
36
+ *
37
+ * cancel:
38
+ * type: interrupt
39
+ * reason: 'Validation failed'
40
+ * throw: true
41
+ * code: 410
42
+ * job:
43
+ * maps:
44
+ * cancelled_at: '{$self.output.metadata.ac}'
45
+ *
46
+ * proceed:
47
+ * type: hook
48
+ *
49
+ * transitions:
50
+ * t1:
51
+ * - to: validate
52
+ * validate:
53
+ * - to: cancel
54
+ * conditions:
55
+ * code: 422 # interrupt only on validation failure
56
+ * - to: proceed
57
+ * ```
58
+ *
59
+ * ## YAML Configuration — Remote Interrupt
60
+ *
61
+ * When `target` is specified, the activity interrupts another flow while
62
+ * the current flow continues to transition to adjacent activities.
63
+ *
64
+ * ```yaml
65
+ * app:
66
+ * id: myapp
67
+ * version: '1'
68
+ * graphs:
69
+ * - subscribes: parent.flow
70
+ * expire: 120
71
+ *
72
+ * activities:
73
+ * t1:
74
+ * type: trigger
75
+ * job:
76
+ * maps:
77
+ * childJobId: '{$self.output.data.childJobId}'
78
+ *
79
+ * stop_child:
80
+ * type: interrupt
81
+ * topic: child.flow.topic # topic of the target flow
82
+ * target: '{t1.output.data.childJobId}'
83
+ * throw: false # do not throw (silent cancellation)
84
+ * descend: true # also interrupt descendant sub-flows
85
+ * job:
86
+ * maps:
87
+ * interrupted: true
88
+ *
89
+ * done:
90
+ * type: hook
91
+ *
92
+ * transitions:
93
+ * t1:
94
+ * - to: stop_child
95
+ * stop_child:
96
+ * - to: done
97
+ * ```
98
+ *
99
+ * ## Configuration Properties
100
+ *
101
+ * | Property | Type | Default | Description |
102
+ * |------------|---------|--------------------|-------------|
103
+ * | `target` | string | (current job) | Job ID to interrupt. Supports `@pipe` expressions. |
104
+ * | `topic` | string | (current topic) | Topic of the target flow |
105
+ * | `reason` | string | `'Job Interrupted'`| Error message attached to the interruption |
106
+ * | `throw` | boolean | `true` | Whether to throw a `JobInterrupted` error |
107
+ * | `descend` | boolean | `false` | Whether to cascade to child/descendant flows |
108
+ * | `code` | number | `410` | Error code attached to the interruption |
109
+ * | `stack` | string | — | Optional stack trace |
110
+ *
111
+ * ## Execution Model
112
+ *
113
+ * - **Self-interrupt (no `target`)**: Category C. Verifies entry, maps job
114
+ * data, sets status to -1, and fires the interrupt. No children.
115
+ * - **Remote interrupt (with `target`)**: Category B. Fires the interrupt
116
+ * best-effort, then uses `executeLeg1StepProtocol` to transition to
117
+ * adjacent activities.
118
+ *
119
+ * @see {@link InterruptActivity} for the TypeScript interface
120
+ */
9
121
  class Interrupt extends activity_1.Activity {
10
122
  constructor(config, data, metadata, hook, engine, context) {
11
123
  super(config, data, metadata, hook, engine, context);
@@ -74,20 +186,21 @@ class Interrupt extends activity_1.Activity {
74
186
  }
75
187
  }
76
188
  async interruptSelf(telemetry) {
77
- // Apply final updates to THIS job's state
78
189
  if (this.config.job?.maps) {
79
190
  this.mapJobData();
80
- await this.setState();
81
191
  }
82
- // Interrupt THIS job
83
- const messageId = await this.interrupt();
84
- // Notarize Leg1 completion and set status
192
+ // Bundle state + Leg1 completion + semaphore in one transaction
85
193
  telemetry.mapActivityAttributes();
86
194
  const transaction = this.store.transact();
195
+ if (this.config.job?.maps) {
196
+ await this.setState(transaction);
197
+ }
87
198
  await collator_1.CollatorService.notarizeLeg1Completion(this, transaction);
88
199
  await this.setStatus(-1, transaction);
89
200
  const txResponse = (await transaction.exec());
90
201
  const jobStatus = this.resolveStatus(txResponse);
202
+ // Interrupt fires AFTER proof commits (best-effort)
203
+ const messageId = await this.interrupt();
91
204
  telemetry.setActivityAttributes({
92
205
  'app.activity.mid': messageId,
93
206
  'app.job.jss': jobStatus,
@@ -3,6 +3,111 @@ import { ActivityData, ActivityMetadata, ActivityType, SignalActivity } from '..
3
3
  import { JobState } from '../../types/job';
4
4
  import { ProviderTransaction } from '../../types/provider';
5
5
  import { Activity } from './activity';
6
+ /**
7
+ * Sends a signal to one or more paused flows, resuming their execution.
8
+ * The `signal` activity is the counterpart to a `Hook` activity
9
+ * configured with a webhook listener. It allows any flow to reach into
10
+ * another flow and deliver data to a waiting hook, regardless of the
11
+ * relationship between the flows.
12
+ *
13
+ * ## YAML Configuration — Signal One
14
+ *
15
+ * Resumes a single paused flow by publishing to the hook's topic. Use
16
+ * `subtype: one` when you know the specific hook topic to signal.
17
+ *
18
+ * ```yaml
19
+ * app:
20
+ * id: myapp
21
+ * version: '1'
22
+ * graphs:
23
+ * - subscribes: signal.start
24
+ * expire: 120
25
+ *
26
+ * activities:
27
+ * t1:
28
+ * type: trigger
29
+ *
30
+ * resume_hook:
31
+ * type: signal
32
+ * subtype: one
33
+ * topic: my.hook.topic # the hook's registered topic
34
+ * status: success # optional: success (default) or pending
35
+ * code: 200 # optional: 200 (default) or 202 (keep-alive)
36
+ * signal:
37
+ * schema:
38
+ * type: object
39
+ * properties:
40
+ * approved: { type: boolean }
41
+ * maps:
42
+ * approved: true # data delivered to the hook
43
+ *
44
+ * done:
45
+ * type: hook
46
+ *
47
+ * transitions:
48
+ * t1:
49
+ * - to: resume_hook
50
+ * resume_hook:
51
+ * - to: done
52
+ * ```
53
+ *
54
+ * A `code: 202` signal delivers data but keeps the hook alive for
55
+ * additional signals. A `code: 200` (default) closes the hook.
56
+ *
57
+ * ## YAML Configuration — Signal All
58
+ *
59
+ * Resumes all paused flows that share a common job key facet. Use
60
+ * `subtype: all` for fan-out patterns where multiple waiting flows
61
+ * should be resumed simultaneously.
62
+ *
63
+ * ```yaml
64
+ * app:
65
+ * id: myapp
66
+ * version: '1'
67
+ * graphs:
68
+ * - subscribes: signal.fan.out
69
+ * expire: 120
70
+ *
71
+ * activities:
72
+ * t1:
73
+ * type: trigger
74
+ *
75
+ * resume_all:
76
+ * type: signal
77
+ * subtype: all
78
+ * topic: hook.resume
79
+ * key_name: parent_job_id # index facet name
80
+ * key_value: '{$job.metadata.jid}'
81
+ * scrub: true # clean up indexes after use
82
+ * resolver:
83
+ * maps:
84
+ * data:
85
+ * parent_job_id: '{$job.metadata.jid}'
86
+ * scrub: true
87
+ * signal:
88
+ * maps:
89
+ * done: true # data delivered to all matching hooks
90
+ *
91
+ * done:
92
+ * type: hook
93
+ *
94
+ * transitions:
95
+ * t1:
96
+ * - to: resume_all
97
+ * resume_all:
98
+ * - to: done
99
+ * ```
100
+ *
101
+ * ## Execution Model
102
+ *
103
+ * Signal is a **Category B (Leg1-only with children)** activity:
104
+ * - Bundles the hook signal with the Leg 1 completion marker in a
105
+ * single transaction (`hookOne`) or fires best-effort (`hookAll`).
106
+ * - Executes the crash-safe `executeLeg1StepProtocol` to transition
107
+ * to adjacent activities.
108
+ *
109
+ * @see {@link SignalActivity} for the TypeScript interface
110
+ */
6
111
  declare class Signal extends Activity {
7
112
  config: SignalActivity;
8
113
  constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
@@ -13,10 +118,10 @@ declare class Signal extends Activity {
13
118
  * The signal activity will hook one. Accepts an optional transaction
14
119
  * so the hook publish can be bundled with the Leg1 completion marker.
15
120
  */
16
- hookOne(transaction?: ProviderTransaction): Promise<string>;
121
+ signalOne(transaction?: ProviderTransaction): Promise<string>;
17
122
  /**
18
- * The signal activity will hook all paused jobs that share the same job key.
123
+ * Signals all paused jobs that share the same job key, resuming their execution.
19
124
  */
20
- hookAll(): Promise<string[]>;
125
+ signalAll(): Promise<string[]>;
21
126
  }
22
127
  export { Signal };
@@ -7,6 +7,111 @@ const mapper_1 = require("../mapper");
7
7
  const pipe_1 = require("../pipe");
8
8
  const telemetry_1 = require("../telemetry");
9
9
  const activity_1 = require("./activity");
10
+ /**
11
+ * Sends a signal to one or more paused flows, resuming their execution.
12
+ * The `signal` activity is the counterpart to a `Hook` activity
13
+ * configured with a webhook listener. It allows any flow to reach into
14
+ * another flow and deliver data to a waiting hook, regardless of the
15
+ * relationship between the flows.
16
+ *
17
+ * ## YAML Configuration — Signal One
18
+ *
19
+ * Resumes a single paused flow by publishing to the hook's topic. Use
20
+ * `subtype: one` when you know the specific hook topic to signal.
21
+ *
22
+ * ```yaml
23
+ * app:
24
+ * id: myapp
25
+ * version: '1'
26
+ * graphs:
27
+ * - subscribes: signal.start
28
+ * expire: 120
29
+ *
30
+ * activities:
31
+ * t1:
32
+ * type: trigger
33
+ *
34
+ * resume_hook:
35
+ * type: signal
36
+ * subtype: one
37
+ * topic: my.hook.topic # the hook's registered topic
38
+ * status: success # optional: success (default) or pending
39
+ * code: 200 # optional: 200 (default) or 202 (keep-alive)
40
+ * signal:
41
+ * schema:
42
+ * type: object
43
+ * properties:
44
+ * approved: { type: boolean }
45
+ * maps:
46
+ * approved: true # data delivered to the hook
47
+ *
48
+ * done:
49
+ * type: hook
50
+ *
51
+ * transitions:
52
+ * t1:
53
+ * - to: resume_hook
54
+ * resume_hook:
55
+ * - to: done
56
+ * ```
57
+ *
58
+ * A `code: 202` signal delivers data but keeps the hook alive for
59
+ * additional signals. A `code: 200` (default) closes the hook.
60
+ *
61
+ * ## YAML Configuration — Signal All
62
+ *
63
+ * Resumes all paused flows that share a common job key facet. Use
64
+ * `subtype: all` for fan-out patterns where multiple waiting flows
65
+ * should be resumed simultaneously.
66
+ *
67
+ * ```yaml
68
+ * app:
69
+ * id: myapp
70
+ * version: '1'
71
+ * graphs:
72
+ * - subscribes: signal.fan.out
73
+ * expire: 120
74
+ *
75
+ * activities:
76
+ * t1:
77
+ * type: trigger
78
+ *
79
+ * resume_all:
80
+ * type: signal
81
+ * subtype: all
82
+ * topic: hook.resume
83
+ * key_name: parent_job_id # index facet name
84
+ * key_value: '{$job.metadata.jid}'
85
+ * scrub: true # clean up indexes after use
86
+ * resolver:
87
+ * maps:
88
+ * data:
89
+ * parent_job_id: '{$job.metadata.jid}'
90
+ * scrub: true
91
+ * signal:
92
+ * maps:
93
+ * done: true # data delivered to all matching hooks
94
+ *
95
+ * done:
96
+ * type: hook
97
+ *
98
+ * transitions:
99
+ * t1:
100
+ * - to: resume_all
101
+ * resume_all:
102
+ * - to: done
103
+ * ```
104
+ *
105
+ * ## Execution Model
106
+ *
107
+ * Signal is a **Category B (Leg1-only with children)** activity:
108
+ * - Bundles the hook signal with the Leg 1 completion marker in a
109
+ * single transaction (`hookOne`) or fires best-effort (`hookAll`).
110
+ * - Executes the crash-safe `executeLeg1StepProtocol` to transition
111
+ * to adjacent activities.
112
+ *
113
+ * @see {@link SignalActivity} for the TypeScript interface
114
+ */
10
115
  class Signal extends activity_1.Activity {
11
116
  constructor(config, data, metadata, hook, engine, context) {
12
117
  super(config, data, metadata, hook, engine, context);
@@ -32,10 +137,10 @@ class Signal extends activity_1.Activity {
32
137
  if (!collator_1.CollatorService.isGuidStep1Done(this.guidLedger)) {
33
138
  const txn1 = this.store.transact();
34
139
  if (this.config.subtype === 'all') {
35
- await this.hookAll();
140
+ await this.signalAll();
36
141
  }
37
142
  else {
38
- await this.hookOne(txn1);
143
+ await this.signalOne(txn1);
39
144
  }
40
145
  await this.setState(txn1);
41
146
  if (this.adjacentIndex === 0) {
@@ -107,17 +212,17 @@ class Signal extends activity_1.Activity {
107
212
  * The signal activity will hook one. Accepts an optional transaction
108
213
  * so the hook publish can be bundled with the Leg1 completion marker.
109
214
  */
110
- async hookOne(transaction) {
215
+ async signalOne(transaction) {
111
216
  const topic = pipe_1.Pipe.resolve(this.config.topic, this.context);
112
217
  const signalInputData = this.mapSignalData();
113
218
  const status = pipe_1.Pipe.resolve(this.config.status, this.context);
114
219
  const code = pipe_1.Pipe.resolve(this.config.code, this.context);
115
- return await this.engine.hook(topic, signalInputData, status, code, transaction);
220
+ return await this.engine.signal(topic, signalInputData, status, code, transaction);
116
221
  }
117
222
  /**
118
- * The signal activity will hook all paused jobs that share the same job key.
223
+ * Signals all paused jobs that share the same job key, resuming their execution.
119
224
  */
120
- async hookAll() {
225
+ async signalAll() {
121
226
  //prep 1) generate `input signal data` (essentially the webhook payload)
122
227
  const signalInputData = this.mapSignalData();
123
228
  //prep 2) generate data that resolves the job key (per the YAML config)
@@ -130,8 +235,8 @@ class Signal extends activity_1.Activity {
130
235
  const key_name = pipe_1.Pipe.resolve(this.config.key_name, this.context);
131
236
  const key_value = pipe_1.Pipe.resolve(this.config.key_value, this.context);
132
237
  const indexQueryFacets = [`${key_name}:${key_value}`];
133
- //execute: `hookAll` will now resume all paused jobs that share the same job key
134
- return await this.engine.hookAll(this.config.topic, signalInputData, keyResolverData, indexQueryFacets);
238
+ //execute: `signalAll` will now resume all paused jobs that share the same job key
239
+ return await this.engine.signalAll(this.config.topic, signalInputData, keyResolverData, indexQueryFacets);
135
240
  }
136
241
  }
137
242
  exports.Signal = Signal;