@hotmeshio/hotmesh 0.0.55 → 0.0.57

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 (182) hide show
  1. package/README.md +1 -1
  2. package/build/modules/enums.js +1 -10
  3. package/build/modules/key.d.ts +0 -38
  4. package/build/modules/key.js +4 -46
  5. package/build/modules/utils.d.ts +0 -8
  6. package/build/modules/utils.js +0 -14
  7. package/build/package.json +11 -4
  8. package/build/services/activities/activity.d.ts +0 -28
  9. package/build/services/activities/activity.js +1 -46
  10. package/build/services/activities/await.js +0 -4
  11. package/build/services/activities/cycle.d.ts +0 -7
  12. package/build/services/activities/cycle.js +1 -16
  13. package/build/services/activities/hook.d.ts +0 -6
  14. package/build/services/activities/hook.js +2 -12
  15. package/build/services/activities/interrupt.js +0 -8
  16. package/build/services/activities/signal.d.ts +0 -6
  17. package/build/services/activities/signal.js +0 -15
  18. package/build/services/activities/trigger.d.ts +0 -4
  19. package/build/services/activities/trigger.js +1 -7
  20. package/build/services/activities/worker.js +0 -4
  21. package/build/services/collator/index.d.ts +0 -70
  22. package/build/services/collator/index.js +1 -91
  23. package/build/services/compiler/deployer.js +6 -38
  24. package/build/services/compiler/index.d.ts +0 -15
  25. package/build/services/compiler/index.js +0 -20
  26. package/build/services/compiler/validator.d.ts +0 -3
  27. package/build/services/compiler/validator.js +0 -25
  28. package/build/services/connector/clients/ioredis.d.ts +2 -2
  29. package/build/services/connector/clients/ioredis.js +0 -2
  30. package/build/services/connector/clients/redis.d.ts +4 -4
  31. package/build/services/connector/clients/redis.js +1 -3
  32. package/build/services/connector/index.d.ts +1 -1
  33. package/build/services/connector/index.js +0 -2
  34. package/build/services/durable/client.d.ts +1 -26
  35. package/build/services/durable/client.js +0 -56
  36. package/build/services/durable/exporter.d.ts +0 -22
  37. package/build/services/durable/exporter.js +1 -30
  38. package/build/services/durable/handle.d.ts +0 -36
  39. package/build/services/durable/handle.js +0 -46
  40. package/build/services/durable/index.d.ts +0 -4
  41. package/build/services/durable/index.js +0 -4
  42. package/build/services/durable/schemas/factory.d.ts +0 -29
  43. package/build/services/durable/schemas/factory.js +0 -29
  44. package/build/services/durable/search.d.ts +1 -36
  45. package/build/services/durable/search.js +56 -56
  46. package/build/services/durable/worker.js +2 -22
  47. package/build/services/durable/workflow.d.ts +0 -114
  48. package/build/services/durable/workflow.js +1 -141
  49. package/build/services/engine/index.d.ts +1 -6
  50. package/build/services/engine/index.js +1 -43
  51. package/build/services/exporter/index.d.ts +0 -27
  52. package/build/services/exporter/index.js +0 -33
  53. package/build/services/hotmesh/index.d.ts +2 -2
  54. package/build/services/hotmesh/index.js +1 -9
  55. package/build/services/logger/index.js +0 -2
  56. package/build/services/mapper/index.d.ts +0 -14
  57. package/build/services/mapper/index.js +0 -14
  58. package/build/services/pipe/functions/date.d.ts +0 -7
  59. package/build/services/pipe/functions/date.js +0 -7
  60. package/build/services/pipe/functions/math.js +0 -2
  61. package/build/services/pipe/index.d.ts +0 -15
  62. package/build/services/pipe/index.js +2 -23
  63. package/build/services/quorum/index.d.ts +0 -7
  64. package/build/services/quorum/index.js +0 -21
  65. package/build/services/reporter/index.d.ts +0 -5
  66. package/build/services/reporter/index.js +0 -9
  67. package/build/services/router/index.d.ts +0 -9
  68. package/build/services/router/index.js +2 -38
  69. package/build/services/serializer/index.js +7 -26
  70. package/build/services/store/cache.d.ts +0 -18
  71. package/build/services/store/cache.js +0 -18
  72. package/build/services/store/clients/ioredis.d.ts +1 -1
  73. package/build/services/store/clients/ioredis.js +0 -1
  74. package/build/services/store/clients/redis.d.ts +1 -1
  75. package/build/services/store/index.d.ts +0 -55
  76. package/build/services/store/index.js +5 -81
  77. package/build/services/stream/clients/ioredis.d.ts +1 -1
  78. package/build/services/stream/clients/ioredis.js +1 -4
  79. package/build/services/stream/clients/redis.d.ts +1 -1
  80. package/build/services/sub/clients/ioredis.d.ts +1 -1
  81. package/build/services/sub/clients/redis.d.ts +1 -1
  82. package/build/services/task/index.d.ts +0 -9
  83. package/build/services/task/index.js +0 -31
  84. package/build/services/telemetry/index.d.ts +0 -7
  85. package/build/services/telemetry/index.js +1 -13
  86. package/build/services/worker/index.d.ts +0 -4
  87. package/build/services/worker/index.js +2 -6
  88. package/build/types/activity.d.ts +0 -81
  89. package/build/types/durable.d.ts +26 -177
  90. package/build/types/exporter.d.ts +0 -13
  91. package/build/types/hotmesh.d.ts +4 -16
  92. package/build/types/hotmesh.js +0 -3
  93. package/build/types/index.d.ts +4 -6
  94. package/build/types/index.js +4 -3
  95. package/build/types/job.d.ts +1 -86
  96. package/build/types/pipe.d.ts +0 -65
  97. package/build/types/quorum.d.ts +15 -10
  98. package/build/types/redis.d.ts +225 -7
  99. package/build/types/redis.js +9 -0
  100. package/build/types/stream.d.ts +0 -58
  101. package/build/types/stream.js +0 -4
  102. package/package.json +11 -4
  103. package/types/durable.ts +131 -4
  104. package/types/hotmesh.ts +3 -6
  105. package/types/index.ts +23 -10
  106. package/types/job.ts +1 -1
  107. package/types/quorum.ts +22 -0
  108. package/types/redis.ts +267 -18
  109. package/build/types/ioredisclient.d.ts +0 -5
  110. package/build/types/ioredisclient.js +0 -5
  111. package/build/types/redisclient.d.ts +0 -26
  112. package/build/types/redisclient.js +0 -2
  113. package/modules/enums.ts +0 -62
  114. package/modules/errors.ts +0 -280
  115. package/modules/key.ts +0 -101
  116. package/modules/storage.ts +0 -3
  117. package/modules/utils.ts +0 -242
  118. package/services/activities/activity.ts +0 -589
  119. package/services/activities/await.ts +0 -113
  120. package/services/activities/cycle.ts +0 -115
  121. package/services/activities/hook.ts +0 -197
  122. package/services/activities/index.ts +0 -19
  123. package/services/activities/interrupt.ts +0 -172
  124. package/services/activities/signal.ts +0 -148
  125. package/services/activities/trigger.ts +0 -295
  126. package/services/activities/worker.ts +0 -107
  127. package/services/collator/README.md +0 -102
  128. package/services/collator/index.ts +0 -291
  129. package/services/compiler/deployer.ts +0 -504
  130. package/services/compiler/index.ts +0 -98
  131. package/services/compiler/validator.ts +0 -158
  132. package/services/connector/clients/ioredis.ts +0 -57
  133. package/services/connector/clients/redis.ts +0 -72
  134. package/services/connector/index.ts +0 -42
  135. package/services/durable/client.ts +0 -266
  136. package/services/durable/connection.ts +0 -10
  137. package/services/durable/exporter.ts +0 -232
  138. package/services/durable/handle.ts +0 -160
  139. package/services/durable/index.ts +0 -27
  140. package/services/durable/schemas/factory.ts +0 -2358
  141. package/services/durable/search.ts +0 -196
  142. package/services/durable/worker.ts +0 -401
  143. package/services/durable/workflow.ts +0 -557
  144. package/services/engine/index.ts +0 -761
  145. package/services/exporter/index.ts +0 -146
  146. package/services/hotmesh/index.ts +0 -237
  147. package/services/logger/index.ts +0 -79
  148. package/services/mapper/index.ts +0 -89
  149. package/services/pipe/functions/array.ts +0 -78
  150. package/services/pipe/functions/bitwise.ts +0 -27
  151. package/services/pipe/functions/conditional.ts +0 -35
  152. package/services/pipe/functions/date.ts +0 -220
  153. package/services/pipe/functions/index.ts +0 -27
  154. package/services/pipe/functions/json.ts +0 -11
  155. package/services/pipe/functions/logical.ts +0 -11
  156. package/services/pipe/functions/math.ts +0 -217
  157. package/services/pipe/functions/number.ts +0 -75
  158. package/services/pipe/functions/object.ts +0 -98
  159. package/services/pipe/functions/string.ts +0 -86
  160. package/services/pipe/functions/symbol.ts +0 -39
  161. package/services/pipe/functions/unary.ts +0 -19
  162. package/services/pipe/index.ts +0 -216
  163. package/services/quorum/index.ts +0 -319
  164. package/services/reporter/index.ts +0 -387
  165. package/services/router/index.ts +0 -426
  166. package/services/serializer/README.md +0 -10
  167. package/services/serializer/index.ts +0 -285
  168. package/services/store/cache.ts +0 -172
  169. package/services/store/clients/ioredis.ts +0 -145
  170. package/services/store/clients/redis.ts +0 -191
  171. package/services/store/index.ts +0 -1091
  172. package/services/stream/clients/ioredis.ts +0 -157
  173. package/services/stream/clients/redis.ts +0 -158
  174. package/services/stream/index.ts +0 -58
  175. package/services/sub/clients/ioredis.ts +0 -83
  176. package/services/sub/clients/redis.ts +0 -74
  177. package/services/sub/index.ts +0 -25
  178. package/services/task/index.ts +0 -250
  179. package/services/telemetry/index.ts +0 -273
  180. package/services/worker/index.ts +0 -248
  181. package/types/ioredisclient.ts +0 -10
  182. package/types/redisclient.ts +0 -30
@@ -10,42 +10,20 @@ declare class ExporterService {
10
10
  symbols: Promise<Symbols> | Symbols;
11
11
  private static symbols;
12
12
  constructor(appId: string, store: StoreService<RedisClient, RedisMulti>, logger: ILogger);
13
- /**
14
- * Convert the job hash from its compiles format into a DurableJobExport object with
15
- * facets that describe the workflow in terms relevant to narrative storytelling.
16
- */
17
13
  export(jobId: string, options?: ExportOptions): Promise<DurableJobExport>;
18
- /**
19
- * Inflates the job data from Redis into a DurableJobExport object
20
- * @param jobHash - the job data from Redis
21
- * @param dependencyList - the list of dependencies for the job
22
- * @returns - the inflated job data
23
- */
24
14
  inflate(jobHash: StringStringType, options: ExportOptions): DurableJobExport;
25
15
  resolveValue(raw: string, withValues: boolean): Record<string, any> | string | number | null;
26
- /**
27
- * Inflates the key from Redis, 3-character symbol
28
- * into a human-readable JSON path, reflecting the
29
- * tree-like structure of the unidimensional Hash
30
- * @private
31
- */
32
16
  inflateKey(key: string): string;
33
17
  filterFields(fullObject: DurableJobExport, block?: ExportFields[], allow?: ExportFields[]): Partial<DurableJobExport>;
34
18
  inflateTransition(match: RegExpMatchArray, value: string, transitionsObject: Record<string, TransitionType>): void;
35
19
  sortEntriesByCreated(obj: {
36
20
  [key: string]: TransitionType;
37
21
  }): TransitionType[];
38
- /**
39
- * marker names are overloaded with details like sequence, type, etc
40
- */
41
22
  keyToObject(key: string): {
42
23
  index: number;
43
24
  dimension?: string;
44
25
  secondary?: number;
45
26
  };
46
- /**
47
- * idem list has a complicated sort order based on indexes and dimensions
48
- */
49
27
  sortParts(parts: TimelineType[]): TimelineType[];
50
28
  }
51
29
  export { ExporterService };
@@ -9,10 +9,6 @@ class ExporterService {
9
9
  this.logger = logger;
10
10
  this.store = store;
11
11
  }
12
- /**
13
- * Convert the job hash from its compiles format into a DurableJobExport object with
14
- * facets that describe the workflow in terms relevant to narrative storytelling.
15
- */
16
12
  async export(jobId, options = {}) {
17
13
  if (!ExporterService.symbols.has(this.appId)) {
18
14
  const symbols = this.store.getAllSymbols();
@@ -22,12 +18,6 @@ class ExporterService {
22
18
  const jobExport = this.inflate(jobData, options);
23
19
  return jobExport;
24
20
  }
25
- /**
26
- * Inflates the job data from Redis into a DurableJobExport object
27
- * @param jobHash - the job data from Redis
28
- * @param dependencyList - the list of dependencies for the job
29
- * @returns - the inflated job data
30
- */
31
21
  inflate(jobHash, options) {
32
22
  const timeline = [];
33
23
  const state = {};
@@ -37,20 +27,16 @@ class ExporterService {
37
27
  Object.entries(jobHash).forEach(([key, value]) => {
38
28
  const match = key.match(regex);
39
29
  if (match) {
40
- //transitions
41
30
  this.inflateTransition(match, value, transitionsObject);
42
31
  }
43
32
  else if (key.length === 3) {
44
- //state
45
33
  state[this.inflateKey(key)] = serializer_1.SerializerService.fromString(value);
46
34
  }
47
35
  else if (key.startsWith('_')) {
48
- //data
49
36
  data[key.substring(1)] = value;
50
37
  }
51
38
  else if (key.startsWith('-')) {
52
- //timeline
53
- const keyParts = this.keyToObject(key); //key parts have meaning
39
+ const keyParts = this.keyToObject(key);
54
40
  timeline.push({
55
41
  ...keyParts,
56
42
  key,
@@ -81,12 +67,6 @@ class ExporterService {
81
67
  }
82
68
  return resolved;
83
69
  }
84
- /**
85
- * Inflates the key from Redis, 3-character symbol
86
- * into a human-readable JSON path, reflecting the
87
- * tree-like structure of the unidimensional Hash
88
- * @private
89
- */
90
70
  inflateKey(key) {
91
71
  const symbols = ExporterService.symbols.get(this.appId);
92
72
  if (key in symbols) {
@@ -124,7 +104,6 @@ class ExporterService {
124
104
  const activity = parts[0];
125
105
  const isCreate = path.endsWith('/output/metadata/ac');
126
106
  const isUpdate = path.endsWith('/output/metadata/au');
127
- //for now only export activity start/stop; activity data would also be interesting
128
107
  if (isCreate || isUpdate) {
129
108
  const targetName = `${activity},${dimensions}`;
130
109
  let target = transitionsObject[targetName];
@@ -148,9 +127,6 @@ class ExporterService {
148
127
  });
149
128
  return entriesArray;
150
129
  }
151
- /**
152
- * marker names are overloaded with details like sequence, type, etc
153
- */
154
130
  keyToObject(key) {
155
131
  function extractDimension(label) {
156
132
  const parts = label.split(',');
@@ -161,14 +137,12 @@ class ExporterService {
161
137
  }
162
138
  const parts = key.split('-');
163
139
  if (parts.length === 4) {
164
- //-proxy-5- -search-1-1-
165
140
  return {
166
141
  index: parseInt(parts[2], 10),
167
142
  dimension: extractDimension(parts[1]),
168
143
  };
169
144
  }
170
145
  else {
171
- //-search,0,0-1-1- -proxy,0,0-1-
172
146
  return {
173
147
  index: parseInt(parts[2], 10),
174
148
  secondary: parseInt(parts[3], 10),
@@ -176,9 +150,6 @@ class ExporterService {
176
150
  };
177
151
  }
178
152
  }
179
- /**
180
- * idem list has a complicated sort order based on indexes and dimensions
181
- */
182
153
  sortParts(parts) {
183
154
  return parts.sort((a, b) => {
184
155
  const { dimension: aDim, index: aIdx, secondary: aSec } = a;
@@ -10,47 +10,11 @@ export declare class WorkflowHandleService {
10
10
  workflowId: string;
11
11
  constructor(hotMesh: HotMesh, workflowTopic: string, workflowId: string);
12
12
  export(options?: ExportOptions): Promise<DurableJobExport>;
13
- /**
14
- * Sends a signal to the workflow. This is a way to send
15
- * a message to a workflow that is paused due to having
16
- * executed `Durable.workflow.waitFor`. The workflow
17
- * will awaken if no other signals are pending.
18
- */
19
13
  signal(signalId: string, data: Record<any, any>): Promise<void>;
20
- /**
21
- * Returns the job state of the workflow. If the workflow has completed
22
- * this is also the job output. If the workflow is still running, this
23
- * is the current state of the job, but it may change depending upon
24
- * the activities that remain.
25
- */
26
14
  state(metadata?: boolean): Promise<Record<string, any>>;
27
- /**
28
- * Returns the current search state of the workflow. This is
29
- * different than the job state or individual activity state.
30
- * Search state represents name/value pairs that were added
31
- * to the workflow. As the workflow is stored in a Redis hash,
32
- * this is a way to store additional data that is indexed
33
- * and searchable using the RediSearch module.
34
- */
35
15
  queryState(fields: string[]): Promise<Record<string, any>>;
36
- /**
37
- * Returns the current status of the workflow. This is a semaphore
38
- * value that represents the current state of the workflow, where
39
- * 0 is complete and a negative value represents that the flow was
40
- * interrupted.
41
- */
42
16
  status(): Promise<number>;
43
- /**
44
- * Interrupts a running workflow. Standard Job Completion tasks will
45
- * run. Subscribers will be notified and the job hash will be expired.
46
- */
47
17
  interrupt(options?: JobInterruptOptions): Promise<string>;
48
- /**
49
- * Waits for the workflow to complete and returns the result. If
50
- * the workflow response includes an error, this method will rethrow
51
- * the error, including the stack trace if available.
52
- * Wrap calls in a try/catch as necessary to avoid unhandled exceptions.
53
- */
54
18
  result<T>(config?: {
55
19
  state?: boolean;
56
20
  throwOnError?: boolean;
@@ -12,21 +12,9 @@ class WorkflowHandleService {
12
12
  async export(options) {
13
13
  return this.exporter.export(this.workflowId, options);
14
14
  }
15
- /**
16
- * Sends a signal to the workflow. This is a way to send
17
- * a message to a workflow that is paused due to having
18
- * executed `Durable.workflow.waitFor`. The workflow
19
- * will awaken if no other signals are pending.
20
- */
21
15
  async signal(signalId, data) {
22
16
  await this.hotMesh.hook(`${this.hotMesh.appId}.wfs.signal`, { id: signalId, data });
23
17
  }
24
- /**
25
- * Returns the job state of the workflow. If the workflow has completed
26
- * this is also the job output. If the workflow is still running, this
27
- * is the current state of the job, but it may change depending upon
28
- * the activities that remain.
29
- */
30
18
  async state(metadata = false) {
31
19
  const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
32
20
  if (!state.data && state.metadata.err) {
@@ -34,56 +22,25 @@ class WorkflowHandleService {
34
22
  }
35
23
  return metadata ? state : state.data;
36
24
  }
37
- /**
38
- * Returns the current search state of the workflow. This is
39
- * different than the job state or individual activity state.
40
- * Search state represents name/value pairs that were added
41
- * to the workflow. As the workflow is stored in a Redis hash,
42
- * this is a way to store additional data that is indexed
43
- * and searchable using the RediSearch module.
44
- */
45
25
  async queryState(fields) {
46
26
  return await this.hotMesh.getQueryState(this.workflowId, fields);
47
27
  }
48
- /**
49
- * Returns the current status of the workflow. This is a semaphore
50
- * value that represents the current state of the workflow, where
51
- * 0 is complete and a negative value represents that the flow was
52
- * interrupted.
53
- */
54
28
  async status() {
55
29
  return await this.hotMesh.getStatus(this.workflowId);
56
30
  }
57
- /**
58
- * Interrupts a running workflow. Standard Job Completion tasks will
59
- * run. Subscribers will be notified and the job hash will be expired.
60
- */
61
31
  async interrupt(options) {
62
32
  return await this.hotMesh.interrupt(`${this.hotMesh.appId}.execute`, this.workflowId, options);
63
33
  }
64
- /**
65
- * Waits for the workflow to complete and returns the result. If
66
- * the workflow response includes an error, this method will rethrow
67
- * the error, including the stack trace if available.
68
- * Wrap calls in a try/catch as necessary to avoid unhandled exceptions.
69
- */
70
34
  async result(config) {
71
35
  const topic = `${this.hotMesh.appId}.executed.${this.workflowId}`;
72
36
  let isResolved = false;
73
37
  return new Promise(async (resolve, reject) => {
74
- /**
75
- * rejects/resolves the promise based on the `throwOnError`
76
- * default behavior is to throw if error
77
- */
78
38
  const safeReject = (err) => {
79
39
  if (config?.throwOnError === false) {
80
40
  return resolve(err);
81
41
  }
82
42
  reject(err);
83
43
  };
84
- /**
85
- * Common completion function that unsubscribes from the topic/returns
86
- */
87
44
  const complete = async (response, err) => {
88
45
  if (isResolved)
89
46
  return;
@@ -106,7 +63,6 @@ class WorkflowHandleService {
106
63
  }
107
64
  resolve(response);
108
65
  };
109
- //more expensive; fetches the entire job, not just the `status`
110
66
  if (config?.state) {
111
67
  const state = await this.hotMesh.getState(`${this.hotMesh.appId}.execute`, this.workflowId);
112
68
  if (state?.data?.done && !state.data?.$error) {
@@ -119,7 +75,6 @@ class WorkflowHandleService {
119
75
  return complete(null, JSON.parse(state.metadata.err));
120
76
  }
121
77
  }
122
- //subscribe to 'done' topic
123
78
  this.hotMesh.sub(topic, async (_topic, state) => {
124
79
  this.hotMesh.unsub(topic);
125
80
  if (state.data.done && !state.data?.$error) {
@@ -133,7 +88,6 @@ class WorkflowHandleService {
133
88
  return await complete(null, error);
134
89
  }
135
90
  });
136
- //check state in case completed during wiring
137
91
  const status = await this.hotMesh.getStatus(this.workflowId);
138
92
  if (status <= 0) {
139
93
  await complete();
@@ -10,10 +10,6 @@ export declare const Durable: {
10
10
  Search: typeof Search;
11
11
  Worker: typeof WorkerService;
12
12
  workflow: typeof WorkflowService;
13
- /**
14
- * Shutdown everything. All connections, workers, and clients will be closed.
15
- * Include in your signal handlers to ensure a clean shutdown.
16
- */
17
13
  shutdown(): Promise<void>;
18
14
  };
19
15
  export type { ContextType };
@@ -13,10 +13,6 @@ exports.Durable = {
13
13
  Search: search_1.Search,
14
14
  Worker: worker_1.WorkerService,
15
15
  workflow: workflow_1.WorkflowService,
16
- /**
17
- * Shutdown everything. All connections, workers, and clients will be closed.
18
- * Include in your signal handlers to ensure a clean shutdown.
19
- */
20
16
  async shutdown() {
21
17
  await client_1.ClientService.shutdown();
22
18
  await worker_1.WorkerService.shutdown();
@@ -1,33 +1,4 @@
1
- /**
2
- *********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
3
- *
4
- * This HotMesh application spec uses 50 activities and 25 transitions
5
- * to model and emulate the Temporal Application & Query servers using
6
- * Redis as the backend.
7
- *
8
- * It's particularly useful for organizations with high-speed, high-volume
9
- * use cases as it uses in-memory Redis Streams for transactional,
10
- * workflow processing, while adhering to Temporal's developer-friendly syntax.
11
- *
12
- * This YAML file can also serve as a useful starting point for building
13
- * Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
14
- * for a physical application server.
15
- *
16
- * Possible use cases include:
17
- * * Orchestration servers
18
- * * Integration servers
19
- * * BPMN engines
20
- * * Reentrant process servers
21
- * * Service Meshes
22
- * * Master Data Management systems
23
- */
24
1
  declare const APP_VERSION = "1";
25
2
  declare const APP_ID = "durable";
26
- /**
27
- * returns a new durable workflow schema
28
- * @param {string} app - app name (e.g., 'durable')
29
- * @param {string} version - number as string (e.g., '1')
30
- * @returns {string} HotMesh App YAML
31
- */
32
3
  declare const getWorkflowYAML: (app: string, version: string) => string;
33
4
  export { getWorkflowYAML, APP_VERSION, APP_ID, };
@@ -1,39 +1,10 @@
1
1
  "use strict";
2
- /**
3
- *********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
4
- *
5
- * This HotMesh application spec uses 50 activities and 25 transitions
6
- * to model and emulate the Temporal Application & Query servers using
7
- * Redis as the backend.
8
- *
9
- * It's particularly useful for organizations with high-speed, high-volume
10
- * use cases as it uses in-memory Redis Streams for transactional,
11
- * workflow processing, while adhering to Temporal's developer-friendly syntax.
12
- *
13
- * This YAML file can also serve as a useful starting point for building
14
- * Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
15
- * for a physical application server.
16
- *
17
- * Possible use cases include:
18
- * * Orchestration servers
19
- * * Integration servers
20
- * * BPMN engines
21
- * * Reentrant process servers
22
- * * Service Meshes
23
- * * Master Data Management systems
24
- */
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
3
  exports.APP_ID = exports.APP_VERSION = exports.getWorkflowYAML = void 0;
27
4
  const APP_VERSION = '1';
28
5
  exports.APP_VERSION = APP_VERSION;
29
6
  const APP_ID = 'durable';
30
7
  exports.APP_ID = APP_ID;
31
- /**
32
- * returns a new durable workflow schema
33
- * @param {string} app - app name (e.g., 'durable')
34
- * @param {string} version - number as string (e.g., '1')
35
- * @returns {string} HotMesh App YAML
36
- */
37
8
  const getWorkflowYAML = (app, version) => {
38
9
  return `app:
39
10
  id: ${app}
@@ -8,51 +8,16 @@ export declare class Search {
8
8
  searchSessionIndex: number;
9
9
  hotMeshClient: HotMesh;
10
10
  store: StoreService<RedisClient, RedisMulti> | null;
11
+ cachedFields: Record<string, string>;
11
12
  constructor(workflowId: string, hotMeshClient: HotMesh, searchSessionId: string);
12
13
  safeKey(key: string): string;
13
- /**
14
- * For those deployments with a redis stack backend (with the FT module),
15
- * this method will configure the search index for the workflow. For all
16
- * others, this method will exit/fail gracefully and not index
17
- * the fields in the HASH. However, all values are still available
18
- * in the HASH.
19
- */
20
14
  static configureSearchIndex(hotMeshClient: HotMesh, search?: WorkflowSearchOptions): Promise<void>;
21
- /**
22
- * For those deployments with a redis stack backend (with the FT module),
23
- * this method will list all search indexes.
24
- * @param {HotMesh} hotMeshClient - the hotmesh client
25
- * @returns {Promise<string[]>} - the list of search indexes
26
- */
27
15
  static listSearchIndexes(hotMeshClient: HotMesh): Promise<string[]>;
28
- /**
29
- * increments the index to return a unique search session guid when
30
- * calling any method that produces side effects (changes the value)
31
- */
32
16
  getSearchSessionGuid(): string;
33
- /**
34
- * Sets the fields listed in args. Returns the
35
- * count of new fields that were set (does not
36
- * count fields that were updated)
37
- */
38
17
  set(...args: string[]): Promise<number>;
39
18
  get(key: string): Promise<string>;
40
19
  mget(...args: string[]): Promise<string[]>;
41
- /**
42
- * Deletes the fields listed in args. Returns the
43
- * count of fields that were deleted.
44
- */
45
20
  del(...args: string[]): Promise<number | void>;
46
- /**
47
- * Increments the value of a field by the given amount. Returns the
48
- * new value of the field after the increment. Can be
49
- * used to decrement the value of a field by specifying a negative.
50
- */
51
21
  incr(key: string, val: number): Promise<number>;
52
- /**
53
- * Multiplies the value of a field by the given amount. Returns the
54
- * new value of the field after the multiplication. NOTE:
55
- * this is exponential multiplication.
56
- */
57
22
  mult(key: string, val: number): Promise<number>;
58
23
  }
@@ -6,6 +6,7 @@ const storage_1 = require("../../modules/storage");
6
6
  class Search {
7
7
  constructor(workflowId, hotMeshClient, searchSessionId) {
8
8
  this.searchSessionIndex = 0;
9
+ this.cachedFields = {};
9
10
  const keyParams = {
10
11
  appId: hotMeshClient.appId,
11
12
  jobId: workflowId
@@ -16,25 +17,30 @@ class Search {
16
17
  this.store = hotMeshClient.engine.store;
17
18
  }
18
19
  safeKey(key) {
20
+ if (key.startsWith('"')) {
21
+ return key.slice(1, -1);
22
+ }
19
23
  return `_${key}`;
20
24
  }
21
- /**
22
- * For those deployments with a redis stack backend (with the FT module),
23
- * this method will configure the search index for the workflow. For all
24
- * others, this method will exit/fail gracefully and not index
25
- * the fields in the HASH. However, all values are still available
26
- * in the HASH.
27
- */
28
25
  static async configureSearchIndex(hotMeshClient, search) {
29
26
  if (search?.schema) {
30
27
  const store = hotMeshClient.engine.store;
31
28
  const schema = [];
32
29
  for (const [key, value] of Object.entries(search.schema)) {
33
- //prefix with a comma (avoids collisions with hotmesh reserved words)
34
- schema.push(`_${key}`);
35
- schema.push(value.type);
36
- if (value.sortable) {
37
- schema.push('SORTABLE');
30
+ if (value.indexed !== false) {
31
+ schema.push(value.fieldName ? `${value.fieldName.toString()}` : `_${key}`);
32
+ schema.push(value.type ? value.type : 'TEXT');
33
+ if (value.noindex) {
34
+ schema.push('NOINDEX');
35
+ }
36
+ else {
37
+ if (value.nostem && value.type === 'TEXT') {
38
+ schema.push('NOSTEM');
39
+ }
40
+ if (value.sortable) {
41
+ schema.push('SORTABLE');
42
+ }
43
+ }
38
44
  }
39
45
  }
40
46
  try {
@@ -51,12 +57,6 @@ class Search {
51
57
  }
52
58
  }
53
59
  }
54
- /**
55
- * For those deployments with a redis stack backend (with the FT module),
56
- * this method will list all search indexes.
57
- * @param {HotMesh} hotMeshClient - the hotmesh client
58
- * @returns {Promise<string[]>} - the list of search indexes
59
- */
60
60
  static async listSearchIndexes(hotMeshClient) {
61
61
  try {
62
62
  const store = hotMeshClient.engine.store;
@@ -68,40 +68,36 @@ class Search {
68
68
  return [];
69
69
  }
70
70
  }
71
- /**
72
- * increments the index to return a unique search session guid when
73
- * calling any method that produces side effects (changes the value)
74
- */
75
71
  getSearchSessionGuid() {
76
- //return the search session as it would exist in the search session index
77
72
  return `${this.searchSessionId}-${this.searchSessionIndex++}-`;
78
73
  }
79
- /**
80
- * Sets the fields listed in args. Returns the
81
- * count of new fields that were set (does not
82
- * count fields that were updated)
83
- */
84
74
  async set(...args) {
85
75
  const ssGuid = this.getSearchSessionGuid();
86
76
  const store = storage_1.asyncLocalStorage.getStore();
87
77
  const replay = store?.get('replay') ?? {};
88
- if (ssGuid in replay) {
89
- return Number(replay[ssGuid]);
90
- }
91
78
  const safeArgs = [];
92
79
  for (let i = 0; i < args.length; i += 2) {
93
- const key = this.safeKey(args[i]);
80
+ const keyName = args[i];
81
+ delete this.cachedFields[keyName];
82
+ const key = this.safeKey(keyName);
94
83
  const value = args[i + 1].toString();
95
84
  safeArgs.push(key, value);
96
85
  }
86
+ if (ssGuid in replay) {
87
+ return Number(replay[ssGuid]);
88
+ }
97
89
  const fieldCount = await this.store.exec('HSET', this.jobId, ...safeArgs);
98
- //no need to wait; set this interim value in the replay
99
90
  this.store.exec('HSET', this.jobId, ssGuid, fieldCount.toString());
100
91
  return Number(fieldCount);
101
92
  }
102
93
  async get(key) {
103
94
  try {
104
- return await this.store.exec('HGET', this.jobId, this.safeKey(key));
95
+ if (key in this.cachedFields) {
96
+ return this.cachedFields[key];
97
+ }
98
+ const value = await this.store.exec('HGET', this.jobId, this.safeKey(key));
99
+ this.cachedFields[key] = value;
100
+ return value;
105
101
  }
106
102
  catch (error) {
107
103
  this.hotMeshClient.logger.error('durable-search-get-error', { ...error });
@@ -109,45 +105,55 @@ class Search {
109
105
  }
110
106
  }
111
107
  async mget(...args) {
108
+ let isCached = true;
109
+ const values = [];
112
110
  const safeArgs = [];
113
111
  for (let i = 0; i < args.length; i++) {
112
+ if (isCached && args[i] in this.cachedFields) {
113
+ values.push(this.cachedFields[args[i]]);
114
+ }
115
+ else {
116
+ isCached = false;
117
+ }
114
118
  safeArgs.push(this.safeKey(args[i]));
115
119
  }
116
120
  try {
117
- return await this.store.exec('HMGET', this.jobId, ...safeArgs);
121
+ if (isCached) {
122
+ return values;
123
+ }
124
+ const returnValues = await this.store.exec('HMGET', this.jobId, ...safeArgs);
125
+ returnValues.forEach((value, index) => {
126
+ if (value !== null) {
127
+ this.cachedFields[args[index]] = value;
128
+ }
129
+ });
130
+ return returnValues;
118
131
  }
119
132
  catch (error) {
120
133
  this.hotMeshClient.logger.error('durable-search-mget-error', { ...error });
121
134
  return [];
122
135
  }
123
136
  }
124
- /**
125
- * Deletes the fields listed in args. Returns the
126
- * count of fields that were deleted.
127
- */
128
137
  async del(...args) {
129
138
  const ssGuid = this.getSearchSessionGuid();
130
139
  const store = storage_1.asyncLocalStorage.getStore();
131
140
  const replay = store?.get('replay') ?? {};
132
- if (ssGuid in replay) {
133
- return Number(replay[ssGuid]);
134
- }
135
141
  const safeArgs = [];
136
142
  for (let i = 0; i < args.length; i++) {
137
- safeArgs.push(this.safeKey(args[i]));
143
+ const keyName = args[i];
144
+ delete this.cachedFields[keyName];
145
+ safeArgs.push(this.safeKey(keyName));
146
+ }
147
+ if (ssGuid in replay) {
148
+ return Number(replay[ssGuid]);
138
149
  }
139
150
  const response = await this.store.exec('HDEL', this.jobId, ...safeArgs);
140
151
  const formattedResponse = isNaN(response) ? 0 : Number(response);
141
- //no need to wait; set this interim value in the replay
142
152
  this.store.exec('HSET', this.jobId, ssGuid, formattedResponse.toString());
143
153
  return formattedResponse;
144
154
  }
145
- /**
146
- * Increments the value of a field by the given amount. Returns the
147
- * new value of the field after the increment. Can be
148
- * used to decrement the value of a field by specifying a negative.
149
- */
150
155
  async incr(key, val) {
156
+ delete this.cachedFields[key];
151
157
  const ssGuid = this.getSearchSessionGuid();
152
158
  const store = storage_1.asyncLocalStorage.getStore();
153
159
  const replay = store?.get('replay') ?? {};
@@ -155,16 +161,11 @@ class Search {
155
161
  return Number(replay[ssGuid]);
156
162
  }
157
163
  const num = await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), val.toString());
158
- //no need to wait; set this interim value in the replay
159
164
  this.store.exec('HSET', this.jobId, ssGuid, num.toString());
160
165
  return Number(num);
161
166
  }
162
- /**
163
- * Multiplies the value of a field by the given amount. Returns the
164
- * new value of the field after the multiplication. NOTE:
165
- * this is exponential multiplication.
166
- */
167
167
  async mult(key, val) {
168
+ delete this.cachedFields[key];
168
169
  const ssGuid = this.getSearchSessionGuid();
169
170
  const store = storage_1.asyncLocalStorage.getStore();
170
171
  const replay = store?.get('replay') ?? {};
@@ -175,7 +176,6 @@ class Search {
175
176
  if (ssGuidValue === 1) {
176
177
  const log = Math.log(val);
177
178
  const logTotal = await this.store.exec('HINCRBYFLOAT', this.jobId, this.safeKey(key), log.toString());
178
- //no need to wait; set this interim value in the replay
179
179
  this.store.exec('HSET', this.jobId, ssGuid, logTotal.toString());
180
180
  return Math.exp(Number(logTotal));
181
181
  }