@hotmeshio/hotmesh 0.14.6 → 0.14.8

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.
package/README.md CHANGED
@@ -29,34 +29,17 @@ Install the package:
29
29
  npm install @hotmeshio/hotmesh
30
30
  ```
31
31
 
32
- The repo includes a `docker-compose.yml` that starts Postgres, NATS, and a development container:
32
+ The repo includes a `docker-compose.yml` that starts Postgres and a development container:
33
33
 
34
34
  ```bash
35
35
  docker compose up -d
36
36
  ```
37
37
 
38
- Then follow the [Quick Start guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/quickstart.md) for a progressive walkthroughfrom a single trigger to conditional, parallel, and compositional workflows.
38
+ See the [Durable API reference](https://docs.hotmesh.io/classes/services_durable.Durable.html) for the full API surface workflows, activities, signals, child workflows, and more.
39
39
 
40
- ## Two ways to write workflows
40
+ ## Writing workflows
41
41
 
42
- Both approaches reuse your activity functions:
43
-
44
- ```typescript
45
- // activities.ts (shared between both approaches)
46
- export async function checkInventory(itemId: string): Promise<number> {
47
- return getInventoryCount(itemId);
48
- }
49
-
50
- export async function reserveItem(itemId: string, quantity: number): Promise<string> {
51
- return createReservation(itemId, quantity);
52
- }
53
-
54
- export async function notifyBackorder(itemId: string): Promise<void> {
55
- await sendBackorderEmail(itemId);
56
- }
57
- ```
58
-
59
- ### Option 1: Code
42
+ **Define the workflow** plain TypeScript with branching, loops, and error handling. Activities are proxied so their results are checkpointed and replayed on restart.
60
43
 
61
44
  ```typescript
62
45
  // workflows.ts
@@ -76,124 +59,72 @@ export async function orderWorkflow(itemId: string, qty: number) {
76
59
  return 'backordered';
77
60
  }
78
61
  }
62
+ ```
79
63
 
80
- // main.ts
81
- import * as activities from './activities';
64
+ **Start a worker** — connects to Postgres and begins processing workflows on the given task queue.
65
+
66
+ ```typescript
67
+ // worker.ts
68
+ import { Durable } from '@hotmeshio/hotmesh';
69
+ import { Client as Postgres } from 'pg';
70
+ import { orderWorkflow } from './workflows';
82
71
 
83
72
  const connection = {
84
73
  class: Postgres,
85
74
  options: { connectionString: 'postgresql://localhost:5432/mydb' }
86
75
  };
87
76
 
88
- await Durable.Worker.create({
77
+ const worker = await Durable.Worker.create({
89
78
  connection,
90
79
  taskQueue: 'orders',
91
80
  workflow: orderWorkflow,
92
- activities,
93
81
  });
94
82
 
83
+ await worker.run();
84
+ ```
85
+
86
+ **Run a workflow** — start an execution and await its result. The client can run in a different process, container, or server.
87
+
88
+ ```typescript
89
+ // client.ts
90
+ import { Durable } from '@hotmeshio/hotmesh';
91
+ import { Client as Postgres } from 'pg';
92
+
93
+ const connection = {
94
+ class: Postgres,
95
+ options: { connectionString: 'postgresql://localhost:5432/mydb' }
96
+ };
97
+
95
98
  const client = new Durable.Client({ connection });
96
99
  const handle = await client.workflow.start({
97
100
  args: ['item-123', 5],
98
101
  taskQueue: 'orders',
99
102
  workflowName: 'orderWorkflow',
100
- workflowId: 'order-456'
103
+ workflowId: 'order-456',
101
104
  });
102
105
 
103
106
  const result = await handle.result();
104
107
  ```
105
108
 
106
- ### Option 2: YAML (functional approach)
107
-
108
- ```yaml
109
- # order.yaml
110
- activities:
111
- trigger:
112
- type: trigger
113
-
114
- checkInventory:
115
- type: worker
116
- topic: inventory.check
117
-
118
- reserveItem:
119
- type: worker
120
- topic: inventory.reserve
121
-
122
- notifyBackorder:
123
- type: worker
124
- topic: inventory.backorder.notify
125
-
126
- transitions:
127
- trigger:
128
- - to: checkInventory
129
-
130
- checkInventory:
131
- - to: reserveItem
132
- conditions:
133
- match:
134
- - expected: true
135
- actual:
136
- '@pipe':
137
- - ['{checkInventory.output.data.availableQty}', '{trigger.output.data.requestedQty}']
138
- - ['{@conditional.gte}']
139
-
140
- - to: notifyBackorder
141
- conditions:
142
- match:
143
- - expected: false
144
- actual:
145
- '@pipe':
146
- - ['{checkInventory.output.data.availableQty}', '{trigger.output.data.requestedQty}']
147
- - ['{@conditional.gte}']
148
- ```
109
+ ### Activities
149
110
 
150
- Deploy and run as follows:
151
- ```typescript
152
- // main.ts (reuses same activities.ts)
153
- import * as activities from './activities';
111
+ Activities are your side-effectful functions — database calls, API requests, anything non-deterministic. HotMesh checkpoints their results so they're never re-executed on replay.
154
112
 
155
- const hotMesh = await HotMesh.init({
156
- appId: 'orders',
157
- engine: { connection },
158
- workers: [
159
- {
160
- topic: 'inventory.check',
161
- connection,
162
- callback: async (data) => {
163
- const availableQty = await activities.checkInventory(data.data.itemId);
164
- return { metadata: { ...data.metadata }, data: { availableQty } };
165
- }
166
- },
167
- {
168
- topic: 'inventory.reserve',
169
- connection,
170
- callback: async (data) => {
171
- const reservationId = await activities.reserveItem(data.data.itemId, data.data.quantity);
172
- return { metadata: { ...data.metadata }, data: { reservationId } };
173
- }
174
- },
175
- {
176
- topic: 'inventory.backorder.notify',
177
- connection,
178
- callback: async (data) => {
179
- await activities.notifyBackorder(data.data.itemId);
180
- return { metadata: { ...data.metadata } };
181
- }
182
- }
183
- ]
184
- });
113
+ ```typescript
114
+ // activities.ts
115
+ export async function checkInventory(itemId: string): Promise<number> {
116
+ return getInventoryCount(itemId);
117
+ }
185
118
 
186
- await hotMesh.deploy('./order.yaml');
187
- await hotMesh.activate('1');
119
+ export async function reserveItem(itemId: string, quantity: number): Promise<string> {
120
+ return createReservation(itemId, quantity);
121
+ }
188
122
 
189
- const result = await hotMesh.pubsub('order.requested', {
190
- itemId: 'item-123',
191
- requestedQty: 5
192
- });
123
+ export async function notifyBackorder(itemId: string): Promise<void> {
124
+ await sendBackorderEmail(itemId);
125
+ }
193
126
  ```
194
127
 
195
- Both compile to the same distributed execution model.
196
-
197
128
  ## Common patterns
198
129
 
199
130
  All snippets below run inside a workflow function (like `orderWorkflow` above). Durable methods are available as static imports:
@@ -321,6 +252,12 @@ There is no proprietary dashboard. Workflow state lives in Postgres, so use what
321
252
  - **Logging** — set `HMSH_LOGLEVEL` (`debug`, `info`, `warn`, `error`, `silent`) to control log verbosity.
322
253
  - **OpenTelemetry** — set `HMSH_TELEMETRY=true` to emit spans and metrics. Plug in any OTel-compatible collector.
323
254
 
255
+ ## YAML workflows
256
+
257
+ HotMesh also supports a declarative YAML syntax. The same activities run in both modes — the difference is compilation speed. YAML workflows compile ~10x faster because the execution graph is declared upfront rather than discovered through replay. The tradeoff is expressiveness: YAML uses a functional pipe syntax for conditions and transformations instead of native TypeScript control flow.
258
+
259
+ See the [Quick Start guide](https://github.com/hotmeshio/sdk-typescript/blob/main/docs/quickstart.md) for YAML examples and the `tests/functional/` directory for working implementations.
260
+
324
261
  ## Architecture
325
262
 
326
263
  For a deep dive into the transactional execution model — how every step is crash-safe, how the monotonic collation ledger guarantees exactly-once delivery, and how cycles and retries remain correct under arbitrary failure — see the [Collation Design Document](https://github.com/hotmeshio/sdk-typescript/blob/main/services/collator/README.md). The symbolic system (how to design workflows) and lifecycle details (how to deploy workflows) are covered in the [Architectural Overview](https://zenodo.org/records/12168558).
@@ -162,6 +162,21 @@ export declare const HMSH_XCLAIM_DELAY_MS: number;
162
162
  export declare const HMSH_XCLAIM_COUNT: number;
163
163
  export declare const HMSH_XPENDING_COUNT: number;
164
164
  export declare const HMSH_BATCH_SIZE: number;
165
+ /**
166
+ * Minimum batch size under adaptive scaling (default: 1).
167
+ *
168
+ * When stream depth is high, the adaptive logic reduces batch size
169
+ * to relieve back-pressure. This value is the floor — the smallest
170
+ * batch the system will fetch per consume cycle.
171
+ *
172
+ * - 1 (default): fully serial under max stress, safest
173
+ * - 2: retains some parallelism while limiting contention
174
+ *
175
+ * Both values produce equivalent throughput in practice (~233s for
176
+ * 1000 concurrent workflows). The reduction from the configured
177
+ * HMSH_BATCH_SIZE is what matters most — the floor is a safety net.
178
+ */
179
+ export declare const HMSH_BATCH_SIZE_MIN: number;
165
180
  /**
166
181
  * Postgres stream reservation timeout in seconds (default: 30).
167
182
  *
@@ -197,6 +212,32 @@ export declare const HMSH_BATCH_SIZE: number;
197
212
  * HMSH_RESERVATION_TIMEOUT_S=30 (default)
198
213
  */
199
214
  export declare const HMSH_RESERVATION_TIMEOUT_S: number;
215
+ /**
216
+ * Maximum reservation timeout in seconds for adaptive scaling (default: 1800).
217
+ *
218
+ * This is the ceiling for the adaptive reservation timeout — how far the
219
+ * system is allowed to stretch under sustained load. The adaptive logic
220
+ * only uses what it needs based on stream depth; this value defines the
221
+ * upper bound, not the steady state.
222
+ *
223
+ * The tradeoff is recovery time after a consumer crash: if a consumer
224
+ * reserves a message and dies, that message is unavailable until the
225
+ * timeout expires. A higher ceiling means longer recovery from crashes
226
+ * but prevents duplicate delivery under heavy sustained load.
227
+ *
228
+ * In practice, crashes are rare and the delay is bounded. The cost of
229
+ * a ceiling that is too low — duplicate delivery, collation errors,
230
+ * wasted CPU, workflow stalls — is far higher than a slightly longer
231
+ * recovery window after a crash.
232
+ *
233
+ * **Tuning guidance:**
234
+ * - Dedicated infrastructure with ample CPU: lower ceiling is fine (600s)
235
+ * - Shared/multi-tenant or CPU-constrained: use the default (1800s)
236
+ * - Long-running batch imports or large workflow graphs: increase (3600s+)
237
+ * - Cloud deployments without CPU contention: the adaptive logic will
238
+ * naturally stay near the starting timeout and rarely approach the ceiling
239
+ */
240
+ export declare const HMSH_RESERVATION_TIMEOUT_MAX_S: number;
200
241
  export declare const HMSH_EXPIRE_DURATION: number;
201
242
  export declare const HMSH_FIDELITY_SECONDS: number;
202
243
  export declare const HMSH_SCOUT_INTERVAL_SECONDS: number;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HMSH_SCOUT_INTERVAL_SECONDS = exports.HMSH_FIDELITY_SECONDS = exports.HMSH_EXPIRE_DURATION = exports.HMSH_RESERVATION_TIMEOUT_S = exports.HMSH_BATCH_SIZE = exports.HMSH_XPENDING_COUNT = exports.HMSH_XCLAIM_COUNT = exports.HMSH_XCLAIM_DELAY_MS = exports.HMSH_BLOCK_TIME_MS = exports.HMSH_DURABLE_INITIAL_INTERVAL = exports.HMSH_DURABLE_EXP_BACKOFF = exports.HMSH_DURABLE_MAX_INTERVAL = exports.HMSH_DURABLE_MAX_ATTEMPTS = exports.HMSH_GRADUATED_INTERVAL_MS = exports.HMSH_MAX_TIMEOUT_MS = exports.HMSH_POISON_MESSAGE_THRESHOLD = exports.HMSH_MAX_RETRIES = exports.MAX_DELAY = exports.MAX_STREAM_RETRIES = exports.INITIAL_STREAM_BACKOFF = exports.MAX_STREAM_BACKOFF = exports.HMSH_EXPIRE_JOB_SECONDS = exports.HMSH_OTT_WAIT_TIME = exports.HMSH_DEPLOYMENT_PAUSE = exports.HMSH_DEPLOYMENT_DELAY = exports.HMSH_ACTIVATION_MAX_RETRY = exports.HMSH_QUORUM_DELAY_MS = exports.HMSH_QUORUM_ROLLCALL_CYCLES = exports.HMSH_STATUS_UNKNOWN = exports.HMSH_CODE_DURABLE_RETRYABLE = exports.HMSH_CODE_DURABLE_FATAL = exports.HMSH_CODE_DURABLE_MAXED = exports.HMSH_CODE_DURABLE_TIMEOUT = exports.HMSH_CODE_DURABLE_WAIT = exports.HMSH_CODE_DURABLE_CONTINUE = exports.HMSH_CODE_DURABLE_PROXY = exports.HMSH_CODE_DURABLE_CHILD = exports.HMSH_CODE_DURABLE_ALL = exports.HMSH_CODE_DURABLE_SLEEP = exports.HMSH_CODE_UNACKED = exports.HMSH_CODE_TIMEOUT = exports.HMSH_CODE_UNKNOWN = exports.HMSH_CODE_INTERRUPT = exports.HMSH_CODE_NOTFOUND = exports.HMSH_CODE_PENDING = exports.HMSH_CODE_SUCCESS = exports.HMSH_PENDING_SIGNAL_EXPIRE = exports.HMSH_SIGNAL_EXPIRE = exports.HMSH_TELEMETRY = exports.HMSH_LOGLEVEL = void 0;
4
- exports.HMSH_ROUTER_POLL_FALLBACK_INTERVAL = exports.HMSH_NOTIFY_PAYLOAD_LIMIT = exports.DEFAULT_TASK_QUEUE = exports.HMSH_GUID_SIZE = exports.HMSH_ROUTER_SCOUT_INTERVAL_MS = exports.HMSH_ROUTER_SCOUT_INTERVAL_SECONDS = void 0;
3
+ exports.HMSH_EXPIRE_DURATION = exports.HMSH_RESERVATION_TIMEOUT_MAX_S = exports.HMSH_RESERVATION_TIMEOUT_S = exports.HMSH_BATCH_SIZE_MIN = exports.HMSH_BATCH_SIZE = exports.HMSH_XPENDING_COUNT = exports.HMSH_XCLAIM_COUNT = exports.HMSH_XCLAIM_DELAY_MS = exports.HMSH_BLOCK_TIME_MS = exports.HMSH_DURABLE_INITIAL_INTERVAL = exports.HMSH_DURABLE_EXP_BACKOFF = exports.HMSH_DURABLE_MAX_INTERVAL = exports.HMSH_DURABLE_MAX_ATTEMPTS = exports.HMSH_GRADUATED_INTERVAL_MS = exports.HMSH_MAX_TIMEOUT_MS = exports.HMSH_POISON_MESSAGE_THRESHOLD = exports.HMSH_MAX_RETRIES = exports.MAX_DELAY = exports.MAX_STREAM_RETRIES = exports.INITIAL_STREAM_BACKOFF = exports.MAX_STREAM_BACKOFF = exports.HMSH_EXPIRE_JOB_SECONDS = exports.HMSH_OTT_WAIT_TIME = exports.HMSH_DEPLOYMENT_PAUSE = exports.HMSH_DEPLOYMENT_DELAY = exports.HMSH_ACTIVATION_MAX_RETRY = exports.HMSH_QUORUM_DELAY_MS = exports.HMSH_QUORUM_ROLLCALL_CYCLES = exports.HMSH_STATUS_UNKNOWN = exports.HMSH_CODE_DURABLE_RETRYABLE = exports.HMSH_CODE_DURABLE_FATAL = exports.HMSH_CODE_DURABLE_MAXED = exports.HMSH_CODE_DURABLE_TIMEOUT = exports.HMSH_CODE_DURABLE_WAIT = exports.HMSH_CODE_DURABLE_CONTINUE = exports.HMSH_CODE_DURABLE_PROXY = exports.HMSH_CODE_DURABLE_CHILD = exports.HMSH_CODE_DURABLE_ALL = exports.HMSH_CODE_DURABLE_SLEEP = exports.HMSH_CODE_UNACKED = exports.HMSH_CODE_TIMEOUT = exports.HMSH_CODE_UNKNOWN = exports.HMSH_CODE_INTERRUPT = exports.HMSH_CODE_NOTFOUND = exports.HMSH_CODE_PENDING = exports.HMSH_CODE_SUCCESS = exports.HMSH_PENDING_SIGNAL_EXPIRE = exports.HMSH_SIGNAL_EXPIRE = exports.HMSH_TELEMETRY = exports.HMSH_LOGLEVEL = void 0;
4
+ exports.HMSH_ROUTER_POLL_FALLBACK_INTERVAL = exports.HMSH_NOTIFY_PAYLOAD_LIMIT = exports.DEFAULT_TASK_QUEUE = exports.HMSH_GUID_SIZE = exports.HMSH_ROUTER_SCOUT_INTERVAL_MS = exports.HMSH_ROUTER_SCOUT_INTERVAL_SECONDS = exports.HMSH_SCOUT_INTERVAL_SECONDS = exports.HMSH_FIDELITY_SECONDS = void 0;
5
5
  /**
6
6
  * Determines the log level for the application. The default is 'info'.
7
7
  */
@@ -179,6 +179,21 @@ exports.HMSH_XCLAIM_DELAY_MS = parseInt(process.env.HMSH_XCLAIM_DELAY_MS, 10) ||
179
179
  exports.HMSH_XCLAIM_COUNT = parseInt(process.env.HMSH_XCLAIM_COUNT, 10) || 3;
180
180
  exports.HMSH_XPENDING_COUNT = parseInt(process.env.HMSH_XPENDING_COUNT, 10) || 10;
181
181
  exports.HMSH_BATCH_SIZE = parseInt(process.env.HMSH_BATCH_SIZE, 10) || 10;
182
+ /**
183
+ * Minimum batch size under adaptive scaling (default: 1).
184
+ *
185
+ * When stream depth is high, the adaptive logic reduces batch size
186
+ * to relieve back-pressure. This value is the floor — the smallest
187
+ * batch the system will fetch per consume cycle.
188
+ *
189
+ * - 1 (default): fully serial under max stress, safest
190
+ * - 2: retains some parallelism while limiting contention
191
+ *
192
+ * Both values produce equivalent throughput in practice (~233s for
193
+ * 1000 concurrent workflows). The reduction from the configured
194
+ * HMSH_BATCH_SIZE is what matters most — the floor is a safety net.
195
+ */
196
+ exports.HMSH_BATCH_SIZE_MIN = parseInt(process.env.HMSH_BATCH_SIZE_MIN, 10) || 1;
182
197
  /**
183
198
  * Postgres stream reservation timeout in seconds (default: 30).
184
199
  *
@@ -214,6 +229,32 @@ exports.HMSH_BATCH_SIZE = parseInt(process.env.HMSH_BATCH_SIZE, 10) || 10;
214
229
  * HMSH_RESERVATION_TIMEOUT_S=30 (default)
215
230
  */
216
231
  exports.HMSH_RESERVATION_TIMEOUT_S = parseInt(process.env.HMSH_RESERVATION_TIMEOUT_S, 10) || 30;
232
+ /**
233
+ * Maximum reservation timeout in seconds for adaptive scaling (default: 1800).
234
+ *
235
+ * This is the ceiling for the adaptive reservation timeout — how far the
236
+ * system is allowed to stretch under sustained load. The adaptive logic
237
+ * only uses what it needs based on stream depth; this value defines the
238
+ * upper bound, not the steady state.
239
+ *
240
+ * The tradeoff is recovery time after a consumer crash: if a consumer
241
+ * reserves a message and dies, that message is unavailable until the
242
+ * timeout expires. A higher ceiling means longer recovery from crashes
243
+ * but prevents duplicate delivery under heavy sustained load.
244
+ *
245
+ * In practice, crashes are rare and the delay is bounded. The cost of
246
+ * a ceiling that is too low — duplicate delivery, collation errors,
247
+ * wasted CPU, workflow stalls — is far higher than a slightly longer
248
+ * recovery window after a crash.
249
+ *
250
+ * **Tuning guidance:**
251
+ * - Dedicated infrastructure with ample CPU: lower ceiling is fine (600s)
252
+ * - Shared/multi-tenant or CPU-constrained: use the default (1800s)
253
+ * - Long-running batch imports or large workflow graphs: increase (3600s+)
254
+ * - Cloud deployments without CPU contention: the adaptive logic will
255
+ * naturally stay near the starting timeout and rarely approach the ceiling
256
+ */
257
+ exports.HMSH_RESERVATION_TIMEOUT_MAX_S = parseInt(process.env.HMSH_RESERVATION_TIMEOUT_MAX_S, 10) || 1800;
217
258
  // TASK WORKER
218
259
  exports.HMSH_EXPIRE_DURATION = parseInt(process.env.HMSH_EXPIRE_DURATION, 10) || 1;
219
260
  const BASE_FIDELITY_SECONDS = 5;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/hotmesh",
3
- "version": "0.14.6",
3
+ "version": "0.14.8",
4
4
  "description": "Durable Workflow",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -181,6 +181,20 @@ class Worker extends activity_1.Activity {
181
181
  retry: this.config.retry,
182
182
  };
183
183
  }
184
+ // Propagate per-activity retry config as _streamRetryConfig so
185
+ // the engine-level retry mechanism uses it for exponential backoff.
186
+ // The durable module's maximumAttempts means max retries
187
+ // (total executions = 1 + maximumAttempts), while the engine's
188
+ // max_retry_attempts means total attempts. Add 1 to align.
189
+ if (jobData?.maximumAttempts || jobData?.backoffCoefficient || jobData?.maximumInterval || jobData?.initialInterval) {
190
+ const durableMaxAttempts = jobData.maximumAttempts ?? 50;
191
+ streamData._streamRetryConfig = {
192
+ max_retry_attempts: durableMaxAttempts + 1,
193
+ backoff_coefficient: jobData.backoffCoefficient ?? 10,
194
+ maximum_interval_seconds: jobData.maximumInterval ?? 120,
195
+ initialInterval: jobData.initialInterval ?? 1,
196
+ };
197
+ }
184
198
  return (await this.engine.router?.publishMessage(topic, streamData, transaction));
185
199
  }
186
200
  }
@@ -474,10 +474,10 @@ class ExporterService {
474
474
  const activityArgsField = this.resolveSymbolField(symbolSets, 'activity_trigger', 'activity_trigger/output/data/arguments');
475
475
  const workflowArgsField = this.resolveSymbolField(symbolSets, 'trigger', 'trigger/output/data/arguments');
476
476
  // ── 1. Enrich activity inputs ──
477
- if (activityArgsField) {
477
+ {
478
478
  const activityEvents = execution.events.filter((e) => e.event_type === 'activity_task_scheduled' || e.event_type === 'activity_task_completed' || e.event_type === 'activity_task_failed');
479
479
  if (activityEvents.length > 0) {
480
- const { byJobId, byNameIndex } = await this.store.getActivityInputs(workflowId, activityArgsField);
480
+ const { byJobId, byNameIndex } = await this.store.getActivityInputs(workflowId, activityArgsField || '');
481
481
  for (const evt of activityEvents) {
482
482
  const attrs = evt.attributes;
483
483
  let input = attrs.timeline_key ? byJobId.get(attrs.timeline_key) : undefined;
@@ -1,22 +1,4 @@
1
- /**
2
- *********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
3
- *
4
- * This HotMesh application spec uses 50 activities and 25 transitions
5
- * to model a durable workflow engine using a pluggable backend.
6
- *
7
- * This YAML file can also serve as a useful starting point for building
8
- * Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
9
- * for a physical application server.
10
- *
11
- * Possible use cases include:
12
- * * Orchestration servers
13
- * * Integration servers
14
- * * BPMN engines
15
- * * Reentrant process servers
16
- * * Service Meshes
17
- * * Master Data Management systems
18
- */
19
- declare const APP_VERSION = "11";
1
+ declare const APP_VERSION = "12";
20
2
  declare const APP_ID = "durable";
21
3
  /**
22
4
  * returns a new durable workflow schema