codehooks-js 1.3.6 → 1.3.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.
@@ -1,2 +1,3 @@
1
- export function serveStatic(options: any, app: any, filestore: any, hook: any, fsoptions: any): void;
1
+ export function serveStatic(options: any, app: any, filestore: any): void;
2
2
  export function render(viewFile: any, data: any, settings: any, cb: any): Promise<any>;
3
+ //# sourceMappingURL=webserver.d.mts.map
@@ -7,12 +7,10 @@ export default _default;
7
7
  * StepsEngine class that manages step-based workflows
8
8
  * @extends EventEmitter
9
9
  */
10
- declare class StepsEngine extends EventEmitter<[never]> {
10
+ declare class StepsEngine {
11
11
  static instance: any;
12
12
  static collectionName: string;
13
13
  static queuePrefix: string;
14
- static timeout: number;
15
- static maxStepCount: number;
16
14
  /**
17
15
  * Set the collection name for storing steps data
18
16
  * @param {string} name - Collection name
@@ -25,37 +23,12 @@ declare class StepsEngine extends EventEmitter<[never]> {
25
23
  * @throws {Error} If prefix is not a non-empty string
26
24
  */
27
25
  static setQueuePrefix(prefix: string): void;
28
- /**
29
- * Set the timeout for steps jobs
30
- * @param {number} timeout - Timeout in milliseconds
31
- * @throws {Error} If timeout is not a positive number
32
- */
33
- static setTimeout(timeout: number): void;
34
- /**
35
- * Set the maximum step count for a steps workflow
36
- * @param {number} maxStepCount - Maximum step count
37
- * @throws {Error} If maxStepCount is not a positive number
38
- */
39
- static setMaxStepCount(maxStepCount: number): void;
40
26
  /**
41
27
  * Get the singleton instance of StepsEngine
42
28
  * @returns {StepsEngine} The singleton instance
43
29
  */
44
30
  static getInstance(): StepsEngine;
45
- constructor();
46
- definitions: Map<any, any>;
47
- /**
48
- * Configure the steps engine
49
- * @param {Object} config - Configuration object
50
- * @param {string} config.collectionName - Collection name
51
- * @param {string} config.queuePrefix - Queue prefix
52
- * @param {number} config.timeout - Timeout in milliseconds
53
- */
54
- configure(config: {
55
- collectionName: string;
56
- queuePrefix: string;
57
- timeout: number;
58
- }): void;
31
+ definitions: any;
59
32
  /**
60
33
  * Get the step definition for a specific step
61
34
  * @param {string} stepsName - Name of the steps workflow
@@ -106,10 +79,9 @@ declare class StepsEngine extends EventEmitter<[never]> {
106
79
  * @param {string} stepsName - Name of the steps workflow
107
80
  * @param {string} instanceId - ID of the steps instance
108
81
  * @param {Object} state - New state to update with
109
- * @param {Object} options - Options for the update, { continue: false } to avoid continuing the the step
110
82
  * @returns {Promise<Object>} The updated state
111
83
  */
112
- updateState(stepsName: string, instanceId: string, state: any, options?: any): Promise<any>;
84
+ updateState(stepsName: string, instanceId: string, state: any): Promise<any>;
113
85
  /**
114
86
  * Set the complete state of a steps instance
115
87
  * @param {string} instanceId - ID of the steps instance
@@ -127,13 +99,6 @@ declare class StepsEngine extends EventEmitter<[never]> {
127
99
  continue(stepsName: string, instanceId: string): Promise<{
128
100
  qId: string;
129
101
  }>;
130
- /**
131
- * Continue all timed out steps instances
132
- * @returns {Promise<Array<{qId: string}>>} Array of results containing queue IDs for continued workflows
133
- */
134
- continueAllTimedOut(): Promise<Array<{
135
- qId: string;
136
- }>>;
137
102
  /**
138
103
  * Get the status of a steps instance
139
104
  * @param {string} id - ID of the steps instance
@@ -145,7 +110,7 @@ declare class StepsEngine extends EventEmitter<[never]> {
145
110
  * @param {Object} filter - Filter criteria for steps workflows
146
111
  * @returns {Promise<Array>} List of steps instances
147
112
  */
148
- getInstances(filter: any): Promise<any[]>;
113
+ listSteps(filter: any): Promise<any[]>;
149
114
  /**
150
115
  * Cancel a steps instance
151
116
  * @param {string} id - ID of the steps instance to cancel
@@ -153,4 +118,4 @@ declare class StepsEngine extends EventEmitter<[never]> {
153
118
  */
154
119
  cancelSteps(id: string): Promise<any>;
155
120
  }
156
- import { EventEmitter } from 'events';
121
+ //# sourceMappingURL=engine.d.mts.map
@@ -2,14 +2,10 @@ export namespace StepsConfig {
2
2
  export { setCollectionName };
3
3
  export { setQueuePrefix };
4
4
  }
5
- export const configure: (config: {
6
- collectionName: string;
7
- queuePrefix: string;
8
- timeout: number;
9
- }) => void;
10
5
  export { Steps };
11
6
  export default StepsEngine;
12
7
  import { setCollectionName } from './engine.mjs';
13
8
  import { setQueuePrefix } from './engine.mjs';
14
9
  import { Steps } from './engine.mjs';
15
10
  import StepsEngine from './engine.mjs';
11
+ //# sourceMappingURL=index.d.mts.map
@@ -151,43 +151,37 @@ class StepsEngine extends EventEmitter {
151
151
  * @throws {Error} If step execution fails
152
152
  */
153
153
  async handleNextStep(stepsName, nextStep, newState, instanceId, options) {
154
+
155
+ // open the connection to the database
156
+ const connection = await Datastore.open();
157
+
158
+ // Handle single next step
159
+ StepsEngine.getInstance().emit('stepStarted', { workflowName: stepsName, step: nextStep, state: newState, instanceId });
160
+
161
+ // remove the _id from the newState
162
+ delete newState._id;
163
+ // increment the step count
164
+ newState.stepCount[nextStep] = (newState.stepCount[nextStep] || 0) + 1;
165
+ // Update the existing steps state in the database
166
+ newState = await connection.updateOne(StepsEngine.collectionName,
167
+ { _id: instanceId },
168
+ { $set: { ...newState, nextStep: nextStep, updatedAt: new Date().toISOString(), stepCount: newState.stepCount } });
169
+
170
+ StepsEngine.getInstance().emit('stateUpdated', { workflowName: stepsName, state: newState, instanceId });
171
+
154
172
  try {
155
- // Handle array of next steps
156
- if (Array.isArray(nextStep)) {
157
- const results = [];
158
- for (const step of nextStep) {
159
- const qid = await this.handleNextStep(stepsName, step, newState, instanceId, options);
160
- results.push(qid);
173
+ // Get the next step function
174
+ const func = StepsEngine.getInstance().getDefinition(stepsName, nextStep);
175
+
176
+ // Wrap the callback in a Promise to ensure proper async handling
177
+ await new Promise(async (resolve, reject) => {
178
+ // check if the step count is greater than the max step count
179
+ if (newState.stepCount[nextStep] > StepsEngine.maxStepCount) {
180
+ reject(new Error(`Step ${nextStep} has been executed ${newState.stepCount[nextStep]} times, which is greater than the maximum step count of ${StepsEngine.maxStepCount}`));
181
+ return;
161
182
  }
162
- return results;
163
- }
164
-
165
- // Handle single next step
166
- StepsEngine.getInstance().emit('stepStarted', { workflowName: stepsName, step: nextStep, state: newState, instanceId });
167
- const connection = await Datastore.open();
168
- // remove the _id from the newState
169
- delete newState._id;
170
- // increment the step count
171
- newState.stepCount[nextStep] = (newState.stepCount[nextStep] || 0) + 1;
172
- // Update the existing steps state in the database
173
- newState = await connection.updateOne(StepsEngine.collectionName,
174
- { _id: instanceId },
175
- { $set: { ...newState, nextStep: nextStep, updatedAt: new Date().toISOString(), stepCount: newState.stepCount } });
176
-
177
- StepsEngine.getInstance().emit('stateUpdated', { workflowName: stepsName, state: newState, instanceId });
178
-
179
- try {
180
- // Get the next step function
181
- const func = StepsEngine.getInstance().getDefinition(stepsName, nextStep);
182
-
183
- // Wrap the callback in a Promise to ensure proper async handling
184
- await new Promise((resolve, reject) => {
185
- // check if the step count is greater than the max step count
186
- if (newState.stepCount[nextStep] > StepsEngine.maxStepCount) {
187
- reject(new Error(`Step ${nextStep} has been executed ${newState.stepCount[nextStep]} times, which is greater than the maximum step count of ${StepsEngine.maxStepCount}`));
188
- return;
189
- }
190
- func({...newState, instanceId: newState._id}, async (nextStep, userState, options) => {
183
+ try {
184
+ await func({...newState, instanceId: newState._id}, async (nextStep, userState, options) => {
191
185
  try {
192
186
  // Protect system-level properties
193
187
  const protectedState = {
@@ -197,7 +191,9 @@ class StepsEngine extends EventEmitter {
197
191
  updatedAt: newState.updatedAt,
198
192
  instanceId: newState.instanceId,
199
193
  workflowName: newState.workflowName,
200
- stepCount: newState.stepCount
194
+ stepCount: newState.stepCount,
195
+ parallelSteps: newState.parallelSteps,
196
+ previousStep: newState.nextStep
201
197
  };
202
198
 
203
199
  // Merge states with userState taking precedence, but protecting system fields
@@ -206,6 +202,38 @@ class StepsEngine extends EventEmitter {
206
202
  ...protectedState
207
203
  };
208
204
 
205
+ // update the parallel steps metadata
206
+ if (mergedState.parallelSteps && mergedState.parallelSteps[mergedState.nextStep]) {
207
+ // get a fresh copy of the parallel steps
208
+ const fresh = await connection.findOne(StepsEngine.collectionName, { _id: instanceId });
209
+ fresh.parallelSteps[mergedState.nextStep].done = true;
210
+ fresh.parallelSteps[mergedState.nextStep].nextStep = nextStep;
211
+ //fresh.parallelSteps[mergedState.nextStep].previousStep = mergedState.previousStep || null;
212
+ delete fresh._id;
213
+ const updated = await connection.updateOne(StepsEngine.collectionName,
214
+ { _id: instanceId },
215
+ { $set: { ...fresh, parallelSteps: fresh.parallelSteps } });
216
+ //console.debug('updated', updated.parallelSteps);
217
+ mergedState.parallelSteps = fresh.parallelSteps;
218
+ // Check if all parallel steps are done
219
+ const allStepsDone = Object.values(fresh.parallelSteps).every(step => step.done);
220
+ if (!allStepsDone) {
221
+ console.debug('Waiting for other parallel steps to complete');
222
+ resolve();
223
+ return;
224
+ } else {
225
+ // validate that all parallel steps have the same next step
226
+ const nextSteps = Object.values(fresh.parallelSteps).map(step => step.nextStep);
227
+ const uniqueNextSteps = [...new Set(nextSteps)];
228
+ if (uniqueNextSteps.length > 1) {
229
+ throw new Error('Parallel steps must join to the same next step');
230
+ }
231
+ // reset the parallel steps
232
+ mergedState.parallelSteps = {};
233
+ console.debug('All parallel steps are done');
234
+ }
235
+ }
236
+
209
237
  // If there is no next step, the workflow is completed
210
238
  if (nextStep === null) {
211
239
  delete mergedState._id;
@@ -220,16 +248,38 @@ class StepsEngine extends EventEmitter {
220
248
  return;
221
249
  }
222
250
 
223
- // Enqueue the next step
224
- console.debug('enqueuing step', nextStep, instanceId);
225
- await connection.enqueue(`${StepsEngine.queuePrefix}_${stepsName}_${nextStep}`, {
251
+ // Enqueue the next step, single or parallel
252
+ if (Array.isArray(nextStep)) {
253
+ const now = new Date().toISOString();
254
+ const metadata = nextStep.reduce((acc, step) => {
255
+ acc[step] = { done: false, startTime: now, previousStep: mergedState.previousStep };
256
+ return acc;
257
+ }, {});
258
+ const metadataDoc = await connection.updateOne(StepsEngine.collectionName,
259
+ { _id: instanceId },
260
+ { $set: { parallelSteps: metadata } });
261
+ //console.log('metadataDoc', metadataDoc);
262
+ // enqueue all steps in parallel
263
+ for (const step of nextStep) {
264
+ console.debug('enqueue step', step, instanceId);
265
+ await connection.enqueue(`${StepsEngine.queuePrefix}_${stepsName}_${step}`, {
266
+ stepsName: stepsName,
267
+ goto: step,
268
+ state: mergedState,
269
+ options: options,
270
+ instanceId: instanceId
271
+ });
272
+ }
273
+ } else {
274
+ console.debug('enqueue step', nextStep, instanceId);
275
+ await connection.enqueue(`${StepsEngine.queuePrefix}_${stepsName}_${nextStep}`, {
226
276
  stepsName: stepsName,
227
277
  goto: nextStep,
228
278
  state: mergedState,
229
279
  options: options,
230
280
  instanceId: instanceId
231
281
  });
232
-
282
+ }
233
283
  StepsEngine.getInstance().emit('stepEnqueued', { workflowName: stepsName, step: nextStep, state: newState, instanceId });
234
284
  resolve();
235
285
  } catch (error) {
@@ -237,14 +287,15 @@ class StepsEngine extends EventEmitter {
237
287
  reject(error);
238
288
  }
239
289
  });
240
- });
241
- } catch (error) {
242
- throw error;
243
- }
244
- }
245
- catch (error) {
290
+ } catch (error) {
291
+ console.error('Error executing step function:', error);
292
+ reject(error);
293
+ }
294
+ });
295
+ } catch (error) {
296
+ console.error('error in handleNextStep outer', error.message);
246
297
  throw error;
247
- }
298
+ }
248
299
  }
249
300
 
250
301
  /**
@@ -267,7 +318,7 @@ class StepsEngine extends EventEmitter {
267
318
  app.worker(`${StepsEngine.queuePrefix}_${name}_${stepName}`, async function(req, res) {
268
319
  try {
269
320
  const { stepsName, goto, state, instanceId, options } = req.body.payload;
270
- console.debug('worker job', stepName, instanceId);
321
+ console.debug('dequeue step', stepName, instanceId);
271
322
  const qid = await StepsEngine.getInstance().handleNextStep(stepsName, goto, state, instanceId, options);
272
323
  } catch (error) {
273
324
  const { stepsName, goto, state, instanceId, options } = req.body.payload;
@@ -393,7 +444,7 @@ class StepsEngine extends EventEmitter {
393
444
  instanceId: instanceId
394
445
  });
395
446
 
396
- resolve({ qId: ID });
447
+ resolve({ instanceId });
397
448
  });
398
449
  }
399
450