@rytass/bpm-core-nestjs-module 0.19.0 → 0.20.0
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/CHANGELOG.md +36 -0
- package/package.json +3 -2
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/bpm/bpm-root-options.d.ts +13 -0
- package/src/lib/bpm/bpm-root-options.js.map +1 -1
- package/src/lib/bpm/bpm-root.module.d.ts +12 -0
- package/src/lib/bpm/bpm-root.module.js +5 -0
- package/src/lib/bpm/bpm-root.module.js.map +1 -1
- package/src/lib/condition/adapters/cel-legacy.adapter.d.ts +62 -0
- package/src/lib/condition/adapters/cel-legacy.adapter.js +141 -0
- package/src/lib/condition/adapters/cel-legacy.adapter.js.map +1 -0
- package/src/lib/condition/adapters/cel-v2.adapter.d.ts +76 -0
- package/src/lib/condition/adapters/cel-v2.adapter.js +371 -0
- package/src/lib/condition/adapters/cel-v2.adapter.js.map +1 -0
- package/src/lib/condition/condition.service.d.ts +90 -5
- package/src/lib/condition/condition.service.js +287 -71
- package/src/lib/condition/condition.service.js.map +1 -1
- package/src/lib/condition/expression-ast.d.ts +176 -0
- package/src/lib/condition/expression-ast.js +1254 -0
- package/src/lib/condition/expression-ast.js.map +1 -0
- package/src/lib/condition/expression-budget.d.ts +44 -0
- package/src/lib/condition/expression-budget.js +61 -0
- package/src/lib/condition/expression-budget.js.map +1 -0
- package/src/lib/condition/expression-dialect.d.ts +29 -0
- package/src/lib/condition/expression-dialect.js +44 -0
- package/src/lib/condition/expression-dialect.js.map +1 -0
- package/src/lib/condition/expression-differential.corpus.d.ts +34 -0
- package/src/lib/condition/expression-differential.corpus.js +995 -0
- package/src/lib/condition/expression-differential.corpus.js.map +1 -0
- package/src/lib/condition/expression-differential.d.ts +33 -0
- package/src/lib/condition/expression-differential.js +48 -0
- package/src/lib/condition/expression-differential.js.map +1 -0
- package/src/lib/condition/expression-engine-failure.d.ts +15 -0
- package/src/lib/condition/expression-engine-failure.js +22 -0
- package/src/lib/condition/expression-engine-failure.js.map +1 -0
- package/src/lib/condition/expression-errors.d.ts +40 -0
- package/src/lib/condition/expression-errors.js +105 -0
- package/src/lib/condition/expression-errors.js.map +1 -0
- package/src/lib/condition/expression-function-invocation.d.ts +50 -0
- package/src/lib/condition/expression-function-invocation.js +290 -0
- package/src/lib/condition/expression-function-invocation.js.map +1 -0
- package/src/lib/condition/expression-result.walker.d.ts +18 -0
- package/src/lib/condition/expression-result.walker.js +152 -0
- package/src/lib/condition/expression-result.walker.js.map +1 -0
- package/src/lib/condition/expression-runtime.d.ts +70 -0
- package/src/lib/condition/expression-runtime.js +134 -0
- package/src/lib/condition/expression-runtime.js.map +1 -0
- package/src/lib/condition/index.d.ts +4 -0
- package/src/lib/condition/index.js +8 -0
- package/src/lib/condition/index.js.map +1 -1
- package/src/lib/delegation/delegation-rule.entity.d.ts +7 -0
- package/src/lib/delegation/delegation-rule.entity.js +10 -0
- package/src/lib/delegation/delegation-rule.entity.js.map +1 -1
- package/src/lib/delegation/delegation.service.d.ts +7 -1
- package/src/lib/delegation/delegation.service.js +22 -5
- package/src/lib/delegation/delegation.service.js.map +1 -1
- package/src/lib/delegation/dto/delegation-rule.input.d.ts +2 -0
- package/src/lib/delegation/dto/delegation-rule.input.js +10 -0
- package/src/lib/delegation/dto/delegation-rule.input.js.map +1 -1
- package/src/lib/expression-function/expression-function.built-ins.d.ts +9 -0
- package/src/lib/expression-function/expression-function.built-ins.js +117 -0
- package/src/lib/expression-function/expression-function.built-ins.js.map +1 -0
- package/src/lib/expression-function/expression-function.module.d.ts +19 -0
- package/src/lib/expression-function/expression-function.module.js +34 -0
- package/src/lib/expression-function/expression-function.module.js.map +1 -0
- package/src/lib/expression-function/expression-function.provider.d.ts +17 -0
- package/src/lib/expression-function/expression-function.provider.js +39 -0
- package/src/lib/expression-function/expression-function.provider.js.map +1 -0
- package/src/lib/expression-function/expression-function.registry.d.ts +36 -0
- package/src/lib/expression-function/expression-function.registry.js +231 -0
- package/src/lib/expression-function/expression-function.registry.js.map +1 -0
- package/src/lib/expression-function/expression-function.types.d.ts +30 -0
- package/src/lib/expression-function/expression-function.types.js +8 -0
- package/src/lib/expression-function/expression-function.types.js.map +1 -0
- package/src/lib/expression-function/index.d.ts +5 -0
- package/src/lib/expression-function/index.js +9 -0
- package/src/lib/expression-function/index.js.map +1 -0
- package/src/lib/form/form-schema.validator.js +53 -6
- package/src/lib/form/form-schema.validator.js.map +1 -1
- package/src/lib/form-data-source/form-data-source-value-resolver.service.d.ts +12 -1
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js +45 -26
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js.map +1 -1
- package/src/lib/form-data-source/form-data-source.expression.d.ts +95 -0
- package/src/lib/form-data-source/form-data-source.expression.js +267 -0
- package/src/lib/form-data-source/form-data-source.expression.js.map +1 -0
- package/src/lib/form-data-source/form-data-source.module.js +4 -0
- package/src/lib/form-data-source/form-data-source.module.js.map +1 -1
- package/src/lib/form-data-source/form-data-source.service.d.ts +22 -3
- package/src/lib/form-data-source/form-data-source.service.js +78 -18
- package/src/lib/form-data-source/form-data-source.service.js.map +1 -1
- package/src/lib/form-data-source/form-data-source.validation.d.ts +47 -4
- package/src/lib/form-data-source/form-data-source.validation.js +151 -23
- package/src/lib/form-data-source/form-data-source.validation.js.map +1 -1
- package/src/lib/migrations/0000000030000-delegation-scope-condition-dialect.d.ts +22 -0
- package/src/lib/migrations/0000000030000-delegation-scope-condition-dialect.js +76 -0
- package/src/lib/migrations/0000000030000-delegation-scope-condition-dialect.js.map +1 -0
- package/src/lib/migrations/index.d.ts +1 -0
- package/src/lib/migrations/index.js +3 -0
- package/src/lib/migrations/index.js.map +1 -1
- package/src/lib/notification/notification.service.d.ts +1 -1
- package/src/lib/notification/notification.service.js +7 -3
- package/src/lib/notification/notification.service.js.map +1 -1
- package/src/lib/template/dto/expression-designer.dto.d.ts +107 -0
- package/src/lib/template/dto/expression-designer.dto.js +415 -0
- package/src/lib/template/dto/expression-designer.dto.js.map +1 -0
- package/src/lib/template/expression-designer.queries.d.ts +16 -0
- package/src/lib/template/expression-designer.queries.js +66 -0
- package/src/lib/template/expression-designer.queries.js.map +1 -0
- package/src/lib/template/expression-designer.service.d.ts +72 -0
- package/src/lib/template/expression-designer.service.js +543 -0
- package/src/lib/template/expression-designer.service.js.map +1 -0
- package/src/lib/template/index.d.ts +2 -0
- package/src/lib/template/index.js +2 -0
- package/src/lib/template/index.js.map +1 -1
- package/src/lib/template/template.module.js +4 -0
- package/src/lib/template/template.module.js.map +1 -1
- package/src/lib/template/template.service.d.ts +37 -1
- package/src/lib/template/template.service.js +317 -29
- package/src/lib/template/template.service.js.map +1 -1
- package/src/lib/template/workflow-definition.validator.d.ts +7 -0
- package/src/lib/template/workflow-definition.validator.js +26 -2
- package/src/lib/template/workflow-definition.validator.js.map +1 -1
- package/src/lib/workflow-engine/time-budget.d.ts +13 -0
- package/src/lib/workflow-engine/time-budget.js +58 -0
- package/src/lib/workflow-engine/time-budget.js.map +1 -0
- package/src/lib/workflow-engine/workflow-engine.service.d.ts +24 -0
- package/src/lib/workflow-engine/workflow-engine.service.js +240 -65
- package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
- package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.js +4 -0
- package/src/lib/workflow-engine/workflow-service-task-dispatcher.token.js.map +1 -1
- package/src/lib/workflow-webhook/workflow-webhook-delivery.service.d.ts +3 -1
- package/src/lib/workflow-webhook/workflow-webhook-delivery.service.js +11 -2
- package/src/lib/workflow-webhook/workflow-webhook-delivery.service.js.map +1 -1
- package/src/lib/workflow-webhook/workflow-webhook-enqueue.d.ts +8 -1
- package/src/lib/workflow-webhook/workflow-webhook-enqueue.js +70 -27
- package/src/lib/workflow-webhook/workflow-webhook-enqueue.js.map +1 -1
- package/src/lib/workflow-webhook/workflow-webhook-expression.d.ts +57 -0
- package/src/lib/workflow-webhook/workflow-webhook-expression.js +123 -0
- package/src/lib/workflow-webhook/workflow-webhook-expression.js.map +1 -0
- package/src/lib/workflow-webhook/workflow-webhook.module.js +4 -0
- package/src/lib/workflow-webhook/workflow-webhook.module.js.map +1 -1
- package/src/lib/workflow-webhook/workflow-webhook.validator.d.ts +7 -0
- package/src/lib/workflow-webhook/workflow-webhook.validator.js +29 -6
- package/src/lib/workflow-webhook/workflow-webhook.validator.js.map +1 -1
|
@@ -48,9 +48,17 @@ const task_entity_1 = require("./task.entity");
|
|
|
48
48
|
const workflow_engine_enums_1 = require("./workflow-engine.enums");
|
|
49
49
|
const workflow_condition_evaluator_1 = require("./workflow-condition-evaluator");
|
|
50
50
|
const workflow_dry_run_object_1 = require("./workflow-dry-run.object");
|
|
51
|
+
const time_budget_1 = require("./time-budget");
|
|
52
|
+
const expression_budget_1 = require("../condition/expression-budget");
|
|
53
|
+
const expression_errors_1 = require("../condition/expression-errors");
|
|
54
|
+
const expression_dialect_1 = require("../condition/expression-dialect");
|
|
51
55
|
const workflow_service_task_dispatcher_token_1 = require("./workflow-service-task-dispatcher.token");
|
|
52
56
|
const workflow_token_entity_1 = require("./workflow-token.entity");
|
|
53
57
|
const bpm_root_options_1 = require("../bpm/bpm-root-options");
|
|
58
|
+
const MAX_DRY_RUN_INPUT_LENGTH = 1_048_576;
|
|
59
|
+
const MAX_DRY_RUN_VISITS = 10_000;
|
|
60
|
+
const DRY_RUN_TIME_BUDGET_MS = 2_000;
|
|
61
|
+
const DRY_RUN_TOO_COMPLEX_MESSAGE = '流程或條件的運算量過大,無法完成試跑,請減少連續的閘道分支或簡化條件';
|
|
54
62
|
const MAX_PROCESSING_STEPS = 500;
|
|
55
63
|
exports.MAX_APPROVAL_INSTANCE_BUSINESS_KEY_LENGTH = 200;
|
|
56
64
|
const APPROVAL_INSTANCE_BUSINESS_KEY_INDEX = 'approval_instances_business_key_key';
|
|
@@ -58,6 +66,40 @@ const APPROVAL_INSTANCE_BUSINESS_KEY_INDEX = 'approval_instances_business_key_ke
|
|
|
58
66
|
const ORG_MANAGER_CHAIN_MAX_HOPS = 20;
|
|
59
67
|
const DEFAULT_APPROVAL_HISTORY_TASK_LIMIT = 50;
|
|
60
68
|
const SYSTEM_DRY_RUN_INSTANCE_ID = 'dry-run-instance';
|
|
69
|
+
// The dry run checks each expression against the roots its use point may read,
|
|
70
|
+
// as publish does. Keep these in step with `WORKFLOW_EXPRESSION_ROOT_IDENTIFIERS`
|
|
71
|
+
// in template.service.ts; P2 moves both to one place.
|
|
72
|
+
const DRY_RUN_WORKFLOW_ROOT_IDENTIFIERS = [
|
|
73
|
+
'env',
|
|
74
|
+
'form',
|
|
75
|
+
'formData',
|
|
76
|
+
'initiator',
|
|
77
|
+
'instance',
|
|
78
|
+
];
|
|
79
|
+
const DRY_RUN_EDGE_ROOT_IDENTIFIERS = [
|
|
80
|
+
...DRY_RUN_WORKFLOW_ROOT_IDENTIFIERS,
|
|
81
|
+
'lastDecision',
|
|
82
|
+
];
|
|
83
|
+
const hasExpressionText = (expression) => typeof expression === 'string' && expression.trim() !== '';
|
|
84
|
+
/**
|
|
85
|
+
* Whether a definition's dialect can be read: missing (`cel-legacy`) or one
|
|
86
|
+
* this version knows. Never throws, unlike `readWorkflowExpressionDialect`.
|
|
87
|
+
*/
|
|
88
|
+
const isReadableExpressionDialect = (definition) => {
|
|
89
|
+
const dialect = definition?.expressionDialect;
|
|
90
|
+
return (dialect === undefined || dialect === null || (0, expression_dialect_1.isExpressionDialect)(dialect));
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Options for evaluating an expression that may be blank. The dialect is read
|
|
94
|
+
* only when there is an expression: an unknown dialect is refused because the
|
|
95
|
+
* expression cannot be evaluated as its author tested it, and a blank one is
|
|
96
|
+
* never evaluated at all. Publishing does not check the field yet (Phase 23
|
|
97
|
+
* P2), so reading it eagerly would turn a stray field on a version with no
|
|
98
|
+
* expressions into an error, where before dialects existed it was ignored.
|
|
99
|
+
*/
|
|
100
|
+
const readExpressionDialectOptions = (expression, definition) => hasExpressionText(expression)
|
|
101
|
+
? { dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(definition) }
|
|
102
|
+
: {};
|
|
61
103
|
/**
|
|
62
104
|
* Delegation-chain reason recorded for an approver-initiated transfer, as
|
|
63
105
|
* opposed to {@link SLA_ESCALATION_DELEGATION_REASON}.
|
|
@@ -152,6 +194,8 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
152
194
|
this.formDataSourceValueResolver = formDataSourceValueResolver;
|
|
153
195
|
this.webhookDeliveryService = webhookDeliveryService;
|
|
154
196
|
this.logger = new common_1.Logger(WorkflowEngineService_1.name);
|
|
197
|
+
/** Webhooks each open engine transaction will send once it has committed. */
|
|
198
|
+
this.deferredWebhookDispatches = new WeakMap();
|
|
155
199
|
// A binding under the token wins: that is either the host's own provider
|
|
156
200
|
// or `workflowServiceTaskDispatcherProvider`, both of them deliberate. The
|
|
157
201
|
// runtime instance from `BPMRootModule`'s async factory comes next.
|
|
@@ -177,6 +221,59 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
177
221
|
readOrganizationToday() {
|
|
178
222
|
return (0, organization_time_zone_1.formatDateOnlyInTimeZone)(new Date(), this.organizationTimeZone);
|
|
179
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Opens an engine transaction whose webhooks wait for its commit. A webhook
|
|
226
|
+
* sent from inside would hold the case lock and a pooled connection for as
|
|
227
|
+
* long as the far end takes to answer, so a slow endpoint could stall the
|
|
228
|
+
* case and then, a connection at a time, the whole API. A transaction that
|
|
229
|
+
* rolls back sends nothing.
|
|
230
|
+
*
|
|
231
|
+
* The caller still waits for the sends, so the outcome is in the activity log
|
|
232
|
+
* by the time a mutation returns, as it always has been.
|
|
233
|
+
*/
|
|
234
|
+
async runEngineTransaction(work) {
|
|
235
|
+
// Mutable on purpose: every step of the transaction appends to it, and
|
|
236
|
+
// threading it through each of them would change a dozen signatures.
|
|
237
|
+
const dispatches = [];
|
|
238
|
+
// One transaction is one operation: its evaluations share one budget.
|
|
239
|
+
const result = await (0, expression_budget_1.runExpressionOperation)(() => this.approvalInstanceRepository.manager.transaction((manager) => {
|
|
240
|
+
this.deferredWebhookDispatches.set(manager, dispatches);
|
|
241
|
+
return work(manager);
|
|
242
|
+
}));
|
|
243
|
+
await dispatches.reduce(async (previous, dispatch) => {
|
|
244
|
+
await previous;
|
|
245
|
+
await this.sendCommittedWebhook(dispatch);
|
|
246
|
+
}, Promise.resolve());
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Queues a webhook for after the commit. A manager this service did not open
|
|
251
|
+
* has no queue and no commit it can see, so that webhook goes out on the spot
|
|
252
|
+
* rather than being dropped.
|
|
253
|
+
*/
|
|
254
|
+
async dispatchWebhookAfterCommit(manager, dispatch) {
|
|
255
|
+
const queue = this.deferredWebhookDispatches.get(manager);
|
|
256
|
+
if (queue) {
|
|
257
|
+
queue.push(dispatch);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const activityRepository = manager.getRepository(activity_log_entity_1.ActivityLogEntity);
|
|
261
|
+
const result = await dispatch.send();
|
|
262
|
+
await activityRepository.save(activityRepository.create(dispatch.readActivityLog(result)));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The transaction has committed and the mutation has succeeded, so nothing
|
|
266
|
+
* here may fail it: a result that cannot be recorded is only logged.
|
|
267
|
+
*/
|
|
268
|
+
async sendCommittedWebhook(dispatch) {
|
|
269
|
+
try {
|
|
270
|
+
const result = await dispatch.send();
|
|
271
|
+
await this.activityLogRepository.save(this.activityLogRepository.create(dispatch.readActivityLog(result)));
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
this.logger.error(`Could not record a webhook result for instance ${dispatch.instanceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
180
277
|
async submitApprovalInstance(input, authContext) {
|
|
181
278
|
if (input.submittedByMemberId !== undefined &&
|
|
182
279
|
input.submittedByMemberId !== null &&
|
|
@@ -219,7 +316,9 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
219
316
|
const initiatorMetadataSnapshot = input.initiatorMetadataSnapshotJson
|
|
220
317
|
? parseJsonObject(input.initiatorMetadataSnapshotJson, 'initiatorMetadataSnapshotJson')
|
|
221
318
|
: await this.readDefaultInitiatorMetadataSnapshot(input.initiatorMemberId);
|
|
222
|
-
if (!this.conditionService.evaluateBoolean(templateVersion.initiatorPolicyCel, buildInitiatorPolicyContext(initiatorMetadataSnapshot), 'initiatorPolicyCel'
|
|
319
|
+
if (!this.conditionService.evaluateBoolean(templateVersion.initiatorPolicyCel, buildInitiatorPolicyContext(initiatorMetadataSnapshot), 'initiatorPolicyCel',
|
|
320
|
+
// The policy is written in its version's dialect (ADR 22 §3.3).
|
|
321
|
+
readExpressionDialectOptions(templateVersion.initiatorPolicyCel, templateVersion.workflowDefinition))) {
|
|
223
322
|
throw new common_1.ConflictException('Current member is not allowed to start this approval template');
|
|
224
323
|
}
|
|
225
324
|
// Named here, before the transaction, so the completion notice that later
|
|
@@ -233,7 +332,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
233
332
|
if (!startNode) {
|
|
234
333
|
throw new common_1.BadRequestException('Published workflow does not include a startEvent');
|
|
235
334
|
}
|
|
236
|
-
return this.
|
|
335
|
+
return this.runEngineTransaction(async (manager) => {
|
|
237
336
|
const instanceRepository = manager.getRepository(approval_instance_entity_1.ApprovalInstanceEntity);
|
|
238
337
|
const tokenRepository = manager.getRepository(workflow_token_entity_1.WorkflowTokenEntity);
|
|
239
338
|
const activityRepository = manager.getRepository(activity_log_entity_1.ActivityLogEntity);
|
|
@@ -370,7 +469,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
370
469
|
return { formDataOptionSnapshot, instance };
|
|
371
470
|
}
|
|
372
471
|
async processInstance(instanceId) {
|
|
373
|
-
await this.
|
|
472
|
+
await this.runEngineTransaction(async (manager) => {
|
|
374
473
|
await manager.query('SELECT pg_advisory_xact_lock(hashtext($1))', [
|
|
375
474
|
instanceId,
|
|
376
475
|
]);
|
|
@@ -397,7 +496,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
397
496
|
});
|
|
398
497
|
}
|
|
399
498
|
async decideTask(input, options = {}) {
|
|
400
|
-
return this.
|
|
499
|
+
return this.runEngineTransaction(async (manager) => {
|
|
401
500
|
const taskRepository = manager.getRepository(task_entity_1.TaskEntity);
|
|
402
501
|
const taskCandidateRepository = manager.getRepository(task_candidate_entity_1.TaskCandidateEntity);
|
|
403
502
|
const taskDecisionRepository = manager.getRepository(task_decision_entity_1.TaskDecisionEntity);
|
|
@@ -760,7 +859,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
760
859
|
});
|
|
761
860
|
}
|
|
762
861
|
async cancelApprovalInstance(input) {
|
|
763
|
-
return this.
|
|
862
|
+
return this.runEngineTransaction(async (manager) => {
|
|
764
863
|
await manager.query('SELECT pg_advisory_xact_lock(hashtext($1))', [
|
|
765
864
|
input.instanceId,
|
|
766
865
|
]);
|
|
@@ -801,7 +900,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
801
900
|
* returned unchanged.
|
|
802
901
|
*/
|
|
803
902
|
async expireApprovalInstance(input) {
|
|
804
|
-
return this.
|
|
903
|
+
return this.runEngineTransaction(async (manager) => {
|
|
805
904
|
await manager.query('SELECT pg_advisory_xact_lock(hashtext($1))', [
|
|
806
905
|
input.instanceId,
|
|
807
906
|
]);
|
|
@@ -858,7 +957,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
858
957
|
const preparation = this.formDataSourceValueResolver
|
|
859
958
|
? await this.prepareResubmitFormDataOptions(input, submittedFormData, authContext ?? createWorkflowAuthContext(input.initiatorMemberId))
|
|
860
959
|
: null;
|
|
861
|
-
return this.
|
|
960
|
+
return this.runEngineTransaction(async (manager) => {
|
|
862
961
|
await manager.query('SELECT pg_advisory_xact_lock(hashtext($1))', [
|
|
863
962
|
input.instanceId,
|
|
864
963
|
]);
|
|
@@ -947,7 +1046,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
947
1046
|
});
|
|
948
1047
|
}
|
|
949
1048
|
async requestAdhocCountersign({ comment, requestedByMemberId, target, taskId, }) {
|
|
950
|
-
return this.
|
|
1049
|
+
return this.runEngineTransaction(async (manager) => {
|
|
951
1050
|
const { instance, node, task } = await this.loadAdhocOperationContext(manager, taskId, requestedByMemberId, { requireAllowAddSigner: true });
|
|
952
1051
|
const targetValue = buildAdhocTargetValue(target);
|
|
953
1052
|
// Rejects WEBHOOK targets — countersigners must be members.
|
|
@@ -979,7 +1078,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
979
1078
|
});
|
|
980
1079
|
}
|
|
981
1080
|
async requestAdhocPreApproval({ comment, onReject, requestedByMemberId, target, taskId, }) {
|
|
982
|
-
return this.
|
|
1081
|
+
return this.runEngineTransaction(async (manager) => {
|
|
983
1082
|
const { instance, node, task } = await this.loadAdhocOperationContext(manager, taskId, requestedByMemberId, { requireAllowAddSigner: true });
|
|
984
1083
|
const targetValue = buildAdhocTargetValue(target);
|
|
985
1084
|
// Rejects WEBHOOK targets — pre-approvers must be members.
|
|
@@ -1006,7 +1105,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1006
1105
|
});
|
|
1007
1106
|
}
|
|
1008
1107
|
async configureAdhocNotification({ channels, requestedByMemberId, target, taskId, type, }) {
|
|
1009
|
-
return this.
|
|
1108
|
+
return this.runEngineTransaction(async (manager) => {
|
|
1010
1109
|
const { instance, node, task } = await this.loadAdhocOperationContext(manager, taskId, requestedByMemberId, { requireAllowAddSigner: false });
|
|
1011
1110
|
const targetValue = buildAdhocTargetValue(target);
|
|
1012
1111
|
const directiveRepository = manager.getRepository(adhoc_directive_entity_1.AdhocDirectiveEntity);
|
|
@@ -1029,7 +1128,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1029
1128
|
});
|
|
1030
1129
|
}
|
|
1031
1130
|
async cancelAdhocDirective({ cancelledByMemberId, directiveId, }) {
|
|
1032
|
-
return this.
|
|
1131
|
+
return this.runEngineTransaction(async (manager) => {
|
|
1033
1132
|
const directiveRepository = manager.getRepository(adhoc_directive_entity_1.AdhocDirectiveEntity);
|
|
1034
1133
|
const directive = await directiveRepository.findOne({
|
|
1035
1134
|
where: { id: directiveId },
|
|
@@ -1593,30 +1692,34 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1593
1692
|
const targetValue = readAdhocTargetValue(directive);
|
|
1594
1693
|
const activityRepository = manager.getRepository(activity_log_entity_1.ActivityLogEntity);
|
|
1595
1694
|
if (targetValue.kind === adhoc_enums_1.AdhocTargetKindEnum.WEBHOOK) {
|
|
1596
|
-
const
|
|
1695
|
+
const webhookPayload = {
|
|
1597
1696
|
...payload,
|
|
1598
1697
|
instanceId: instance.id,
|
|
1599
1698
|
instanceTitle: instance.title,
|
|
1600
1699
|
message,
|
|
1601
1700
|
triggeredAt: new Date().toISOString(),
|
|
1602
|
-
}
|
|
1603
|
-
await
|
|
1604
|
-
actorMemberId: null,
|
|
1605
|
-
eventType: result.ok
|
|
1606
|
-
? workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_EXECUTED
|
|
1607
|
-
: workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_FAILED,
|
|
1701
|
+
};
|
|
1702
|
+
await this.dispatchWebhookAfterCommit(manager, {
|
|
1608
1703
|
instanceId: instance.id,
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1704
|
+
readActivityLog: (result) => ({
|
|
1705
|
+
actorMemberId: null,
|
|
1706
|
+
eventType: result.ok
|
|
1707
|
+
? workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_EXECUTED
|
|
1708
|
+
: workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_FAILED,
|
|
1709
|
+
instanceId: instance.id,
|
|
1710
|
+
nodeId: directive.originNodeId,
|
|
1711
|
+
payload: {
|
|
1712
|
+
action: 'ADHOC_WEBHOOK',
|
|
1713
|
+
directiveId: directive.id,
|
|
1714
|
+
error: result.error,
|
|
1715
|
+
ok: result.ok,
|
|
1716
|
+
status: result.status,
|
|
1717
|
+
url: targetValue.webhookUrl,
|
|
1718
|
+
},
|
|
1719
|
+
taskId: null,
|
|
1720
|
+
}),
|
|
1721
|
+
send: () => executeAdhocWebhookDispatch(this.serviceTaskDispatcher, targetValue, webhookPayload),
|
|
1722
|
+
});
|
|
1620
1723
|
return;
|
|
1621
1724
|
}
|
|
1622
1725
|
try {
|
|
@@ -1667,29 +1770,38 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1667
1770
|
})));
|
|
1668
1771
|
}
|
|
1669
1772
|
dryRunApprovalWorkflow(input) {
|
|
1773
|
+
// Checked first: parsing happens outside the time budget below.
|
|
1774
|
+
if ([
|
|
1775
|
+
input.workflowDefinitionJson,
|
|
1776
|
+
input.formDataJson,
|
|
1777
|
+
input.initiatorMetadataSnapshotJson ?? '',
|
|
1778
|
+
].some((json) => json.length > MAX_DRY_RUN_INPUT_LENGTH)) {
|
|
1779
|
+
return createFailedDryRunResult('試跑資料過大,請縮小流程或測試資料後再試');
|
|
1780
|
+
}
|
|
1670
1781
|
const workflowDefinition = parseWorkflowDefinition(input.workflowDefinitionJson);
|
|
1671
1782
|
const formData = parseJsonObject(input.formDataJson, 'formDataJson');
|
|
1672
1783
|
const initiatorMetadataSnapshot = input.initiatorMetadataSnapshotJson
|
|
1673
1784
|
? parseJsonObject(input.initiatorMetadataSnapshotJson, 'initiatorMetadataSnapshotJson')
|
|
1674
1785
|
: readDefaultInitiatorMetadataSnapshot(input.initiatorMemberId);
|
|
1675
1786
|
try {
|
|
1787
|
+
// The CEL engine loads outside the budget so an interrupt can never land
|
|
1788
|
+
// halfway through loading a module.
|
|
1789
|
+
this.conditionService.prepareEngine((0, expression_dialect_1.readWorkflowExpressionDialect)(workflowDefinition));
|
|
1790
|
+
// The outer budget bounds the whole walk, and the operation budget
|
|
1791
|
+
// bounds the expressions inside it. Both are charged to this dry run only.
|
|
1676
1792
|
return Object.assign(new workflow_dry_run_object_1.WorkflowDryRunResultObject(), {
|
|
1677
1793
|
errors: [],
|
|
1678
|
-
steps: this.simulateWorkflow({
|
|
1794
|
+
steps: (0, expression_budget_1.runExpressionOperation)(() => (0, time_budget_1.runWithinTimeBudget)(() => this.simulateWorkflow({
|
|
1679
1795
|
formData,
|
|
1680
1796
|
initiatorMemberId: input.initiatorMemberId,
|
|
1681
1797
|
initiatorMetadataSnapshot,
|
|
1682
1798
|
workflowDefinition,
|
|
1683
|
-
}),
|
|
1799
|
+
}), DRY_RUN_TIME_BUDGET_MS)),
|
|
1684
1800
|
valid: true,
|
|
1685
1801
|
});
|
|
1686
1802
|
}
|
|
1687
1803
|
catch (error) {
|
|
1688
|
-
return
|
|
1689
|
-
errors: [error instanceof Error ? error.message : 'Dry run failed'],
|
|
1690
|
-
steps: [],
|
|
1691
|
-
valid: false,
|
|
1692
|
-
});
|
|
1804
|
+
return createFailedDryRunResult(readDryRunFailureMessage(error));
|
|
1693
1805
|
}
|
|
1694
1806
|
}
|
|
1695
1807
|
simulateWorkflow(input) {
|
|
@@ -1697,8 +1809,18 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1697
1809
|
if (!startNode) {
|
|
1698
1810
|
throw new common_1.BadRequestException('Workflow does not include a startEvent');
|
|
1699
1811
|
}
|
|
1812
|
+
// Every branch re-walks whatever follows it, so a chain of gateways doubles
|
|
1813
|
+
// the work at each one while the depth limit never trips. Closure state
|
|
1814
|
+
// because all the branches of one dry run share this one count.
|
|
1815
|
+
let visits = 0;
|
|
1700
1816
|
return this.simulateWorkflowPath({
|
|
1701
1817
|
...input,
|
|
1818
|
+
chargeVisit: () => {
|
|
1819
|
+
visits += 1;
|
|
1820
|
+
if (visits > MAX_DRY_RUN_VISITS) {
|
|
1821
|
+
throw new common_1.ConflictException(DRY_RUN_TOO_COMPLEX_MESSAGE);
|
|
1822
|
+
}
|
|
1823
|
+
},
|
|
1702
1824
|
depth: 0,
|
|
1703
1825
|
incomingEdge: null,
|
|
1704
1826
|
lastDecision: null,
|
|
@@ -1711,6 +1833,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1711
1833
|
if (input.depth > MAX_PROCESSING_STEPS) {
|
|
1712
1834
|
throw new common_1.ConflictException('Dry run exceeded maximum processing steps');
|
|
1713
1835
|
}
|
|
1836
|
+
input.chargeVisit();
|
|
1714
1837
|
const node = readWorkflowNodeOrThrow(input.workflowDefinition, input.nodeId);
|
|
1715
1838
|
const visitKey = `${input.nodeId}:${input.incomingEdge?.id ?? 'start'}`;
|
|
1716
1839
|
const entryCondition = readNodeEntryCondition(node);
|
|
@@ -1732,7 +1855,10 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1732
1855
|
];
|
|
1733
1856
|
}
|
|
1734
1857
|
const nextVisitedNodeIds = new Set([...input.visitedNodeIds, visitKey]);
|
|
1735
|
-
const entryConditionMet = this.conditionService.evaluateBoolean(entryCondition, buildDryRunExpressionContext(input, input.lastDecision), `workflow.nodes.${node.id}.data.entryCondition
|
|
1858
|
+
const entryConditionMet = this.conditionService.evaluateBoolean(entryCondition, buildDryRunExpressionContext(input, input.lastDecision), `workflow.nodes.${node.id}.data.entryCondition`, {
|
|
1859
|
+
allowedRootIdentifiers: DRY_RUN_WORKFLOW_ROOT_IDENTIFIERS,
|
|
1860
|
+
dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(input.workflowDefinition),
|
|
1861
|
+
});
|
|
1736
1862
|
const assignment = entryConditionMet && node.type === 'userTask'
|
|
1737
1863
|
? this.resolveDryRunAssignment(input, node)
|
|
1738
1864
|
: null;
|
|
@@ -1826,7 +1952,10 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1826
1952
|
evaluateDryRunEdge(input, edge, lastDecision) {
|
|
1827
1953
|
const expression = edge.data.condition?.trim();
|
|
1828
1954
|
if (expression && !isListValuedStructuredCondition(edge, input.formData)) {
|
|
1829
|
-
return this.conditionService.evaluateBoolean(expression, buildDryRunExpressionContext(input, lastDecision), `workflow.edges.${edge.id}.data.condition
|
|
1955
|
+
return this.conditionService.evaluateBoolean(expression, buildDryRunExpressionContext(input, lastDecision), `workflow.edges.${edge.id}.data.condition`, {
|
|
1956
|
+
allowedRootIdentifiers: DRY_RUN_EDGE_ROOT_IDENTIFIERS,
|
|
1957
|
+
dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(input.workflowDefinition),
|
|
1958
|
+
});
|
|
1830
1959
|
}
|
|
1831
1960
|
return (0, workflow_condition_evaluator_1.evaluateWorkflowEdgeCondition)(edge, { formData: input.formData });
|
|
1832
1961
|
}
|
|
@@ -1926,7 +2055,10 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
1926
2055
|
return findMemberIdsInValue(readValueAtPath(input.formData, resolver.formPath));
|
|
1927
2056
|
}
|
|
1928
2057
|
if (resolver.type === 'EXPRESSION') {
|
|
1929
|
-
return findMemberIdsInValue(this.conditionService.evaluateValue(resolver.expression, buildDryRunExpressionContext(input, null), `${label}.expression
|
|
2058
|
+
return findMemberIdsInValue(this.conditionService.evaluateValue(resolver.expression, buildDryRunExpressionContext(input, null), `${label}.expression`, {
|
|
2059
|
+
allowedRootIdentifiers: DRY_RUN_WORKFLOW_ROOT_IDENTIFIERS,
|
|
2060
|
+
dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(input.workflowDefinition),
|
|
2061
|
+
}));
|
|
1930
2062
|
}
|
|
1931
2063
|
if (resolver.type === 'ORG_MANAGER') {
|
|
1932
2064
|
const managerMemberIds = findMemberIdsInValue(readManagerMemberIdFromInitiatorSnapshot(input.initiatorMetadataSnapshot, resolver.levelsUp));
|
|
@@ -2138,7 +2270,18 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
2138
2270
|
if (!currentVersion?.formDefinitionVersionId) {
|
|
2139
2271
|
return false;
|
|
2140
2272
|
}
|
|
2141
|
-
|
|
2273
|
+
// A policy in a dialect this version does not know cannot be evaluated,
|
|
2274
|
+
// so the template is not launchable (fail closed), but only that one:
|
|
2275
|
+
// publishing does not check the field yet (Phase 23 P2), and one such
|
|
2276
|
+
// version must not break the list for every member.
|
|
2277
|
+
if (hasExpressionText(currentVersion.initiatorPolicyCel) &&
|
|
2278
|
+
!isReadableExpressionDialect(currentVersion.workflowDefinition)) {
|
|
2279
|
+
this.logger.warn(`template=${template.id} version=${currentVersion.id} left out of launchable templates: unknown expression dialect`);
|
|
2280
|
+
return false;
|
|
2281
|
+
}
|
|
2282
|
+
// Each template is its own operation, so one slow template cannot use
|
|
2283
|
+
// up the allowance of the rest of the list.
|
|
2284
|
+
return (0, expression_budget_1.runExpressionOperation)(() => this.conditionService.evaluateBoolean(currentVersion.initiatorPolicyCel, buildInitiatorPolicyContext(initiatorMetadataSnapshot), 'initiatorPolicyCel', readExpressionDialectOptions(currentVersion.initiatorPolicyCel, currentVersion.workflowDefinition)));
|
|
2142
2285
|
});
|
|
2143
2286
|
}
|
|
2144
2287
|
async listWorkflowTokens(instanceId, scope) {
|
|
@@ -2592,7 +2735,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
2592
2735
|
}
|
|
2593
2736
|
isNodeEntryConditionMet(instance, node) {
|
|
2594
2737
|
const entryCondition = readNodeEntryCondition(node);
|
|
2595
|
-
return this.conditionService.evaluateBoolean(entryCondition, buildWorkflowExpressionContext(instance), `workflow.nodes.${node.id}.data.entryCondition
|
|
2738
|
+
return this.conditionService.evaluateBoolean(entryCondition, buildWorkflowExpressionContext(instance), `workflow.nodes.${node.id}.data.entryCondition`, readExpressionDialectOptions(entryCondition, instance.workflowSnapshot));
|
|
2596
2739
|
}
|
|
2597
2740
|
async skipNodeByEntryCondition(manager, instance, token, node) {
|
|
2598
2741
|
await this.skipNode(manager, instance, token, node, {
|
|
@@ -2665,7 +2808,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
2665
2808
|
return this.conditionService.evaluateBoolean(expression, {
|
|
2666
2809
|
...buildWorkflowExpressionContext(instance),
|
|
2667
2810
|
lastDecision: await this.readLastDecisionContext(manager, instance.id, node.id),
|
|
2668
|
-
}, `workflow.edges.${edge.id}.data.condition
|
|
2811
|
+
}, `workflow.edges.${edge.id}.data.condition`, { dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(instance.workflowSnapshot) });
|
|
2669
2812
|
}
|
|
2670
2813
|
return (0, workflow_condition_evaluator_1.evaluateWorkflowEdgeCondition)(edge, { formData: instance.formData });
|
|
2671
2814
|
}
|
|
@@ -3491,7 +3634,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
3491
3634
|
});
|
|
3492
3635
|
}
|
|
3493
3636
|
async executeTaskReassignment(preRead, options) {
|
|
3494
|
-
return this.
|
|
3637
|
+
return this.runEngineTransaction(async (manager) => {
|
|
3495
3638
|
try {
|
|
3496
3639
|
const plan = await this.planTaskReassignment(manager, preRead.id, options);
|
|
3497
3640
|
if (options.dryRun) {
|
|
@@ -3868,7 +4011,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
3868
4011
|
async delegateResolvedCandidates(manager, instance, nodeId, resolvedCandidates, gradeGated) {
|
|
3869
4012
|
// One batch for the node, so the host directory is asked once for every
|
|
3870
4013
|
// candidate's delegation agents rather than once per candidate.
|
|
3871
|
-
const resolutions = await this.delegationService.resolveAssignees(resolvedCandidates.map((candidate) => candidate.memberId), this.buildDelegationContext(instance, nodeId));
|
|
4014
|
+
const resolutions = await this.delegationService.resolveAssignees(resolvedCandidates.map((candidate) => candidate.memberId), { ...this.buildDelegationContext(instance, nodeId), manager });
|
|
3872
4015
|
const resolved = resolvedCandidates.map((candidate, index) => ({
|
|
3873
4016
|
candidate,
|
|
3874
4017
|
resolution: resolutions[index],
|
|
@@ -3890,7 +4033,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
3890
4033
|
}
|
|
3891
4034
|
/** One member's delegation, grade-gated as {@link applyGradeGate} says. */
|
|
3892
4035
|
async resolveDelegation(manager, principalMemberId, context, gradeGated) {
|
|
3893
|
-
const resolution = await this.delegationService.resolveAssignee(principalMemberId, context);
|
|
4036
|
+
const resolution = await this.delegationService.resolveAssignee(principalMemberId, { ...context, manager });
|
|
3894
4037
|
const memberIds = gradeGated
|
|
3895
4038
|
? readGradeGateMemberIds(principalMemberId, resolution)
|
|
3896
4039
|
: [];
|
|
@@ -3946,7 +4089,7 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
3946
4089
|
return readMemberIdsFromValue(readValueAtPath(instance.formData, resolver.formPath), label, subject, `依表單欄位「${resolver.formPath}」`);
|
|
3947
4090
|
}
|
|
3948
4091
|
if (resolver.type === 'EXPRESSION') {
|
|
3949
|
-
return readMemberIdsFromValue(this.conditionService.evaluateValue(resolver.expression, buildWorkflowExpressionContext(instance), `${label}.expression
|
|
4092
|
+
return readMemberIdsFromValue(this.conditionService.evaluateValue(resolver.expression, buildWorkflowExpressionContext(instance), `${label}.expression`, { dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(instance.workflowSnapshot) }), label, subject, '依運算式');
|
|
3950
4093
|
}
|
|
3951
4094
|
if (resolver.type === 'POSITION') {
|
|
3952
4095
|
return this.resolvePositionCandidates(manager, resolver.positionId, label, subject);
|
|
@@ -4468,34 +4611,39 @@ let WorkflowEngineService = WorkflowEngineService_1 = class WorkflowEngineServic
|
|
|
4468
4611
|
const action = node.data.action;
|
|
4469
4612
|
if (action.type === 'WEBHOOK') {
|
|
4470
4613
|
const payload = typeof action.payload === 'string' && action.payload.trim()
|
|
4471
|
-
? this.conditionService.evaluateValue(action.payload, buildWorkflowExpressionContext(instance), `workflow.nodes.${node.id}.data.action.payload
|
|
4614
|
+
? this.conditionService.evaluateValue(action.payload, buildWorkflowExpressionContext(instance), `workflow.nodes.${node.id}.data.action.payload`, {
|
|
4615
|
+
dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(instance.workflowSnapshot),
|
|
4616
|
+
})
|
|
4472
4617
|
: {
|
|
4473
4618
|
instance: buildWorkflowExpressionContext(instance).instance,
|
|
4474
4619
|
triggeredAt: new Date().toISOString(),
|
|
4475
4620
|
};
|
|
4476
|
-
|
|
4477
|
-
await activityRepository.save(activityRepository.create({
|
|
4478
|
-
actorMemberId: null,
|
|
4479
|
-
eventType: result.ok
|
|
4480
|
-
? workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_EXECUTED
|
|
4481
|
-
: workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_FAILED,
|
|
4621
|
+
await this.dispatchWebhookAfterCommit(manager, {
|
|
4482
4622
|
instanceId: instance.id,
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4623
|
+
readActivityLog: (result) => ({
|
|
4624
|
+
actorMemberId: null,
|
|
4625
|
+
eventType: result.ok
|
|
4626
|
+
? workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_EXECUTED
|
|
4627
|
+
: workflow_engine_enums_1.ActivityLogEventTypeEnum.SERVICE_TASK_FAILED,
|
|
4628
|
+
instanceId: instance.id,
|
|
4629
|
+
nodeId: node.id,
|
|
4630
|
+
payload: {
|
|
4631
|
+
action: 'WEBHOOK',
|
|
4632
|
+
error: result.error,
|
|
4633
|
+
ok: result.ok,
|
|
4634
|
+
status: result.status,
|
|
4635
|
+
tokenId: token.id,
|
|
4636
|
+
url: action.url,
|
|
4637
|
+
},
|
|
4638
|
+
taskId: null,
|
|
4639
|
+
}),
|
|
4640
|
+
send: () => executeWebhookServiceAction(this.serviceTaskDispatcher, action, payload),
|
|
4641
|
+
});
|
|
4494
4642
|
await this.advanceTokenToOutgoingNodes(manager, instance, token, node);
|
|
4495
4643
|
return;
|
|
4496
4644
|
}
|
|
4497
4645
|
if (action.type === 'SET_FORM_FIELD') {
|
|
4498
|
-
const value = this.conditionService.evaluateValue(action.value, buildWorkflowExpressionContext(instance), `workflow.nodes.${node.id}.data.action.value
|
|
4646
|
+
const value = this.conditionService.evaluateValue(action.value, buildWorkflowExpressionContext(instance), `workflow.nodes.${node.id}.data.action.value`, { dialect: (0, expression_dialect_1.readWorkflowExpressionDialect)(instance.workflowSnapshot) });
|
|
4499
4647
|
assertServiceTaskTextValue(instance.formDefinitionSnapshot, action.fieldPath, value, node.data.label);
|
|
4500
4648
|
const updatedFormData = writeValueAtPath(instance.formData, action.fieldPath, value);
|
|
4501
4649
|
// A service task runs inside this transaction, so it cannot call a host
|
|
@@ -5617,6 +5765,33 @@ function normalizeFormFieldPath(path) {
|
|
|
5617
5765
|
}
|
|
5618
5766
|
return segments;
|
|
5619
5767
|
}
|
|
5768
|
+
/**
|
|
5769
|
+
* The message a failed dry run shows its caller. Only the fixed budget text, an
|
|
5770
|
+
* HTTP exception's own message, or an expression error's label and code reach
|
|
5771
|
+
* this point. Any other error is replaced with a generic message, since its text
|
|
5772
|
+
* may carry engine or context details.
|
|
5773
|
+
*/
|
|
5774
|
+
function readDryRunFailureMessage(error) {
|
|
5775
|
+
if (error instanceof time_budget_1.TimeBudgetExceededError) {
|
|
5776
|
+
return DRY_RUN_TOO_COMPLEX_MESSAGE;
|
|
5777
|
+
}
|
|
5778
|
+
if (error instanceof expression_errors_1.ExpressionRuntimeError) {
|
|
5779
|
+
return error.keyName
|
|
5780
|
+
? `${error.message}(找不到「${error.keyName}」)`
|
|
5781
|
+
: error.message;
|
|
5782
|
+
}
|
|
5783
|
+
if (error instanceof common_1.HttpException) {
|
|
5784
|
+
return error.message;
|
|
5785
|
+
}
|
|
5786
|
+
return 'Dry run failed';
|
|
5787
|
+
}
|
|
5788
|
+
function createFailedDryRunResult(message) {
|
|
5789
|
+
return Object.assign(new workflow_dry_run_object_1.WorkflowDryRunResultObject(), {
|
|
5790
|
+
errors: [message],
|
|
5791
|
+
steps: [],
|
|
5792
|
+
valid: false,
|
|
5793
|
+
});
|
|
5794
|
+
}
|
|
5620
5795
|
async function executeWebhookServiceAction(serviceTaskDispatcher, action, payload) {
|
|
5621
5796
|
try {
|
|
5622
5797
|
return await serviceTaskDispatcher.dispatchWebhook({
|