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.
- package/package.json +2 -4
- package/types/aggregation/index.d.mts +38 -1
- package/types/crudlify/index.d.mts +9 -5
- package/types/crudlify/lib/eventhooks.d.mts +1 -0
- package/types/crudlify/lib/query/q2m/index.d.mts +7 -0
- package/types/crudlify/lib/query/q2m/q2m.d.mts +1 -0
- package/types/crudlify/lib/schema/json-schema/index.d.mts +1 -0
- package/types/crudlify/lib/schema/yup/index.d.mts +2 -1
- package/types/crudlify/lib/schema/zod/index.d.mts +1 -0
- package/types/index.d.ts +1254 -126
- package/types/webserver.d.mts +2 -1
- package/types/workflow/engine.d.mts +5 -40
- package/types/workflow/index.d.mts +1 -5
- package/workflow/engine.mjs +100 -49
package/types/webserver.d.mts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export function serveStatic(options: any, app: any, filestore: any
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/workflow/engine.mjs
CHANGED
|
@@ -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
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
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
|
-
|
|
242
|
-
|
|
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('
|
|
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({
|
|
447
|
+
resolve({ instanceId });
|
|
397
448
|
});
|
|
398
449
|
}
|
|
399
450
|
|