@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
@@ -3,6 +3,107 @@ import { ActivityData, ActivityMetadata, AwaitActivity, ActivityType } from '../
3
3
  import { ProviderTransaction } from '../../types/provider';
4
4
  import { JobState } from '../../types/job';
5
5
  import { Activity } from './activity';
6
+ /**
7
+ * Invokes another graph (sub-flow) and optionally waits for its completion.
8
+ * The `await` activity enables compositional workflows where one graph
9
+ * triggers another by publishing to its `subscribes` topic, creating a
10
+ * parent-child relationship between flows.
11
+ *
12
+ * ## YAML Configuration
13
+ *
14
+ * The `topic` in the await activity must match the `subscribes` topic of
15
+ * the child graph. Both graphs are defined in the same app YAML:
16
+ *
17
+ * ```yaml
18
+ * app:
19
+ * id: myapp
20
+ * version: '1'
21
+ * graphs:
22
+ *
23
+ * # ── Parent graph ──────────────────────────────
24
+ * - subscribes: order.placed
25
+ * expire: 120
26
+ *
27
+ * activities:
28
+ * t1:
29
+ * type: trigger
30
+ * job:
31
+ * maps:
32
+ * orderId: '{$self.output.data.id}'
33
+ *
34
+ * a1:
35
+ * type: await
36
+ * topic: approval.requested # ◄── targets the child graph's subscribes
37
+ * await: true
38
+ * input:
39
+ * schema:
40
+ * type: object
41
+ * properties:
42
+ * orderId: { type: string }
43
+ * maps:
44
+ * orderId: '{t1.output.data.id}'
45
+ * output:
46
+ * schema:
47
+ * type: object
48
+ * properties:
49
+ * approved: { type: boolean }
50
+ * job:
51
+ * maps:
52
+ * approval: '{$self.output.data.approved}'
53
+ *
54
+ * done:
55
+ * type: hook
56
+ *
57
+ * transitions:
58
+ * t1:
59
+ * - to: a1
60
+ * a1:
61
+ * - to: done
62
+ *
63
+ * # ── Child graph (invoked by the await) ────────
64
+ * - subscribes: approval.requested # ◄── matched by the await activity's topic
65
+ * publishes: approval.completed
66
+ * expire: 60
67
+ *
68
+ * activities:
69
+ * t1:
70
+ * type: trigger
71
+ * review:
72
+ * type: worker
73
+ * topic: approval.review
74
+ *
75
+ * transitions:
76
+ * t1:
77
+ * - to: review
78
+ * ```
79
+ *
80
+ * ## Fire-and-Forget Mode
81
+ *
82
+ * When `await` is explicitly set to `false`, the activity starts the child
83
+ * flow but does not wait for its completion. The parent flow immediately
84
+ * continues. The child's `job_id` is returned as the output.
85
+ *
86
+ * ```yaml
87
+ * a1:
88
+ * type: await
89
+ * topic: background.process
90
+ * await: false
91
+ * job:
92
+ * maps:
93
+ * childJobId: '{$self.output.data.job_id}'
94
+ * ```
95
+ *
96
+ * ## Execution Model
97
+ *
98
+ * Await is a **Category A (duplex)** activity:
99
+ * - **Leg 1** (`process`): Maps input data and publishes a
100
+ * `StreamDataType.AWAIT` message to the engine stream. The engine
101
+ * starts the child flow.
102
+ * - **Leg 2** (`processEvent`, inherited): Receives the child flow's
103
+ * final output, maps output data, and transitions to adjacent activities.
104
+ *
105
+ * @see {@link AwaitActivity} for the TypeScript interface
106
+ */
6
107
  declare class Await extends Activity {
7
108
  config: AwaitActivity;
8
109
  constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
@@ -8,6 +8,107 @@ const pipe_1 = require("../pipe");
8
8
  const telemetry_1 = require("../telemetry");
9
9
  const stream_1 = require("../../types/stream");
10
10
  const activity_1 = require("./activity");
11
+ /**
12
+ * Invokes another graph (sub-flow) and optionally waits for its completion.
13
+ * The `await` activity enables compositional workflows where one graph
14
+ * triggers another by publishing to its `subscribes` topic, creating a
15
+ * parent-child relationship between flows.
16
+ *
17
+ * ## YAML Configuration
18
+ *
19
+ * The `topic` in the await activity must match the `subscribes` topic of
20
+ * the child graph. Both graphs are defined in the same app YAML:
21
+ *
22
+ * ```yaml
23
+ * app:
24
+ * id: myapp
25
+ * version: '1'
26
+ * graphs:
27
+ *
28
+ * # ── Parent graph ──────────────────────────────
29
+ * - subscribes: order.placed
30
+ * expire: 120
31
+ *
32
+ * activities:
33
+ * t1:
34
+ * type: trigger
35
+ * job:
36
+ * maps:
37
+ * orderId: '{$self.output.data.id}'
38
+ *
39
+ * a1:
40
+ * type: await
41
+ * topic: approval.requested # ◄── targets the child graph's subscribes
42
+ * await: true
43
+ * input:
44
+ * schema:
45
+ * type: object
46
+ * properties:
47
+ * orderId: { type: string }
48
+ * maps:
49
+ * orderId: '{t1.output.data.id}'
50
+ * output:
51
+ * schema:
52
+ * type: object
53
+ * properties:
54
+ * approved: { type: boolean }
55
+ * job:
56
+ * maps:
57
+ * approval: '{$self.output.data.approved}'
58
+ *
59
+ * done:
60
+ * type: hook
61
+ *
62
+ * transitions:
63
+ * t1:
64
+ * - to: a1
65
+ * a1:
66
+ * - to: done
67
+ *
68
+ * # ── Child graph (invoked by the await) ────────
69
+ * - subscribes: approval.requested # ◄── matched by the await activity's topic
70
+ * publishes: approval.completed
71
+ * expire: 60
72
+ *
73
+ * activities:
74
+ * t1:
75
+ * type: trigger
76
+ * review:
77
+ * type: worker
78
+ * topic: approval.review
79
+ *
80
+ * transitions:
81
+ * t1:
82
+ * - to: review
83
+ * ```
84
+ *
85
+ * ## Fire-and-Forget Mode
86
+ *
87
+ * When `await` is explicitly set to `false`, the activity starts the child
88
+ * flow but does not wait for its completion. The parent flow immediately
89
+ * continues. The child's `job_id` is returned as the output.
90
+ *
91
+ * ```yaml
92
+ * a1:
93
+ * type: await
94
+ * topic: background.process
95
+ * await: false
96
+ * job:
97
+ * maps:
98
+ * childJobId: '{$self.output.data.job_id}'
99
+ * ```
100
+ *
101
+ * ## Execution Model
102
+ *
103
+ * Await is a **Category A (duplex)** activity:
104
+ * - **Leg 1** (`process`): Maps input data and publishes a
105
+ * `StreamDataType.AWAIT` message to the engine stream. The engine
106
+ * starts the child flow.
107
+ * - **Leg 2** (`processEvent`, inherited): Receives the child flow's
108
+ * final output, maps output data, and transitions to adjacent activities.
109
+ *
110
+ * @see {@link AwaitActivity} for the TypeScript interface
111
+ */
11
112
  class Await extends activity_1.Activity {
12
113
  constructor(config, data, metadata, hook, engine, context) {
13
114
  super(config, data, metadata, hook, engine, context);
@@ -25,11 +126,11 @@ class Await extends activity_1.Activity {
25
126
  telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
26
127
  telemetry.startActivitySpan(this.leg);
27
128
  this.mapInputData();
28
- //save state and authorize reentry
129
+ //save state and mark Leg1 complete
29
130
  const transaction = this.store.transact();
30
131
  //todo: await this.registerTimeout();
31
132
  const messageId = await this.execActivity(transaction);
32
- await collator_1.CollatorService.authorizeReentry(this, transaction);
133
+ await collator_1.CollatorService.notarizeLeg1Completion(this, transaction);
33
134
  await this.setState(transaction);
34
135
  await this.setStatus(0, transaction);
35
136
  const multiResponse = (await transaction.exec());
@@ -3,6 +3,88 @@ import { ActivityData, ActivityMetadata, ActivityType, CycleActivity } from '../
3
3
  import { ProviderTransaction } from '../../types/provider';
4
4
  import { JobState } from '../../types/job';
5
5
  import { Activity } from './activity';
6
+ /**
7
+ * Re-executes an ancestor activity in a new dimensional thread, enabling
8
+ * retry loops and iterative patterns without violating the DAG constraint.
9
+ * The `cycle` activity targets a specific ancestor (typically a
10
+ * `Hook` with `cycle: true`) and sends execution back to that point.
11
+ *
12
+ * Each cycle iteration runs in a fresh **dimensional thread** — individual
13
+ * activity state is isolated per iteration, while **shared job state**
14
+ * (`job.maps`) accumulates across iterations. This pattern enables retries,
15
+ * polling loops, and iterative processing.
16
+ *
17
+ * ## YAML Configuration
18
+ *
19
+ * ```yaml
20
+ * app:
21
+ * id: myapp
22
+ * version: '1'
23
+ * graphs:
24
+ * - subscribes: retry.start
25
+ * expire: 300
26
+ *
27
+ * activities:
28
+ * t1:
29
+ * type: trigger
30
+ *
31
+ * pivot:
32
+ * type: hook
33
+ * cycle: true # marks this activity as a cycle target
34
+ * output:
35
+ * maps:
36
+ * retryCount: 0
37
+ *
38
+ * do_work:
39
+ * type: worker
40
+ * topic: work.do
41
+ * output:
42
+ * schema:
43
+ * type: object
44
+ * properties:
45
+ * result: { type: string }
46
+ *
47
+ * retry:
48
+ * type: cycle
49
+ * ancestor: pivot # re-execute from this activity
50
+ * input:
51
+ * maps:
52
+ * retryCount: # increment retry counter each cycle
53
+ * '@pipe':
54
+ * - ['{pivot.output.data.retryCount}', 1]
55
+ * - ['{@math.add}']
56
+ *
57
+ * done:
58
+ * type: hook
59
+ *
60
+ * transitions:
61
+ * t1:
62
+ * - to: pivot
63
+ * pivot:
64
+ * - to: do_work
65
+ * do_work:
66
+ * - to: retry
67
+ * conditions:
68
+ * code: 500 # cycle on error
69
+ * - to: done
70
+ * ```
71
+ *
72
+ * ## Key Behaviors
73
+ *
74
+ * - The `ancestor` field must reference an activity with `cycle: true`.
75
+ * - The cycle activity's `input.maps` override the ancestor's output data
76
+ * for the next iteration, allowing each cycle to pass different values.
77
+ * - Dimensional isolation ensures parallel cycle iterations don't collide.
78
+ *
79
+ * ## Execution Model
80
+ *
81
+ * Cycle is a **Category A (Leg 1 only)** activity:
82
+ * - Maps input data, resolves the re-entry dimensional address, and
83
+ * publishes a stream message addressed to the ancestor activity.
84
+ * - The ancestor re-enters via its Leg 2 path in the new dimension.
85
+ *
86
+ * @see {@link CycleActivity} for the TypeScript interface
87
+ */
6
88
  declare class Cycle extends Activity {
7
89
  config: CycleActivity;
8
90
  constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
@@ -6,6 +6,88 @@ const utils_1 = require("../../modules/utils");
6
6
  const collator_1 = require("../collator");
7
7
  const telemetry_1 = require("../telemetry");
8
8
  const activity_1 = require("./activity");
9
+ /**
10
+ * Re-executes an ancestor activity in a new dimensional thread, enabling
11
+ * retry loops and iterative patterns without violating the DAG constraint.
12
+ * The `cycle` activity targets a specific ancestor (typically a
13
+ * `Hook` with `cycle: true`) and sends execution back to that point.
14
+ *
15
+ * Each cycle iteration runs in a fresh **dimensional thread** — individual
16
+ * activity state is isolated per iteration, while **shared job state**
17
+ * (`job.maps`) accumulates across iterations. This pattern enables retries,
18
+ * polling loops, and iterative processing.
19
+ *
20
+ * ## YAML Configuration
21
+ *
22
+ * ```yaml
23
+ * app:
24
+ * id: myapp
25
+ * version: '1'
26
+ * graphs:
27
+ * - subscribes: retry.start
28
+ * expire: 300
29
+ *
30
+ * activities:
31
+ * t1:
32
+ * type: trigger
33
+ *
34
+ * pivot:
35
+ * type: hook
36
+ * cycle: true # marks this activity as a cycle target
37
+ * output:
38
+ * maps:
39
+ * retryCount: 0
40
+ *
41
+ * do_work:
42
+ * type: worker
43
+ * topic: work.do
44
+ * output:
45
+ * schema:
46
+ * type: object
47
+ * properties:
48
+ * result: { type: string }
49
+ *
50
+ * retry:
51
+ * type: cycle
52
+ * ancestor: pivot # re-execute from this activity
53
+ * input:
54
+ * maps:
55
+ * retryCount: # increment retry counter each cycle
56
+ * '@pipe':
57
+ * - ['{pivot.output.data.retryCount}', 1]
58
+ * - ['{@math.add}']
59
+ *
60
+ * done:
61
+ * type: hook
62
+ *
63
+ * transitions:
64
+ * t1:
65
+ * - to: pivot
66
+ * pivot:
67
+ * - to: do_work
68
+ * do_work:
69
+ * - to: retry
70
+ * conditions:
71
+ * code: 500 # cycle on error
72
+ * - to: done
73
+ * ```
74
+ *
75
+ * ## Key Behaviors
76
+ *
77
+ * - The `ancestor` field must reference an activity with `cycle: true`.
78
+ * - The cycle activity's `input.maps` override the ancestor's output data
79
+ * for the next iteration, allowing each cycle to pass different values.
80
+ * - Dimensional isolation ensures parallel cycle iterations don't collide.
81
+ *
82
+ * ## Execution Model
83
+ *
84
+ * Cycle is a **Category A (Leg 1 only)** activity:
85
+ * - Maps input data, resolves the re-entry dimensional address, and
86
+ * publishes a stream message addressed to the ancestor activity.
87
+ * - The ancestor re-enters via its Leg 2 path in the new dimension.
88
+ *
89
+ * @see {@link CycleActivity} for the TypeScript interface
90
+ */
9
91
  class Cycle extends activity_1.Activity {
10
92
  constructor(config, data, metadata, hook, engine, context) {
11
93
  super(config, data, metadata, hook, engine, context);
@@ -23,23 +105,19 @@ class Cycle extends activity_1.Activity {
23
105
  telemetry = new telemetry_1.TelemetryService(this.engine.appId, this.config, this.metadata, this.context);
24
106
  telemetry.startActivitySpan(this.leg);
25
107
  this.mapInputData();
26
- //set state/status
27
- let transaction = this.store.transact();
108
+ //set state/status, cycle ancestor, and mark Leg1 complete — single transaction
109
+ const transaction = this.store.transact();
28
110
  await this.setState(transaction);
29
111
  await this.setStatus(0, transaction); //leg 1 never changes job status
112
+ const messageId = await this.cycleAncestorActivity(transaction);
113
+ await collator_1.CollatorService.notarizeLeg1Completion(this, transaction);
30
114
  const txResponse = (await transaction.exec());
31
115
  telemetry.mapActivityAttributes();
32
116
  const jobStatus = this.resolveStatus(txResponse);
33
- //cycle the target ancestor
34
- transaction = this.store.transact();
35
- const messageId = await this.cycleAncestorActivity(transaction);
36
117
  telemetry.setActivityAttributes({
37
118
  'app.activity.mid': messageId,
38
119
  'app.job.jss': jobStatus,
39
120
  });
40
- //exit early (`Cycle` activities only execute Leg 1)
41
- await collator_1.CollatorService.notarizeEarlyExit(this, transaction);
42
- (await transaction.exec());
43
121
  return this.context.metadata.aid;
44
122
  }
45
123
  catch (error) {
@@ -7,12 +7,155 @@ import { ProviderTransaction } from '../../types/provider';
7
7
  import { StreamCode, StreamStatus } from '../../types/stream';
8
8
  import { Activity } from './activity';
9
9
  /**
10
- * Supports `signal hook`, `time hook`, and `cycle hook` patterns
10
+ * A versatile pause/resume activity that supports three distinct patterns:
11
+ * **time hook** (sleep), **web hook** (external signal), and **passthrough**
12
+ * (immediate transition with optional data mapping).
13
+ *
14
+ * The hook activity is the most flexible activity type. Depending on its
15
+ * YAML configuration, it operates in one of the following modes:
16
+ *
17
+ * ## Time Hook (Sleep)
18
+ *
19
+ * Pauses the flow for a specified duration in seconds. The `sleep` value
20
+ * can be a literal number or a `@pipe` expression for dynamic delays
21
+ * (e.g., exponential backoff).
22
+ *
23
+ * ```yaml
24
+ * app:
25
+ * id: myapp
26
+ * version: '1'
27
+ * graphs:
28
+ * - subscribes: job.start
29
+ * expire: 300
30
+ *
31
+ * activities:
32
+ * t1:
33
+ * type: trigger
34
+ *
35
+ * delay:
36
+ * type: hook
37
+ * sleep: 60 # pause for 60 seconds
38
+ * job:
39
+ * maps:
40
+ * paused_at: '{$self.output.metadata.ac}'
41
+ *
42
+ * resume:
43
+ * type: hook
44
+ *
45
+ * transitions:
46
+ * t1:
47
+ * - to: delay
48
+ * delay:
49
+ * - to: resume
50
+ * ```
51
+ *
52
+ * ## Web Hook (External Signal)
53
+ *
54
+ * Registers a webhook listener on a named topic. The flow pauses until
55
+ * an external signal is sent to the hook's topic. The signal data becomes
56
+ * available as `$self.hook.data`. The `hooks` section at the graph level
57
+ * routes incoming signals to the waiting activity.
58
+ *
59
+ * ```yaml
60
+ * app:
61
+ * id: myapp
62
+ * version: '1'
63
+ * graphs:
64
+ * - subscribes: order.placed
65
+ * expire: 3600
66
+ *
67
+ * activities:
68
+ * t1:
69
+ * type: trigger
70
+ *
71
+ * wait_for_approval:
72
+ * type: hook
73
+ * hook:
74
+ * type: object
75
+ * properties:
76
+ * approved: { type: boolean }
77
+ * job:
78
+ * maps:
79
+ * approved: '{$self.hook.data.approved}'
80
+ *
81
+ * done:
82
+ * type: hook
83
+ *
84
+ * transitions:
85
+ * t1:
86
+ * - to: wait_for_approval
87
+ * wait_for_approval:
88
+ * - to: done
89
+ *
90
+ * hooks:
91
+ * order.approval: # external topic that delivers the signal
92
+ * - to: wait_for_approval
93
+ * conditions:
94
+ * match:
95
+ * - expected: '{t1.output.data.id}'
96
+ * actual: '{$self.hook.data.id}'
97
+ * ```
98
+ *
99
+ * ## Passthrough (No Hook)
100
+ *
101
+ * When neither `sleep` nor `hook` is configured, the hook activity acts
102
+ * as a passthrough: it maps data and immediately transitions to children.
103
+ * This is useful for data transformation, convergence points, or as a
104
+ * cycle pivot (with `cycle: true`).
105
+ *
106
+ * ```yaml
107
+ * app:
108
+ * id: myapp
109
+ * version: '1'
110
+ * graphs:
111
+ * - subscribes: job.start
112
+ *
113
+ * activities:
114
+ * t1:
115
+ * type: trigger
116
+ *
117
+ * pivot:
118
+ * type: hook
119
+ * cycle: true # enables re-entry from a cycle activity
120
+ * output:
121
+ * maps:
122
+ * retryCount: 0
123
+ * job:
124
+ * maps:
125
+ * counter: '{$self.output.data.retryCount}'
126
+ *
127
+ * do_work:
128
+ * type: worker
129
+ * topic: work.do
130
+ *
131
+ * transitions:
132
+ * t1:
133
+ * - to: pivot
134
+ * pivot:
135
+ * - to: do_work
136
+ * ```
137
+ *
138
+ * ## Execution Model
139
+ *
140
+ * - **With `sleep` or `hook`**: Category A (duplex). Leg 1 registers the
141
+ * hook and saves state. Leg 2 fires when the timer expires or the
142
+ * external signal arrives (via `processTimeHookEvent` or
143
+ * `processWebHookEvent`).
144
+ * - **Without `sleep` or `hook`**: Category B (passthrough). Uses the
145
+ * crash-safe `executeLeg1StepProtocol` to map data and transition
146
+ * to adjacent activities.
147
+ *
148
+ * @see {@link HookActivity} for the TypeScript interface
11
149
  */
12
150
  declare class Hook extends Activity {
13
151
  config: HookActivity;
14
152
  constructor(config: ActivityType, data: ActivityData, metadata: ActivityMetadata, hook: ActivityData | null, engine: EngineService, context?: JobState);
15
153
  process(): Promise<string>;
154
+ /**
155
+ * Static config check: does this activity have a hook or sleep config?
156
+ * Used for routing before context is loaded.
157
+ */
158
+ isConfiguredAsHook(): boolean;
16
159
  /**
17
160
  * does this activity use a time-hook or web-hook
18
161
  */