@webda/workflow 0.0.0-stage → 4.0.0-beta.14

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 (48) hide show
  1. package/LICENSE +166 -0
  2. package/README.md +54 -2
  3. package/lib/authoring.d.ts +115 -0
  4. package/lib/authoring.d.ts.map +1 -0
  5. package/lib/authoring.js +107 -0
  6. package/lib/authoring.js.map +1 -0
  7. package/lib/expression.d.ts +21 -0
  8. package/lib/expression.d.ts.map +1 -0
  9. package/lib/expression.js +196 -0
  10. package/lib/expression.js.map +1 -0
  11. package/lib/graph.d.ts +429 -0
  12. package/lib/graph.d.ts.map +1 -0
  13. package/lib/graph.js +72 -0
  14. package/lib/graph.js.map +1 -0
  15. package/lib/hooks.d.ts +38 -0
  16. package/lib/hooks.d.ts.map +1 -0
  17. package/lib/hooks.js +23 -0
  18. package/lib/hooks.js.map +1 -0
  19. package/lib/index.d.ts +11 -0
  20. package/lib/index.d.ts.map +1 -0
  21. package/lib/index.js +15 -0
  22. package/lib/index.js.map +1 -0
  23. package/lib/interpreter.d.ts +69 -0
  24. package/lib/interpreter.d.ts.map +1 -0
  25. package/lib/interpreter.js +332 -0
  26. package/lib/interpreter.js.map +1 -0
  27. package/lib/models/workflow.model.d.ts +71 -0
  28. package/lib/models/workflow.model.d.ts.map +1 -0
  29. package/lib/models/workflow.model.js +70 -0
  30. package/lib/models/workflow.model.js.map +1 -0
  31. package/lib/models/workflowinstance.model.d.ts +132 -0
  32. package/lib/models/workflowinstance.model.d.ts.map +1 -0
  33. package/lib/models/workflowinstance.model.js +168 -0
  34. package/lib/models/workflowinstance.model.js.map +1 -0
  35. package/lib/models/workflowsignal.model.d.ts +51 -0
  36. package/lib/models/workflowsignal.model.d.ts.map +1 -0
  37. package/lib/models/workflowsignal.model.js +53 -0
  38. package/lib/models/workflowsignal.model.js.map +1 -0
  39. package/lib/models/workflowtask.model.d.ts +103 -0
  40. package/lib/models/workflowtask.model.d.ts.map +1 -0
  41. package/lib/models/workflowtask.model.js +104 -0
  42. package/lib/models/workflowtask.model.js.map +1 -0
  43. package/lib/workflow.service.d.ts +685 -0
  44. package/lib/workflow.service.d.ts.map +1 -0
  45. package/lib/workflow.service.js +1951 -0
  46. package/lib/workflow.service.js.map +1 -0
  47. package/package.json +68 -3
  48. package/webda.module.json +2688 -0
@@ -0,0 +1,69 @@
1
+ import type { FlowDefinition, FlowError, Journal, TaskOptions } from "./graph.js";
2
+ /**
3
+ * Maximum number of iterations of a `while`
4
+ */
5
+ export declare const MAX_LOOP_ITERATIONS = 10000;
6
+ /**
7
+ * A task the engine has to run: the next missing outcome of the journal
8
+ */
9
+ export interface ScheduledTask {
10
+ /**
11
+ * Task key: `<statement id>@<iteration path>`
12
+ */
13
+ key: string;
14
+ /**
15
+ * Operation
16
+ */
17
+ operation: string;
18
+ /**
19
+ * Input
20
+ */
21
+ input: any;
22
+ /**
23
+ * Flow defaults merged with the task options
24
+ */
25
+ options: TaskOptions;
26
+ }
27
+ /**
28
+ * Result of a replay
29
+ */
30
+ export type RunResult = {
31
+ status: "done";
32
+ output: any;
33
+ } | {
34
+ status: "error";
35
+ error: FlowError;
36
+ } | {
37
+ status: "pending";
38
+ schedule: ScheduledTask[];
39
+ };
40
+ /**
41
+ * Task key of a statement at an iteration path
42
+ * @param id - the statement id
43
+ * @param path - indexes of the enclosing loops and branches
44
+ * @returns the key
45
+ */
46
+ export declare function taskKey(id: string, path: number[]): string;
47
+ /**
48
+ * Statement id of a task key
49
+ * @param key - the task key
50
+ * @returns the statement id
51
+ */
52
+ export declare function statementIdOf(key: string): string;
53
+ /**
54
+ * Replay a flow against its journal
55
+ *
56
+ * Pure: no I/O, the same arguments always give the same result.
57
+ * @param def - the flow definition
58
+ * @param input - the flow input, by parameter name
59
+ * @param journal - outcomes of the finished tasks
60
+ * @returns done with the output, error with the uncaught error, or pending with the tasks to run
61
+ */
62
+ export declare function run(def: FlowDefinition, input: Record<string, any>, journal: Journal): RunResult;
63
+ /**
64
+ * Statement ids of a definition, nested ones included
65
+ * @param def - the flow definition
66
+ * @returns the ids
67
+ */
68
+ export declare function keysOf(def: Pick<FlowDefinition, "body">): Set<string>;
69
+ //# sourceMappingURL=interpreter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter.d.ts","sources":["../src/interpreter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAQ,cAAc,EAAE,SAAS,EAAE,OAAO,EAAQ,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9F;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,KAAK,EAAE,GAAG,CAAC;IACX;;OAEG;IACH,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC;AAoBrD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAoQD;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,CAchG;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAgBrE"}
@@ -0,0 +1,332 @@
1
+ import { evaluate } from "./expression.js";
2
+ /**
3
+ * Maximum number of iterations of a `while`
4
+ */
5
+ export const MAX_LOOP_ITERATIONS = 10000;
6
+ /**
7
+ * An error thrown inside the flow, catchable by a `try`
8
+ */
9
+ class FlowThrow {
10
+ error;
11
+ /**
12
+ * Create a new FlowThrow instance
13
+ * @param error - the flow error
14
+ */
15
+ constructor(error) {
16
+ this.error = error;
17
+ }
18
+ }
19
+ const NORMAL = { type: "normal" };
20
+ /**
21
+ * Task key of a statement at an iteration path
22
+ * @param id - the statement id
23
+ * @param path - indexes of the enclosing loops and branches
24
+ * @returns the key
25
+ */
26
+ export function taskKey(id, path) {
27
+ return `${id}@${path.join(".")}`;
28
+ }
29
+ /**
30
+ * Statement id of a task key
31
+ * @param key - the task key
32
+ * @returns the statement id
33
+ */
34
+ export function statementIdOf(key) {
35
+ return key.substring(0, key.lastIndexOf("@"));
36
+ }
37
+ /**
38
+ * Replay of one flow against its journal
39
+ */
40
+ class Replay {
41
+ def;
42
+ journal;
43
+ /**
44
+ * Create a new Replay instance
45
+ * @param def - the flow
46
+ * @param journal - finished task outcomes
47
+ */
48
+ constructor(def, journal) {
49
+ this.def = def;
50
+ this.journal = journal;
51
+ }
52
+ /**
53
+ * Throw a flow error
54
+ * @param code - error code
55
+ * @param message - error message
56
+ * @returns never
57
+ */
58
+ fail(code, message) {
59
+ throw new FlowThrow({ code, message, operation: this.def.id });
60
+ }
61
+ /**
62
+ * Evaluate an expression, an invalid one throws in the flow
63
+ * @param expr - the expression
64
+ * @param scope - the variables
65
+ * @returns the value
66
+ */
67
+ value(expr, scope) {
68
+ try {
69
+ return evaluate(expr, scope);
70
+ }
71
+ catch (err) {
72
+ return this.fail("ExpressionError", err.message);
73
+ }
74
+ }
75
+ /**
76
+ * Run a block of statements in order, stopping at the first one that does not complete normally
77
+ * @param stmts - the statements
78
+ * @param scope - the variables
79
+ * @param path - the iteration path
80
+ * @returns the completion
81
+ */
82
+ block(stmts, scope, path) {
83
+ for (const stmt of stmts ?? []) {
84
+ const res = this.stmt(stmt, scope, path);
85
+ if (res.type !== "normal") {
86
+ return res;
87
+ }
88
+ }
89
+ return NORMAL;
90
+ }
91
+ /**
92
+ * Run one statement
93
+ * @param stmt - the statement
94
+ * @param scope - the variables
95
+ * @param path - the iteration path
96
+ * @returns the completion
97
+ */
98
+ stmt(stmt, scope, path) {
99
+ switch (stmt.kind) {
100
+ case "task":
101
+ return this.task(stmt, scope, path);
102
+ case "assign":
103
+ scope[stmt.name] = this.value(stmt.value, scope);
104
+ return NORMAL;
105
+ case "if":
106
+ return this.block(this.value(stmt.cond, scope) ? stmt.then : stmt.else, scope, path);
107
+ case "forOf": {
108
+ const items = this.value(stmt.items, scope);
109
+ if (!Array.isArray(items)) {
110
+ this.fail("TypeError", `${stmt.id}: items is not an array`);
111
+ }
112
+ for (let i = 0; i < items.length; i++) {
113
+ scope[stmt.item] = items[i];
114
+ const res = this.block(stmt.body, scope, [...path, i]);
115
+ if (res.type !== "normal") {
116
+ return res;
117
+ }
118
+ }
119
+ return NORMAL;
120
+ }
121
+ case "while":
122
+ for (let i = 0; this.value(stmt.cond, scope); i++) {
123
+ if (i >= MAX_LOOP_ITERATIONS) {
124
+ this.fail("LoopLimit", `${stmt.id}: more than ${MAX_LOOP_ITERATIONS} iterations`);
125
+ }
126
+ const res = this.block(stmt.body, scope, [...path, i]);
127
+ if (res.type !== "normal") {
128
+ return res;
129
+ }
130
+ }
131
+ return NORMAL;
132
+ case "try":
133
+ return this.try(stmt, scope, path);
134
+ case "parallel":
135
+ return this.concurrent(stmt.branches.map((branch, i) => ({ body: branch, scope: structuredClone(scope), path: [...path, i] })), Infinity, scope, stmt.assign);
136
+ case "map": {
137
+ const items = this.value(stmt.items, scope);
138
+ if (!Array.isArray(items)) {
139
+ this.fail("TypeError", `${stmt.id}: items is not an array`);
140
+ }
141
+ return this.concurrent(items.map((item, i) => ({
142
+ body: stmt.body,
143
+ scope: { ...structuredClone(scope), [stmt.item]: structuredClone(item) },
144
+ path: [...path, i]
145
+ })), stmt.concurrency && stmt.concurrency > 0 ? stmt.concurrency : Infinity, scope, stmt.assign);
146
+ }
147
+ case "return":
148
+ return { type: "return", value: stmt.value === undefined ? undefined : this.value(stmt.value, scope) };
149
+ case "throw": {
150
+ const value = this.value(stmt.value, scope);
151
+ if (value && typeof value.code === "string" && typeof value.message === "string") {
152
+ // A caught FlowError rethrown
153
+ throw new FlowThrow({ code: value.code, message: value.message, operation: String(value.operation ?? "") });
154
+ }
155
+ return this.fail("FlowError", typeof value === "string" ? value : JSON.stringify(value));
156
+ }
157
+ }
158
+ return this.fail("InvalidStatement", `Unknown statement kind ${stmt?.kind}`);
159
+ }
160
+ /**
161
+ * A task: its outcome from the journal, or schedule it
162
+ * @param stmt - the task statement
163
+ * @param scope - the variables
164
+ * @param path - the iteration path
165
+ * @returns the completion
166
+ */
167
+ task(stmt, scope, path) {
168
+ const key = taskKey(stmt.id, path);
169
+ const outcome = this.journal[key];
170
+ if (outcome === undefined) {
171
+ return {
172
+ type: "pending",
173
+ schedule: [
174
+ {
175
+ key,
176
+ operation: stmt.operation,
177
+ input: this.value(stmt.input, scope),
178
+ options: { ...this.def.options, ...stmt.options }
179
+ }
180
+ ]
181
+ };
182
+ }
183
+ if ("error" in outcome) {
184
+ throw new FlowThrow(outcome.error);
185
+ }
186
+ if (stmt.assign) {
187
+ scope[stmt.assign] = structuredClone(outcome.result);
188
+ }
189
+ return NORMAL;
190
+ }
191
+ /**
192
+ * try/catch/finally: finally runs after the body or the catch, then their completion goes on
193
+ * @param stmt - the try statement
194
+ * @param scope - the variables
195
+ * @param path - the iteration path
196
+ * @returns the completion
197
+ */
198
+ try(stmt, scope, path) {
199
+ let res = NORMAL;
200
+ let thrown;
201
+ try {
202
+ res = this.block(stmt.body, scope, path);
203
+ }
204
+ catch (err) {
205
+ if (!(err instanceof FlowThrow))
206
+ throw err;
207
+ if (stmt.catch) {
208
+ if (stmt.catchVar) {
209
+ scope[stmt.catchVar] = structuredClone(err.error);
210
+ }
211
+ try {
212
+ res = this.block(stmt.catch, scope, path);
213
+ }
214
+ catch (err2) {
215
+ if (!(err2 instanceof FlowThrow))
216
+ throw err2;
217
+ thrown = err2;
218
+ }
219
+ }
220
+ else {
221
+ thrown = err;
222
+ }
223
+ }
224
+ if (res?.type === "pending") {
225
+ return res;
226
+ }
227
+ const fin = this.block(stmt.finally, scope, path);
228
+ if (fin.type !== "normal") {
229
+ return fin;
230
+ }
231
+ if (thrown) {
232
+ throw thrown;
233
+ }
234
+ return res;
235
+ }
236
+ /**
237
+ * Run branches concurrently: each one on its own copy of the variables, at most `concurrency` unfinished
238
+ * @param branches - the bodies with their scope and path
239
+ * @param concurrency - maximum number of unfinished branches
240
+ * @param scope - the parent variables
241
+ * @param assign - variable receiving the return values
242
+ * @returns the completion
243
+ */
244
+ concurrent(branches, concurrency, scope, assign) {
245
+ const values = [];
246
+ const schedule = [];
247
+ let running = 0;
248
+ let error;
249
+ for (const branch of branches) {
250
+ if (running >= concurrency) {
251
+ // A later branch cannot start before one of the running ones finishes
252
+ break;
253
+ }
254
+ try {
255
+ const res = this.block(branch.body, branch.scope, branch.path);
256
+ if (res.type === "pending") {
257
+ running++;
258
+ schedule.push(...res.schedule);
259
+ }
260
+ else {
261
+ values.push(res.type === "return" ? res.value : undefined);
262
+ }
263
+ }
264
+ catch (err) {
265
+ if (!(err instanceof FlowThrow))
266
+ throw err;
267
+ // The first branch to fail (in order) fails the whole statement
268
+ error ??= err;
269
+ }
270
+ }
271
+ if (error) {
272
+ throw error;
273
+ }
274
+ if (schedule.length) {
275
+ return { type: "pending", schedule };
276
+ }
277
+ if (assign) {
278
+ scope[assign] = values;
279
+ }
280
+ return NORMAL;
281
+ }
282
+ }
283
+ /**
284
+ * Replay a flow against its journal
285
+ *
286
+ * Pure: no I/O, the same arguments always give the same result.
287
+ * @param def - the flow definition
288
+ * @param input - the flow input, by parameter name
289
+ * @param journal - outcomes of the finished tasks
290
+ * @returns done with the output, error with the uncaught error, or pending with the tasks to run
291
+ */
292
+ export function run(def, input, journal) {
293
+ const replay = new Replay(def, journal);
294
+ try {
295
+ const res = replay.block(def.body, structuredClone(input ?? {}), []);
296
+ if (res.type === "pending") {
297
+ return { status: "pending", schedule: res.schedule };
298
+ }
299
+ return { status: "done", output: res.type === "return" ? res.value : undefined };
300
+ }
301
+ catch (err) {
302
+ if (err instanceof FlowThrow) {
303
+ return { status: "error", error: err.error };
304
+ }
305
+ throw err;
306
+ }
307
+ }
308
+ /**
309
+ * Statement ids of a definition, nested ones included
310
+ * @param def - the flow definition
311
+ * @returns the ids
312
+ */
313
+ export function keysOf(def) {
314
+ const ids = new Set();
315
+ const walk = (stmts) => {
316
+ for (const stmt of stmts ?? []) {
317
+ if (!stmt || typeof stmt !== "object")
318
+ continue;
319
+ ids.add(stmt.id);
320
+ walk(stmt.then);
321
+ walk(stmt.else);
322
+ walk(stmt.body);
323
+ walk(stmt.catch);
324
+ walk(stmt.finally);
325
+ for (const branch of stmt.branches ?? [])
326
+ walk(branch);
327
+ }
328
+ };
329
+ walk(def.body);
330
+ return ids;
331
+ }
332
+ //# sourceMappingURL=interpreter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter.js","sources":["../src/interpreter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { CoreModel, type IOperationContext } from "@webda/core";
2
+ import type { TaskOptions } from "../graph.js";
3
+ /**
4
+ * A cron launching a stored workflow
5
+ */
6
+ export interface StoredWorkflowCron {
7
+ /**
8
+ * Cron expression
9
+ */
10
+ cron: string;
11
+ /**
12
+ * Description
13
+ */
14
+ description?: string;
15
+ /**
16
+ * Flow input, by parameter name
17
+ */
18
+ input?: Record<string, any>;
19
+ }
20
+ /**
21
+ * A workflow defined at runtime: the same graph as a `.flow.ts` flow, stored as data
22
+ *
23
+ * Saving validates the graph (expressions, statement kinds, operations, `useSystem`); the WorkflowService registers
24
+ * it as the operation `name` and its crons, which run as the user who saved it last.
25
+ *
26
+ * @WebdaModel
27
+ * @WebdaPlural Workflows
28
+ */
29
+ export default class Workflow extends CoreModel {
30
+ /**
31
+ * Flow id: the operation launching it
32
+ */
33
+ name: string;
34
+ /**
35
+ * Names of the flow parameters, in order
36
+ */
37
+ params: string[];
38
+ /**
39
+ * JSON schema of the input
40
+ */
41
+ input: object;
42
+ /**
43
+ * The statements ({@link Stmt}[])
44
+ */
45
+ body: any[];
46
+ /**
47
+ * Default options of every task
48
+ */
49
+ options?: TaskOptions;
50
+ /**
51
+ * Crons launching the flow
52
+ */
53
+ crons?: StoredWorkflowCron[];
54
+ /**
55
+ * {@link flowVersion} of the graph, computed on save
56
+ */
57
+ version: string;
58
+ /**
59
+ * User id of the last save: the identity of its crons
60
+ */
61
+ updatedBy?: string;
62
+ /**
63
+ * The system always; any authenticated user reads; writes need the stored workflow role
64
+ * @param context - the caller
65
+ * @param action - the action
66
+ * @returns true when allowed, the reason otherwise
67
+ */
68
+ canAct(context: IOperationContext, action: string): Promise<string | boolean>;
69
+ }
70
+ export { Workflow };
71
+ //# sourceMappingURL=workflow.model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.model.d.ts","sources":["../../src/models/workflow.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,SAAS;IAC7C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ;;OAEG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,CAalF;CACF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { CoreModel } from "@webda/core";
2
+ import { useWorkflowControls } from "../hooks.js";
3
+ /**
4
+ * A workflow defined at runtime: the same graph as a `.flow.ts` flow, stored as data
5
+ *
6
+ * Saving validates the graph (expressions, statement kinds, operations, `useSystem`); the WorkflowService registers
7
+ * it as the operation `name` and its crons, which run as the user who saved it last.
8
+ *
9
+ * @WebdaModel
10
+ * @WebdaPlural Workflows
11
+ */
12
+ export default class Workflow extends CoreModel {
13
+ /**
14
+ * Flow id: the operation launching it
15
+ */
16
+ name;
17
+ /**
18
+ * Names of the flow parameters, in order
19
+ */
20
+ params;
21
+ /**
22
+ * JSON schema of the input
23
+ */
24
+ input;
25
+ /**
26
+ * The statements ({@link Stmt}[])
27
+ */
28
+ body;
29
+ /**
30
+ * Default options of every task
31
+ */
32
+ options;
33
+ /**
34
+ * Crons launching the flow
35
+ */
36
+ crons;
37
+ /**
38
+ * {@link flowVersion} of the graph, computed on save
39
+ */
40
+ version;
41
+ /**
42
+ * User id of the last save: the identity of its crons
43
+ */
44
+ updatedBy;
45
+ /**
46
+ * The system always; any authenticated user reads; writes need the stored workflow role
47
+ * @param context - the caller
48
+ * @param action - the action
49
+ * @returns true when allowed, the reason otherwise
50
+ */
51
+ async canAct(context, action) {
52
+ if (context.isGlobalContext())
53
+ return true;
54
+ if (!context.getCurrentUserId())
55
+ return "Authentication required";
56
+ if (action === "get" || action === "query")
57
+ return true;
58
+ let role = "workflow-admin";
59
+ try {
60
+ role = useWorkflowControls().getStoredWorkflowRole();
61
+ }
62
+ catch {
63
+ // No WorkflowService: the default role
64
+ }
65
+ const roles = context.getSession()?.roles ?? (await context.getCurrentUser())?.getRoles?.() ?? [];
66
+ return roles.includes(role) || `Role ${role} required`;
67
+ }
68
+ }
69
+ export { Workflow };
70
+ //# sourceMappingURL=workflow.model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.model.js","sources":["../../src/models/workflow.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAoBlD;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,SAAS;IAC7C;;OAEG;IACH,IAAI,CAAS;IACb;;OAEG;IACH,MAAM,CAAW;IACjB;;OAEG;IACH,KAAK,CAAS;IACd;;OAEG;IACH,IAAI,CAAQ;IACZ;;OAEG;IACH,OAAO,CAAe;IACtB;;OAEG;IACH,KAAK,CAAwB;IAC7B;;OAEG;IACH,OAAO,CAAS;IAChB;;OAEG;IACH,SAAS,CAAU;IAEnB;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,OAA0B,EAAE,MAAc;QACrD,IAAI,OAAO,CAAC,eAAe,EAAE;YAAE,OAAO,IAAI,CAAC;QAC3C,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE;YAAE,OAAO,yBAAyB,CAAC;QAClE,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACxD,IAAI,IAAI,GAAG,gBAAgB,CAAC;QAC5B,IAAI,CAAC;YACH,IAAI,GAAG,mBAAmB,EAAE,CAAC,qBAAqB,EAAE,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;QACD,MAAM,KAAK,GACT,OAAO,CAAC,UAAU,EAAE,EAAE,KAAK,IAAK,CAAC,MAAM,OAAO,CAAC,cAAc,EAAE,CAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC;QAC/F,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,WAAW,CAAC;IACzD,CAAC;CACF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}