codehooks-js 1.3.2 → 1.3.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codehooks-js",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "type": "module",
5
5
  "description": "Codehooks.io official library - provides express.JS like syntax",
6
6
  "main": "index.js",
package/types/index.d.ts CHANGED
@@ -64,6 +64,10 @@ declare class Codehooks {
64
64
  crudlify: (schema?: {}, options?: {}) => Promise<import("./crudlify/lib/eventhooks.mjs").EventHooks>;
65
65
  createWorkflow: (name: any, description: any, steps: any, options?: {}) => {
66
66
  definitions: Map<any, any>;
67
+ configure(config: {
68
+ collectionName: string;
69
+ queuePrefix: string;
70
+ }): void;
67
71
  getDefinition(stepsName: string, stepName: string): Function;
68
72
  validateStepDefinition(step: Function): void;
69
73
  handleNextStep(stepsName: string, nextStep: string | null, newState: any, instanceId: string, options: any): Promise<string | string[]>;
@@ -30,6 +30,16 @@ declare class StepsEngine extends EventEmitter<[never]> {
30
30
  static getInstance(): StepsEngine;
31
31
  constructor();
32
32
  definitions: Map<any, any>;
33
+ /**
34
+ * Configure the steps engine
35
+ * @param {Object} config - Configuration object
36
+ * @param {string} config.collectionName - Collection name
37
+ * @param {string} config.queuePrefix - Queue prefix
38
+ */
39
+ configure(config: {
40
+ collectionName: string;
41
+ queuePrefix: string;
42
+ }): void;
33
43
  /**
34
44
  * Get the step definition for a specific step
35
45
  * @param {string} stepsName - Name of the steps workflow
@@ -2,6 +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
+ }) => void;
5
9
  export { Steps };
6
10
  export default StepsEngine;
7
11
  import { setCollectionName } from './engine.mjs';
@@ -20,8 +20,8 @@ class StepsEngine extends EventEmitter {
20
20
  static instance = null;
21
21
 
22
22
  // Configuration
23
- static collectionName = 'stepsdata';
24
- static queuePrefix = 'stepsqueue';
23
+ static collectionName = 'workflowdata';
24
+ static queuePrefix = 'workflowqueue';
25
25
 
26
26
  /**
27
27
  * Set the collection name for storing steps data
@@ -47,6 +47,21 @@ class StepsEngine extends EventEmitter {
47
47
  StepsEngine.queuePrefix = prefix.trim();
48
48
  }
49
49
 
50
+ /**
51
+ * Configure the steps engine
52
+ * @param {Object} config - Configuration object
53
+ * @param {string} config.collectionName - Collection name
54
+ * @param {string} config.queuePrefix - Queue prefix
55
+ */
56
+ configure(config) {
57
+ if (config.collectionName) {
58
+ StepsEngine.setCollectionName(config.collectionName);
59
+ }
60
+ if (config.queuePrefix) {
61
+ StepsEngine.setQueuePrefix(config.queuePrefix);
62
+ }
63
+ }
64
+
50
65
  /**
51
66
  * Get the singleton instance of StepsEngine
52
67
  * @returns {StepsEngine} The singleton instance
@@ -114,8 +129,6 @@ class StepsEngine extends EventEmitter {
114
129
  return results;
115
130
  }
116
131
 
117
- const isFinished = nextStep === null;
118
-
119
132
  // Handle single next step
120
133
  StepsEngine.getInstance().emit('stepStarted', { workflowName: stepsName, step: nextStep, state: newState, instanceId });
121
134
  const connection = await Datastore.open();
@@ -124,29 +137,20 @@ class StepsEngine extends EventEmitter {
124
137
  // Update the existing steps state in the database
125
138
  newState = await connection.updateOne(StepsEngine.collectionName,
126
139
  { _id: instanceId },
127
- { $set: { ...newState, nextStep: nextStep, updatedAt: new Date().toISOString(), isFinished: isFinished } });
140
+ { $set: { ...newState, nextStep: nextStep, updatedAt: new Date().toISOString() } });
128
141
 
129
142
  StepsEngine.getInstance().emit('stateUpdated', { workflowName: stepsName, state: newState, instanceId });
130
143
 
144
+
145
+
131
146
  // Get the next step function
132
147
  const func = StepsEngine.getInstance().getDefinition(stepsName, nextStep);
133
148
 
134
- // Check if the step is waiting for input
135
- if (options && options.waitForInput === true) {
136
- console.log('Steps workflow is paused, waiting for input for at step', nextStep);
137
- this.emit('stepWaiting', { workflowName: stepsName, step: nextStep, instanceId });
138
- return;
139
- }
140
-
141
149
  try {
142
150
  // Call the next step function with the step context
143
151
  func.call(this, {...newState, instanceId: newState._id}, async function (nextStep, userState, options) {
144
152
  try {
145
- if (nextStep === null) {
146
- console.log('No next step, steps workflow completed');
147
- StepsEngine.getInstance().emit('completed', { message: 'Steps workflow completed', ...userState });
148
- return;
149
- }
153
+
150
154
  // Protect system-level properties
151
155
  const protectedState = {
152
156
  _id: newState._id,
@@ -154,18 +158,32 @@ class StepsEngine extends EventEmitter {
154
158
  createdAt: newState.createdAt,
155
159
  updatedAt: newState.updatedAt,
156
160
  instanceId: newState.instanceId,
157
- isFinished: newState.isFinished
161
+ workflowName: newState.workflowName
158
162
  };
159
163
 
160
164
  // Merge states with userState taking precedence, but protecting system fields
161
165
  const mergedState = {
162
- ...newState,
166
+ //...newState,
163
167
  ...userState,
164
168
  ...protectedState
165
169
  };
166
170
 
171
+ // If there is no next step, the workflow is completed
172
+ if (nextStep === null) {
173
+ delete mergedState._id;
174
+ const completionTime = (new Date(mergedState.updatedAt) - new Date(mergedState.createdAt)) / 1000;
175
+ console.log(`Workflow ${stepsName} ${instanceId} is completed in time: ${completionTime}s 🎉`);
176
+ const db = await Datastore.open();
177
+ await db.updateOne(StepsEngine.collectionName,
178
+ { _id: instanceId },
179
+ { $set: { ...mergedState, nextStep: null, updatedAt: new Date().toISOString() } });
180
+ StepsEngine.getInstance().emit('completed', { message: 'Steps workflow completed', ...userState });
181
+ return;
182
+ }
183
+
167
184
  // Enqueue the next step
168
- const qres = connection.enqueue(`${StepsEngine.queuePrefix}`, {
185
+ //console.log('enqueuing step', `${StepsEngine.queuePrefix}_${stepsName}_${nextStep}`);
186
+ connection.enqueue(`${StepsEngine.queuePrefix}_${stepsName}_${nextStep}`, {
169
187
  stepsName: stepsName,
170
188
  goto: nextStep,
171
189
  state: mergedState,
@@ -180,7 +198,7 @@ class StepsEngine extends EventEmitter {
180
198
  }
181
199
  });
182
200
  } catch (error) {
183
- console.error('Error in step function:', error.message);
201
+ console.error('Error in step function: '+nextStep, error.message);
184
202
  const connection = await Datastore.open();
185
203
  await connection.updateOne(StepsEngine.collectionName,
186
204
  { _id: instanceId },
@@ -208,13 +226,14 @@ class StepsEngine extends EventEmitter {
208
226
  // Validate each step in the definition
209
227
  for (const [stepName, step] of Object.entries(definition)) {
210
228
  try {
211
- if (stepName !== null) {
212
- app.worker(`${StepsEngine.queuePrefix}`, async (req, res) => {
229
+ if (stepName !== undefined) {
230
+ //console.log('registering queue for step', `${StepsEngine.queuePrefix}_${name}_${stepName}`);
231
+ app.worker(`${StepsEngine.queuePrefix}_${name}_${stepName}`, async (req, res) => {
213
232
  const { stepsName, goto, state, instanceId, options } = req.body.payload;
214
233
  try {
215
234
  const qid = await StepsEngine.getInstance().handleNextStep(stepsName, goto, state, instanceId, options);
216
235
  } catch (error) {
217
- console.error('Error in step function:', error.message);
236
+ console.error('Error in step function: ' + stepName, error.message);
218
237
  } finally {
219
238
  res.end();
220
239
  }
@@ -252,8 +271,8 @@ class StepsEngine extends EventEmitter {
252
271
  const connection = await Datastore.open();
253
272
  // Create a new steps state in the database
254
273
  const newState = await connection.insertOne(StepsEngine.collectionName,
255
- { ...initialState, nextStep: firstStepName, createdAt: new Date().toISOString() });
256
- const { _id: ID } = await connection.enqueue(`${StepsEngine.queuePrefix}`, {
274
+ { ...initialState, nextStep: firstStepName, createdAt: new Date().toISOString(), workflowName: name });
275
+ const { _id: ID } = await connection.enqueue(`${StepsEngine.queuePrefix}_${name}_${firstStepName}`, {
257
276
  stepsName: name,
258
277
  goto: firstStepName,
259
278
  state: newState,
@@ -319,7 +338,7 @@ class StepsEngine extends EventEmitter {
319
338
  StepsEngine.getInstance().emit('workflowContinued', { stepsName, step: state.nextStep, instanceId });
320
339
 
321
340
  return new Promise(async (resolve, reject) => {
322
- const { _id: ID } = await connection.enqueue(`${StepsEngine.queuePrefix}`, {
341
+ const { _id: ID } = await connection.enqueue(`${StepsEngine.queuePrefix}_${stepsName}_${state.nextStep}`, {
323
342
  stepsName,
324
343
  goto: state.nextStep,
325
344
  state: state,
@@ -6,6 +6,9 @@ export const StepsConfig = {
6
6
  setQueuePrefix
7
7
  };
8
8
 
9
+ // Re-export the configure method
10
+ export const configure = StepsEngine.configure;
11
+
9
12
  // Re-export the workflow instance
10
13
  export { Steps };
11
14