@rytass/bpm-core-nestjs-module 0.22.0 → 0.23.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 +64 -0
- package/package.json +2 -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 +57 -0
- package/src/lib/bpm/bpm-root-options.js.map +1 -1
- package/src/lib/bpm/bpm-root.module.d.ts +21 -0
- package/src/lib/bpm/bpm-root.module.js +6 -0
- package/src/lib/bpm/bpm-root.module.js.map +1 -1
- package/src/lib/form/dto/form-definition.input.d.ts +5 -0
- package/src/lib/form/dto/form-definition.input.js.map +1 -1
- package/src/lib/form/form-definition.entity.d.ts +5 -0
- package/src/lib/form/form-definition.entity.js +7 -0
- package/src/lib/form/form-definition.entity.js.map +1 -1
- package/src/lib/form/form-schema.validator.js +17 -5
- package/src/lib/form/form-schema.validator.js.map +1 -1
- package/src/lib/form/form.queries.d.ts +2 -2
- package/src/lib/form/form.queries.js +17 -5
- package/src/lib/form/form.queries.js.map +1 -1
- package/src/lib/form/form.service.d.ts +2 -1
- package/src/lib/form/form.service.js +10 -5
- package/src/lib/form/form.service.js.map +1 -1
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js +22 -2
- 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.errors.d.ts +11 -0
- package/src/lib/form-data-source/form-data-source.errors.js +14 -1
- package/src/lib/form-data-source/form-data-source.errors.js.map +1 -1
- package/src/lib/form-data-source/form-data-source.service.d.ts +6 -0
- package/src/lib/form-data-source/form-data-source.service.js +37 -3
- package/src/lib/form-data-source/form-data-source.service.js.map +1 -1
- package/src/lib/instance-event/approval-instance-event.entity.d.ts +27 -0
- package/src/lib/instance-event/approval-instance-event.entity.js +93 -0
- package/src/lib/instance-event/approval-instance-event.entity.js.map +1 -0
- package/src/lib/instance-event/index.d.ts +13 -0
- package/src/lib/instance-event/index.js +17 -0
- package/src/lib/instance-event/index.js.map +1 -0
- package/src/lib/instance-event/instance-event.delivery-scheduler.service.d.ts +21 -0
- package/src/lib/instance-event/instance-event.delivery-scheduler.service.js +81 -0
- package/src/lib/instance-event/instance-event.delivery-scheduler.service.js.map +1 -0
- package/src/lib/instance-event/instance-event.delivery.service.d.ts +69 -0
- package/src/lib/instance-event/instance-event.delivery.service.js +259 -0
- package/src/lib/instance-event/instance-event.delivery.service.js.map +1 -0
- package/src/lib/instance-event/instance-event.delivery.subscriber.d.ts +24 -0
- package/src/lib/instance-event/instance-event.delivery.subscriber.js +85 -0
- package/src/lib/instance-event/instance-event.delivery.subscriber.js.map +1 -0
- package/src/lib/instance-event/instance-event.enums.d.ts +12 -0
- package/src/lib/instance-event/instance-event.enums.js +28 -0
- package/src/lib/instance-event/instance-event.enums.js.map +1 -0
- package/src/lib/instance-event/instance-event.module.d.ts +13 -0
- package/src/lib/instance-event/instance-event.module.js +52 -0
- package/src/lib/instance-event/instance-event.module.js.map +1 -0
- package/src/lib/instance-event/instance-event.object.d.ts +24 -0
- package/src/lib/instance-event/instance-event.object.js +73 -0
- package/src/lib/instance-event/instance-event.object.js.map +1 -0
- package/src/lib/instance-event/instance-event.options.d.ts +26 -0
- package/src/lib/instance-event/instance-event.options.js +35 -0
- package/src/lib/instance-event/instance-event.options.js.map +1 -0
- package/src/lib/instance-event/instance-event.resolver.d.ts +10 -0
- package/src/lib/instance-event/instance-event.resolver.js +75 -0
- package/src/lib/instance-event/instance-event.resolver.js.map +1 -0
- package/src/lib/instance-event/instance-event.service.d.ts +18 -0
- package/src/lib/instance-event/instance-event.service.js +37 -0
- package/src/lib/instance-event/instance-event.service.js.map +1 -0
- package/src/lib/instance-event/instance-event.token.d.ts +19 -0
- package/src/lib/instance-event/instance-event.token.js +9 -0
- package/src/lib/instance-event/instance-event.token.js.map +1 -0
- package/src/lib/instance-event/instance-event.types.d.ts +67 -0
- package/src/lib/instance-event/instance-event.types.js +9 -0
- package/src/lib/instance-event/instance-event.types.js.map +1 -0
- package/src/lib/instance-event/instance-event.writer.d.ts +21 -0
- package/src/lib/instance-event/instance-event.writer.js +45 -0
- package/src/lib/instance-event/instance-event.writer.js.map +1 -0
- package/src/lib/migrations/0000000032000-host-integration-round.d.ts +25 -0
- package/src/lib/migrations/0000000032000-host-integration-round.js +104 -0
- package/src/lib/migrations/0000000032000-host-integration-round.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.js +50 -9
- package/src/lib/notification/notification.service.js.map +1 -1
- package/src/lib/template/approval-template-version.entity.d.ts +9 -1
- package/src/lib/template/approval-template-version.entity.js +11 -1
- package/src/lib/template/approval-template-version.entity.js.map +1 -1
- package/src/lib/template/approval-template.entity.d.ts +18 -0
- package/src/lib/template/approval-template.entity.js +23 -0
- package/src/lib/template/approval-template.entity.js.map +1 -1
- package/src/lib/template/dto/approval-template.input.d.ts +21 -0
- package/src/lib/template/dto/approval-template.input.js +38 -0
- package/src/lib/template/dto/approval-template.input.js.map +1 -1
- package/src/lib/template/dto/compose-approval-template.input.d.ts +23 -0
- package/src/lib/template/dto/compose-approval-template.input.js +37 -0
- package/src/lib/template/dto/compose-approval-template.input.js.map +1 -1
- package/src/lib/template/template-key.d.ts +26 -0
- package/src/lib/template/template-key.js +67 -0
- package/src/lib/template/template-key.js.map +1 -0
- package/src/lib/template/template.enums.d.ts +11 -0
- package/src/lib/template/template.enums.js +17 -1
- package/src/lib/template/template.enums.js.map +1 -1
- package/src/lib/template/template.queries.d.ts +3 -2
- package/src/lib/template/template.queries.js +29 -4
- package/src/lib/template/template.queries.js.map +1 -1
- package/src/lib/template/template.service.d.ts +8 -1
- package/src/lib/template/template.service.js +94 -17
- package/src/lib/template/template.service.js.map +1 -1
- package/src/lib/workflow-engine/approver-filled-table-columns.d.ts +91 -0
- package/src/lib/workflow-engine/approver-filled-table-columns.js +301 -0
- package/src/lib/workflow-engine/approver-filled-table-columns.js.map +1 -0
- package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.d.ts +7 -0
- package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js +9 -0
- package/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.js.map +1 -1
- package/src/lib/workflow-engine/index.d.ts +1 -0
- package/src/lib/workflow-engine/index.js +1 -0
- package/src/lib/workflow-engine/index.js.map +1 -1
- package/src/lib/workflow-engine/instance-guard.runner.d.ts +19 -0
- package/src/lib/workflow-engine/instance-guard.runner.js +102 -0
- package/src/lib/workflow-engine/instance-guard.runner.js.map +1 -0
- package/src/lib/workflow-engine/instance-guard.token.d.ts +101 -0
- package/src/lib/workflow-engine/instance-guard.token.js +9 -0
- package/src/lib/workflow-engine/instance-guard.token.js.map +1 -0
- package/src/lib/workflow-engine/missing-form-fields.d.ts +12 -0
- package/src/lib/workflow-engine/missing-form-fields.js +27 -0
- package/src/lib/workflow-engine/missing-form-fields.js.map +1 -0
- package/src/lib/workflow-engine/workflow-engine.module.d.ts +2 -0
- package/src/lib/workflow-engine/workflow-engine.module.js +3 -0
- package/src/lib/workflow-engine/workflow-engine.module.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.mutations.d.ts +1 -1
- package/src/lib/workflow-engine/workflow-engine.mutations.js +8 -3
- package/src/lib/workflow-engine/workflow-engine.mutations.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.queries.d.ts +7 -7
- package/src/lib/workflow-engine/workflow-engine.queries.js +97 -28
- package/src/lib/workflow-engine/workflow-engine.queries.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.service.d.ts +141 -7
- package/src/lib/workflow-engine/workflow-engine.service.js +653 -75
- package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.tokens.d.ts +5 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { FieldAccessFillUnit, FormDataSourceValueSnapshots, FormDefinitionSchema, UserTaskNode, WorkflowDefinition } from '@rytass/bpm-core-shared';
|
|
2
|
+
/**
|
|
3
|
+
* What the user tasks of one workflow let an approver fill (ADR 27 §4(a)),
|
|
4
|
+
* split for a submission.
|
|
5
|
+
*
|
|
6
|
+
* `wholeKeys` are top-level fields granted whole. An end user's value for one
|
|
7
|
+
* is dropped and the field is only shape checked, as before.
|
|
8
|
+
*
|
|
9
|
+
* `openColumnsByTable` maps a table granted only per column to the column keys
|
|
10
|
+
* an approver fills. The table itself stays with the applicant (its rows are
|
|
11
|
+
* theirs to add, and the approver may not change their row structure); only
|
|
12
|
+
* those cells wait for the approver. Nobody can fill them before the approval
|
|
13
|
+
* node, so their required flags do not apply at submission.
|
|
14
|
+
*/
|
|
15
|
+
export interface ApproverFilledDeferral {
|
|
16
|
+
readonly openColumnsByTable: ReadonlyMap<string, ReadonlySet<string>>;
|
|
17
|
+
readonly wholeKeys: ReadonlySet<string>;
|
|
18
|
+
}
|
|
19
|
+
type FormRow = Readonly<Record<string, unknown>>;
|
|
20
|
+
export declare const readApproverFilledDeferral: (definition: WorkflowDefinition) => ApproverFilledDeferral;
|
|
21
|
+
/**
|
|
22
|
+
* The schema a submission is validated against: each open column of a
|
|
23
|
+
* deferred table is not required. Its type and a host-supplied value are still
|
|
24
|
+
* checked, and the table's own rules (`minRows`, `maxRows`) are untouched.
|
|
25
|
+
*/
|
|
26
|
+
export declare const projectOpenColumnsOptional: (schema: FormDefinitionSchema, deferral: ApproverFilledDeferral) => FormDefinitionSchema;
|
|
27
|
+
/**
|
|
28
|
+
* Settles the open cells of each row of a deferred table. The submitted cell
|
|
29
|
+
* is dropped. The stored cell comes back only for a row the stored data has
|
|
30
|
+
* that cell on, and only when the applicant's own cells on that row equal the
|
|
31
|
+
* stored row's at the same position. Rows are matched by position (no row id),
|
|
32
|
+
* so a reordered, deleted or inserted row that now sits where a different row
|
|
33
|
+
* was would otherwise inherit an approver's value that judged another record.
|
|
34
|
+
* Such a row keeps no open cell and the later approver fills it again. A row
|
|
35
|
+
* past the stored length gets none. `stored` is `null` on a first submission,
|
|
36
|
+
* so no open cell survives it.
|
|
37
|
+
*/
|
|
38
|
+
export declare const applyOpenColumnCells: (formData: FormRow, stored: FormRow | null, deferral: ApproverFilledDeferral) => FormRow;
|
|
39
|
+
export declare const APPROVER_FILL_ERROR_CODES: {
|
|
40
|
+
readonly CELL_LOCKED: "FORM_FIELD_ACCESS_CELL_LOCKED";
|
|
41
|
+
readonly DEPENDENT_COLUMN_STALE: "FORM_FIELD_ACCESS_DEPENDENT_COLUMN_STALE";
|
|
42
|
+
readonly TABLE_ROWS_LOCKED: "FORM_FIELD_ACCESS_TABLE_ROWS_LOCKED";
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Fails closed when an approver changes a column that a column the approver
|
|
46
|
+
* may not fill reads (ADR 27 §4.3). The dependent column keeps its stored value
|
|
47
|
+
* and is not re-resolved, so a changed source would leave it stale. Current
|
|
48
|
+
* publish lint rejects such a template; this guards templates published before
|
|
49
|
+
* that rule. A dependent that is open to the same node is re-resolved at
|
|
50
|
+
* decide, so it is not a break.
|
|
51
|
+
*/
|
|
52
|
+
export declare const assertDependentColumnsFrozen: (schema: FormDefinitionSchema | null, node: UserTaskNode, storedFormData: Readonly<Record<string, unknown>>, mergedFormData: Readonly<Record<string, unknown>>) => void;
|
|
53
|
+
type ColumnFill = FieldAccessFillUnit['fill'];
|
|
54
|
+
/**
|
|
55
|
+
* The table columns one user task lets its approver fill (ADR 27 §4(a)), keyed
|
|
56
|
+
* by table, each with its fill. A table granted whole in the same node is left
|
|
57
|
+
* out: that grant is the whole-field path and is checked as before.
|
|
58
|
+
*/
|
|
59
|
+
export type NodeColumnFillMap = ReadonlyMap<string, ReadonlyMap<string, ColumnFill>>;
|
|
60
|
+
export declare const readNodeColumnFillMap: (node: UserTaskNode) => NodeColumnFillMap;
|
|
61
|
+
/**
|
|
62
|
+
* The schema the decide path validates against: each open column this node
|
|
63
|
+
* grants REQUIRED is required. Its own `required` flag is kept as well, so a
|
|
64
|
+
* column the template already requires stays required.
|
|
65
|
+
*/
|
|
66
|
+
export declare const projectNodeOpenColumnsRequired: (schema: FormDefinitionSchema, columnFillMap: NodeColumnFillMap) => FormDefinitionSchema;
|
|
67
|
+
/**
|
|
68
|
+
* Settles an approver's payload against the stored form data, table by table
|
|
69
|
+
* (ADR 27 §4(a)). The row count and order must match the stored rows, and each
|
|
70
|
+
* row's applicant cells must match the stored row at that position. Only the
|
|
71
|
+
* open cells are taken from the payload. Other fields pass through unchanged.
|
|
72
|
+
*/
|
|
73
|
+
export declare const settleColumnFillPayload: (payload: FormRow, stored: FormRow, columnFillMap: NodeColumnFillMap) => FormRow;
|
|
74
|
+
/**
|
|
75
|
+
* The schema narrowed to the open cells an approver fills that take a data
|
|
76
|
+
* source (ADR 27 §4(b)): one table per column-mode table with at least one such
|
|
77
|
+
* cell, keeping only those columns. A ROW_FIELD binding reads its value from
|
|
78
|
+
* the same row of the form data, so the narrowed schema needs no other column.
|
|
79
|
+
*/
|
|
80
|
+
export declare const readOpenDataSourceCellSchema: (schema: FormDefinitionSchema, columnFillMap: NodeColumnFillMap) => FormDefinitionSchema;
|
|
81
|
+
/**
|
|
82
|
+
* The snapshots without the cells of `cellSchema`: the open data-source cells
|
|
83
|
+
* are re-resolved at decide time, so their stored snapshots must not survive
|
|
84
|
+
* into the merge. Other rows, other columns and whole-field snapshots are kept.
|
|
85
|
+
* This is not `readSnapshotWithoutFields`, which would also drop the applicant's
|
|
86
|
+
* own cells of the same table.
|
|
87
|
+
*/
|
|
88
|
+
export declare const readSnapshotWithoutOpenCells: (snapshots: FormDataSourceValueSnapshots | null | undefined, cellSchema: FormDefinitionSchema) => FormDataSourceValueSnapshots;
|
|
89
|
+
/** Only the snapshots of the open cells of `cellSchema`, the complement of the above. */
|
|
90
|
+
export declare const readOpenCellSnapshots: (snapshots: FormDataSourceValueSnapshots, cellSchema: FormDefinitionSchema) => FormDataSourceValueSnapshots;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readOpenCellSnapshots = exports.readSnapshotWithoutOpenCells = exports.readOpenDataSourceCellSchema = exports.settleColumnFillPayload = exports.projectNodeOpenColumnsRequired = exports.readNodeColumnFillMap = exports.assertDependentColumnsFrozen = exports.APPROVER_FILL_ERROR_CODES = exports.applyOpenColumnCells = exports.projectOpenColumnsOptional = exports.readApproverFilledDeferral = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const bpm_core_shared_1 = require("@rytass/bpm-core-shared");
|
|
6
|
+
const form_data_fingerprint_1 = require("./form-data-fingerprint");
|
|
7
|
+
const hasOwn = (target, key) => Object.prototype.hasOwnProperty.call(target, key);
|
|
8
|
+
const isFormRow = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
const isUserTaskNode = (node) => node.type === 'userTask';
|
|
10
|
+
const readApproverFilledDeferral = (definition) => {
|
|
11
|
+
const units = definition.nodes
|
|
12
|
+
.filter(isUserTaskNode)
|
|
13
|
+
.flatMap((node) => (0, bpm_core_shared_1.readNodeFillUnits)(node));
|
|
14
|
+
const wholeKeys = new Set(units
|
|
15
|
+
.filter((unit) => unit.columnKey === null)
|
|
16
|
+
.map((unit) => unit.fieldKey));
|
|
17
|
+
const columnPairs = units.flatMap((unit) => unit.columnKey === null || wholeKeys.has(unit.fieldKey)
|
|
18
|
+
? []
|
|
19
|
+
: [[unit.fieldKey, unit.columnKey]]);
|
|
20
|
+
const openColumnsByTable = new Map([...new Set(columnPairs.map(([fieldKey]) => fieldKey))].map((fieldKey) => [
|
|
21
|
+
fieldKey,
|
|
22
|
+
new Set(columnPairs
|
|
23
|
+
.filter(([key]) => key === fieldKey)
|
|
24
|
+
.map(([, columnKey]) => columnKey)),
|
|
25
|
+
]));
|
|
26
|
+
return { openColumnsByTable, wholeKeys };
|
|
27
|
+
};
|
|
28
|
+
exports.readApproverFilledDeferral = readApproverFilledDeferral;
|
|
29
|
+
/**
|
|
30
|
+
* The schema a submission is validated against: each open column of a
|
|
31
|
+
* deferred table is not required. Its type and a host-supplied value are still
|
|
32
|
+
* checked, and the table's own rules (`minRows`, `maxRows`) are untouched.
|
|
33
|
+
*/
|
|
34
|
+
const projectOpenColumnsOptional = (schema, deferral) => ({
|
|
35
|
+
...schema,
|
|
36
|
+
fields: schema.fields.map((field) => {
|
|
37
|
+
const openColumns = (0, bpm_core_shared_1.isTableFieldDefinition)(field)
|
|
38
|
+
? deferral.openColumnsByTable.get(field.fieldKey)
|
|
39
|
+
: undefined;
|
|
40
|
+
if (!(0, bpm_core_shared_1.isTableFieldDefinition)(field) || openColumns === undefined) {
|
|
41
|
+
return field;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
...field,
|
|
45
|
+
columns: field.columns.map((column) => openColumns.has(column.fieldKey)
|
|
46
|
+
? { ...column, required: false }
|
|
47
|
+
: column),
|
|
48
|
+
};
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
exports.projectOpenColumnsOptional = projectOpenColumnsOptional;
|
|
52
|
+
/**
|
|
53
|
+
* The cells of a row the applicant owns: every column that is not open.
|
|
54
|
+
*/
|
|
55
|
+
const readApplicantCells = (row, openColumns) => Object.fromEntries(Object.entries(row).filter(([column]) => !openColumns.has(column)));
|
|
56
|
+
/**
|
|
57
|
+
* Settles the open cells of each row of a deferred table. The submitted cell
|
|
58
|
+
* is dropped. The stored cell comes back only for a row the stored data has
|
|
59
|
+
* that cell on, and only when the applicant's own cells on that row equal the
|
|
60
|
+
* stored row's at the same position. Rows are matched by position (no row id),
|
|
61
|
+
* so a reordered, deleted or inserted row that now sits where a different row
|
|
62
|
+
* was would otherwise inherit an approver's value that judged another record.
|
|
63
|
+
* Such a row keeps no open cell and the later approver fills it again. A row
|
|
64
|
+
* past the stored length gets none. `stored` is `null` on a first submission,
|
|
65
|
+
* so no open cell survives it.
|
|
66
|
+
*/
|
|
67
|
+
const applyOpenColumnCells = (formData, stored, deferral) => Object.fromEntries(Object.entries(formData).map(([key, value]) => {
|
|
68
|
+
const openColumns = deferral.openColumnsByTable.get(key);
|
|
69
|
+
if (openColumns === undefined || !Array.isArray(value)) {
|
|
70
|
+
return [key, value];
|
|
71
|
+
}
|
|
72
|
+
const storedValue = stored === null ? undefined : stored[key];
|
|
73
|
+
const storedRows = Array.isArray(storedValue)
|
|
74
|
+
? storedValue
|
|
75
|
+
: [];
|
|
76
|
+
return [
|
|
77
|
+
key,
|
|
78
|
+
value.map((row, index) => {
|
|
79
|
+
if (!isFormRow(row)) {
|
|
80
|
+
return row;
|
|
81
|
+
}
|
|
82
|
+
const kept = readApplicantCells(row, openColumns);
|
|
83
|
+
const storedRow = storedRows[index];
|
|
84
|
+
if (!isFormRow(storedRow)) {
|
|
85
|
+
return kept;
|
|
86
|
+
}
|
|
87
|
+
const sameRecord = (0, form_data_fingerprint_1.computeStableValueFingerprint)(kept) ===
|
|
88
|
+
(0, form_data_fingerprint_1.computeStableValueFingerprint)(readApplicantCells(storedRow, openColumns));
|
|
89
|
+
if (!sameRecord) {
|
|
90
|
+
return kept;
|
|
91
|
+
}
|
|
92
|
+
const restored = Object.fromEntries([...openColumns]
|
|
93
|
+
.filter((column) => hasOwn(storedRow, column))
|
|
94
|
+
.map((column) => [
|
|
95
|
+
column,
|
|
96
|
+
storedRow[column],
|
|
97
|
+
]));
|
|
98
|
+
return { ...kept, ...restored };
|
|
99
|
+
}),
|
|
100
|
+
];
|
|
101
|
+
}));
|
|
102
|
+
exports.applyOpenColumnCells = applyOpenColumnCells;
|
|
103
|
+
exports.APPROVER_FILL_ERROR_CODES = {
|
|
104
|
+
CELL_LOCKED: 'FORM_FIELD_ACCESS_CELL_LOCKED',
|
|
105
|
+
DEPENDENT_COLUMN_STALE: 'FORM_FIELD_ACCESS_DEPENDENT_COLUMN_STALE',
|
|
106
|
+
TABLE_ROWS_LOCKED: 'FORM_FIELD_ACCESS_TABLE_ROWS_LOCKED',
|
|
107
|
+
};
|
|
108
|
+
const readColumnFingerprints = (rows, columnKey) => Array.isArray(rows)
|
|
109
|
+
? rows.map((row) => (0, form_data_fingerprint_1.computeStableValueFingerprint)(isFormRow(row) ? row[columnKey] : undefined))
|
|
110
|
+
: [];
|
|
111
|
+
/**
|
|
112
|
+
* Fails closed when an approver changes a column that a column the approver
|
|
113
|
+
* may not fill reads (ADR 27 §4.3). The dependent column keeps its stored value
|
|
114
|
+
* and is not re-resolved, so a changed source would leave it stale. Current
|
|
115
|
+
* publish lint rejects such a template; this guards templates published before
|
|
116
|
+
* that rule. A dependent that is open to the same node is re-resolved at
|
|
117
|
+
* decide, so it is not a break.
|
|
118
|
+
*/
|
|
119
|
+
const assertDependentColumnsFrozen = (schema, node, storedFormData, mergedFormData) => {
|
|
120
|
+
const stale = (0, bpm_core_shared_1.readFieldAccessDependencyBreaks)(schema, (0, bpm_core_shared_1.readNodeFillUnits)(node)).find(({ fieldKey, sourceColumnKey }) => readColumnFingerprints(storedFormData[fieldKey], sourceColumnKey).join('\n') !==
|
|
121
|
+
readColumnFingerprints(mergedFormData[fieldKey], sourceColumnKey).join('\n'));
|
|
122
|
+
if (stale !== undefined) {
|
|
123
|
+
throw new common_1.ConflictException({
|
|
124
|
+
code: exports.APPROVER_FILL_ERROR_CODES.DEPENDENT_COLUMN_STALE,
|
|
125
|
+
message: `Column ${stale.sourceColumnKey} of table ${stale.fieldKey} is read by column ${stale.dependentColumnKey}, which an approver may not change at this step`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
exports.assertDependentColumnsFrozen = assertDependentColumnsFrozen;
|
|
130
|
+
const readNodeColumnFillMap = (node) => {
|
|
131
|
+
const units = (0, bpm_core_shared_1.readNodeFillUnits)(node);
|
|
132
|
+
const wholeKeys = new Set(units
|
|
133
|
+
.filter((unit) => unit.columnKey === null)
|
|
134
|
+
.map((unit) => unit.fieldKey));
|
|
135
|
+
const columnUnits = units.filter((unit) => unit.columnKey !== null && !wholeKeys.has(unit.fieldKey));
|
|
136
|
+
return new Map([...new Set(columnUnits.map((unit) => unit.fieldKey))].map((fieldKey) => [
|
|
137
|
+
fieldKey,
|
|
138
|
+
new Map(columnUnits
|
|
139
|
+
.filter((unit) => unit.fieldKey === fieldKey)
|
|
140
|
+
.map((unit) => [
|
|
141
|
+
unit.columnKey,
|
|
142
|
+
unit.fill,
|
|
143
|
+
])),
|
|
144
|
+
]));
|
|
145
|
+
};
|
|
146
|
+
exports.readNodeColumnFillMap = readNodeColumnFillMap;
|
|
147
|
+
/**
|
|
148
|
+
* The schema the decide path validates against: each open column this node
|
|
149
|
+
* grants REQUIRED is required. Its own `required` flag is kept as well, so a
|
|
150
|
+
* column the template already requires stays required.
|
|
151
|
+
*/
|
|
152
|
+
const projectNodeOpenColumnsRequired = (schema, columnFillMap) => ({
|
|
153
|
+
...schema,
|
|
154
|
+
fields: schema.fields.map((field) => {
|
|
155
|
+
const columnFills = (0, bpm_core_shared_1.isTableFieldDefinition)(field)
|
|
156
|
+
? columnFillMap.get(field.fieldKey)
|
|
157
|
+
: undefined;
|
|
158
|
+
if (!(0, bpm_core_shared_1.isTableFieldDefinition)(field) || columnFills === undefined) {
|
|
159
|
+
return field;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
...field,
|
|
163
|
+
columns: field.columns.map((column) => columnFills.get(column.fieldKey) === 'REQUIRED' && !column.required
|
|
164
|
+
? { ...column, required: true }
|
|
165
|
+
: column),
|
|
166
|
+
};
|
|
167
|
+
}),
|
|
168
|
+
});
|
|
169
|
+
exports.projectNodeOpenColumnsRequired = projectNodeOpenColumnsRequired;
|
|
170
|
+
const cellValue = (row, columnKey) => row[columnKey] ?? null;
|
|
171
|
+
/**
|
|
172
|
+
* The first applicant cell of `row` that differs from the stored row's, or
|
|
173
|
+
* `null` when every applicant cell is the same. A missing cell counts as null.
|
|
174
|
+
*/
|
|
175
|
+
const readFirstMismatchedApplicantCell = (row, storedRow, openColumns) => {
|
|
176
|
+
const applicant = readApplicantCells(row, openColumns);
|
|
177
|
+
const storedApplicant = readApplicantCells(storedRow, openColumns);
|
|
178
|
+
return ([
|
|
179
|
+
...new Set([...Object.keys(applicant), ...Object.keys(storedApplicant)]),
|
|
180
|
+
].find((columnKey) => (0, form_data_fingerprint_1.computeStableValueFingerprint)(cellValue(applicant, columnKey)) !==
|
|
181
|
+
(0, form_data_fingerprint_1.computeStableValueFingerprint)(cellValue(storedApplicant, columnKey))) ?? null);
|
|
182
|
+
};
|
|
183
|
+
const rowsLocked = (fieldKey) => new common_1.ConflictException({
|
|
184
|
+
code: exports.APPROVER_FILL_ERROR_CODES.TABLE_ROWS_LOCKED,
|
|
185
|
+
message: `Table ${fieldKey} has fixed rows at this step; an approver may only fill its open columns`,
|
|
186
|
+
});
|
|
187
|
+
const settleTableRows = (fieldKey, rows, storedValue, openColumns) => {
|
|
188
|
+
const storedRows = Array.isArray(storedValue)
|
|
189
|
+
? storedValue
|
|
190
|
+
: [];
|
|
191
|
+
if (rows === null) {
|
|
192
|
+
if (storedRows.length === 0) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
throw rowsLocked(fieldKey);
|
|
196
|
+
}
|
|
197
|
+
// Not an array: the shape check in validation answers it with TYPE.
|
|
198
|
+
if (!Array.isArray(rows)) {
|
|
199
|
+
return rows;
|
|
200
|
+
}
|
|
201
|
+
if (rows.length !== storedRows.length) {
|
|
202
|
+
throw rowsLocked(fieldKey);
|
|
203
|
+
}
|
|
204
|
+
return rows.map((row, index) => {
|
|
205
|
+
const storedRow = storedRows[index];
|
|
206
|
+
if (!isFormRow(row) || !isFormRow(storedRow)) {
|
|
207
|
+
throw rowsLocked(fieldKey);
|
|
208
|
+
}
|
|
209
|
+
const mismatch = readFirstMismatchedApplicantCell(row, storedRow, openColumns);
|
|
210
|
+
if (mismatch !== null) {
|
|
211
|
+
// A row whose applicant cells match another stored row was moved, which
|
|
212
|
+
// changes the row order. Reporting it as a changed cell would hide that.
|
|
213
|
+
const movedElsewhere = storedRows.some((other, otherIndex) => otherIndex !== index &&
|
|
214
|
+
isFormRow(other) &&
|
|
215
|
+
readFirstMismatchedApplicantCell(row, other, openColumns) === null);
|
|
216
|
+
if (movedElsewhere) {
|
|
217
|
+
throw rowsLocked(fieldKey);
|
|
218
|
+
}
|
|
219
|
+
throw new common_1.ConflictException({
|
|
220
|
+
code: exports.APPROVER_FILL_ERROR_CODES.CELL_LOCKED,
|
|
221
|
+
message: `Column ${mismatch} of table ${fieldKey} row ${index + 1} is not open to approvers`,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
// The applicant's cells come from the stored row, so a payload can only
|
|
225
|
+
// change the open cells. Any other key the payload sent is dropped.
|
|
226
|
+
return {
|
|
227
|
+
...readApplicantCells(storedRow, openColumns),
|
|
228
|
+
...Object.fromEntries([...openColumns].map((columnKey) => [
|
|
229
|
+
columnKey,
|
|
230
|
+
cellValue(row, columnKey),
|
|
231
|
+
])),
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Settles an approver's payload against the stored form data, table by table
|
|
237
|
+
* (ADR 27 §4(a)). The row count and order must match the stored rows, and each
|
|
238
|
+
* row's applicant cells must match the stored row at that position. Only the
|
|
239
|
+
* open cells are taken from the payload. Other fields pass through unchanged.
|
|
240
|
+
*/
|
|
241
|
+
const settleColumnFillPayload = (payload, stored, columnFillMap) => Object.fromEntries(Object.entries(payload).map(([fieldKey, value]) => {
|
|
242
|
+
const columnFills = columnFillMap.get(fieldKey);
|
|
243
|
+
return columnFills === undefined
|
|
244
|
+
? [fieldKey, value]
|
|
245
|
+
: [
|
|
246
|
+
fieldKey,
|
|
247
|
+
settleTableRows(fieldKey, value, hasOwn(stored, fieldKey) ? stored[fieldKey] : undefined, new Set(columnFills.keys())),
|
|
248
|
+
];
|
|
249
|
+
}));
|
|
250
|
+
exports.settleColumnFillPayload = settleColumnFillPayload;
|
|
251
|
+
/**
|
|
252
|
+
* The schema narrowed to the open cells an approver fills that take a data
|
|
253
|
+
* source (ADR 27 §4(b)): one table per column-mode table with at least one such
|
|
254
|
+
* cell, keeping only those columns. A ROW_FIELD binding reads its value from
|
|
255
|
+
* the same row of the form data, so the narrowed schema needs no other column.
|
|
256
|
+
*/
|
|
257
|
+
const readOpenDataSourceCellSchema = (schema, columnFillMap) => ({
|
|
258
|
+
...schema,
|
|
259
|
+
fields: schema.fields.flatMap((field) => {
|
|
260
|
+
const columnFills = (0, bpm_core_shared_1.isTableFieldDefinition)(field)
|
|
261
|
+
? columnFillMap.get(field.fieldKey)
|
|
262
|
+
: undefined;
|
|
263
|
+
if (!(0, bpm_core_shared_1.isTableFieldDefinition)(field) || columnFills === undefined) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
const columns = field.columns.flatMap((column) => columnFills.has(column.fieldKey) &&
|
|
267
|
+
(0, bpm_core_shared_1.isFormDataSourceFieldDefinition)(column)
|
|
268
|
+
? [column]
|
|
269
|
+
: []);
|
|
270
|
+
return columns.length === 0 ? [] : [{ ...field, columns }];
|
|
271
|
+
}),
|
|
272
|
+
});
|
|
273
|
+
exports.readOpenDataSourceCellSchema = readOpenDataSourceCellSchema;
|
|
274
|
+
/** Matches a cell snapshot key, `<tableKey>[<rowIndex>].<columnKey>`. */
|
|
275
|
+
const CELL_SNAPSHOT_KEY_PATTERN = /^([^[\].]+)\[\d+\]\.([^[\].]+)$/;
|
|
276
|
+
const readOpenCellKeys = (cellSchema) => new Set(cellSchema.fields.flatMap((field) => (0, bpm_core_shared_1.isTableFieldDefinition)(field)
|
|
277
|
+
? field.columns.map((column) => `${field.fieldKey}.${column.fieldKey}`)
|
|
278
|
+
: []));
|
|
279
|
+
const isOpenCellSnapshotKey = (key, openCellKeys) => {
|
|
280
|
+
const match = CELL_SNAPSHOT_KEY_PATTERN.exec(key);
|
|
281
|
+
return match !== null && openCellKeys.has(`${match[1]}.${match[2]}`);
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* The snapshots without the cells of `cellSchema`: the open data-source cells
|
|
285
|
+
* are re-resolved at decide time, so their stored snapshots must not survive
|
|
286
|
+
* into the merge. Other rows, other columns and whole-field snapshots are kept.
|
|
287
|
+
* This is not `readSnapshotWithoutFields`, which would also drop the applicant's
|
|
288
|
+
* own cells of the same table.
|
|
289
|
+
*/
|
|
290
|
+
const readSnapshotWithoutOpenCells = (snapshots, cellSchema) => {
|
|
291
|
+
const openCellKeys = readOpenCellKeys(cellSchema);
|
|
292
|
+
return Object.fromEntries(Object.entries(snapshots ?? {}).filter(([key]) => !isOpenCellSnapshotKey(key, openCellKeys)));
|
|
293
|
+
};
|
|
294
|
+
exports.readSnapshotWithoutOpenCells = readSnapshotWithoutOpenCells;
|
|
295
|
+
/** Only the snapshots of the open cells of `cellSchema`, the complement of the above. */
|
|
296
|
+
const readOpenCellSnapshots = (snapshots, cellSchema) => {
|
|
297
|
+
const openCellKeys = readOpenCellKeys(cellSchema);
|
|
298
|
+
return Object.fromEntries(Object.entries(snapshots).filter(([key]) => isOpenCellSnapshotKey(key, openCellKeys)));
|
|
299
|
+
};
|
|
300
|
+
exports.readOpenCellSnapshots = readOpenCellSnapshots;
|
|
301
|
+
//# sourceMappingURL=approver-filled-table-columns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approver-filled-table-columns.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/workflow-engine/approver-filled-table-columns.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,4 +3,11 @@ export declare class DryRunApprovalWorkflowInput {
|
|
|
3
3
|
formDataJson: string;
|
|
4
4
|
initiatorMemberId: string;
|
|
5
5
|
initiatorMetadataSnapshotJson: string | null;
|
|
6
|
+
/**
|
|
7
|
+
* The form schema of the template being tried. Used only when the host turns
|
|
8
|
+
* on `expressionMissingFormFieldsAsNull`, so the dry run fills unfilled
|
|
9
|
+
* fields the way a real case would (ADR 27 §3); without it the form data is
|
|
10
|
+
* read as given.
|
|
11
|
+
*/
|
|
12
|
+
formSchemaJson?: string | null;
|
|
6
13
|
}
|
|
@@ -28,6 +28,15 @@ tslib_1.__decorate([
|
|
|
28
28
|
(0, class_validator_1.IsString)(),
|
|
29
29
|
tslib_1.__metadata("design:type", Object)
|
|
30
30
|
], DryRunApprovalWorkflowInput.prototype, "initiatorMetadataSnapshotJson", void 0);
|
|
31
|
+
tslib_1.__decorate([
|
|
32
|
+
(0, graphql_1.Field)(() => String, {
|
|
33
|
+
description: 'Form schema JSON of the template being tried. Only read when the host enables expressionMissingFormFieldsAsNull: unfilled top-level fields are then read as null ([] for a table), as in a real case.',
|
|
34
|
+
nullable: true,
|
|
35
|
+
}),
|
|
36
|
+
(0, class_validator_1.IsOptional)(),
|
|
37
|
+
(0, class_validator_1.IsString)(),
|
|
38
|
+
tslib_1.__metadata("design:type", Object)
|
|
39
|
+
], DryRunApprovalWorkflowInput.prototype, "formSchemaJson", void 0);
|
|
31
40
|
exports.DryRunApprovalWorkflowInput = DryRunApprovalWorkflowInput = tslib_1.__decorate([
|
|
32
41
|
(0, graphql_1.InputType)()
|
|
33
42
|
], DryRunApprovalWorkflowInput);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dry-run-approval-workflow.input.js","sourceRoot":"","sources":["../../../../../../../libs/bpm-core/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.ts"],"names":[],"mappings":";;;;AAAA,6CAAmD;AACnD,qDAAuD;AAGhD,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;
|
|
1
|
+
{"version":3,"file":"dry-run-approval-workflow.input.js","sourceRoot":"","sources":["../../../../../../../libs/bpm-core/src/lib/workflow-engine/dto/dry-run-approval-workflow.input.ts"],"names":[],"mappings":";;;;AAAA,6CAAmD;AACnD,qDAAuD;AAGhD,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;CAgCvC,CAAA;AAhCY,kEAA2B;AAGtC;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,0BAAQ,GAAE;;2EACqB;AAIhC;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,0BAAQ,GAAE;;iEACW;AAItB;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,0BAAQ,GAAE;;sEACgB;AAK3B;IAHC,IAAA,eAAK,EAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;kFACmC;AAe9C;IAPC,IAAA,eAAK,EAAC,GAAG,EAAE,CAAC,MAAM,EAAE;QACnB,WAAW,EACT,uMAAuM;QACzM,QAAQ,EAAE,IAAI;KACf,CAAC;IACD,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;mEACoB;sCA/BpB,2BAA2B;IADvC,IAAA,mBAAS,GAAE;GACC,2BAA2B,CAgCvC"}
|
|
@@ -13,6 +13,7 @@ export * from './dto/reassign-task.input';
|
|
|
13
13
|
export * from './dto/resubmit-approval-instance.input';
|
|
14
14
|
export * from './dto/submit-approval-instance.input';
|
|
15
15
|
export * from './initiator-custom-fields-resolver.token';
|
|
16
|
+
export * from './instance-guard.token';
|
|
16
17
|
export * from './task-candidate.entity';
|
|
17
18
|
export * from './task-decision.entity';
|
|
18
19
|
export * from './task.entity';
|
|
@@ -16,6 +16,7 @@ tslib_1.__exportStar(require("./dto/reassign-task.input"), exports);
|
|
|
16
16
|
tslib_1.__exportStar(require("./dto/resubmit-approval-instance.input"), exports);
|
|
17
17
|
tslib_1.__exportStar(require("./dto/submit-approval-instance.input"), exports);
|
|
18
18
|
tslib_1.__exportStar(require("./initiator-custom-fields-resolver.token"), exports);
|
|
19
|
+
tslib_1.__exportStar(require("./instance-guard.token"), exports);
|
|
19
20
|
tslib_1.__exportStar(require("./task-candidate.entity"), exports);
|
|
20
21
|
tslib_1.__exportStar(require("./task-decision.entity"), exports);
|
|
21
22
|
tslib_1.__exportStar(require("./task.entity"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/workflow-engine/index.ts"],"names":[],"mappings":";;;AAAA,gEAAsC;AACtC,mEAAyC;AACzC,wDAA8B;AAC9B,+EAAqD;AACrD,qEAA2C;AAC3C,yEAA+C;AAC/C,mEAAyC;AACzC,+EAAqD;AACrD,kEAAwC;AACxC,gFAAsD;AACtD,4EAAkD;AAClD,oEAA0C;AAC1C,iFAAuD;AACvD,+EAAqD;AACrD,mFAAyD;AACzD,kEAAwC;AACxC,iEAAuC;AACvC,wDAA8B;AAC9B,qEAA2C;AAC3C,yEAA+C;AAC/C,oEAA0C;AAC1C,8EAAoD;AACpD,kEAAwC;AACxC,mEAAyC;AACzC,oEAA0C;AAC1C,mEAAyC;AACzC,mFAAyD;AACzD,kEAAwC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/workflow-engine/index.ts"],"names":[],"mappings":";;;AAAA,gEAAsC;AACtC,mEAAyC;AACzC,wDAA8B;AAC9B,+EAAqD;AACrD,qEAA2C;AAC3C,yEAA+C;AAC/C,mEAAyC;AACzC,+EAAqD;AACrD,kEAAwC;AACxC,gFAAsD;AACtD,4EAAkD;AAClD,oEAA0C;AAC1C,iFAAuD;AACvD,+EAAqD;AACrD,mFAAyD;AACzD,iEAAuC;AACvC,kEAAwC;AACxC,iEAAuC;AACvC,wDAA8B;AAC9B,qEAA2C;AAC3C,yEAA+C;AAC/C,oEAA0C;AAC1C,8EAAoD;AACpD,kEAAwC;AACxC,mEAAyC;AACzC,oEAA0C;AAC1C,mEAAyC;AACzC,mFAAyD;AACzD,kEAAwC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BPMInstanceGuard, BPMInstanceGuardInput } from './instance-guard.token';
|
|
2
|
+
/** Default for `instanceGuardTimeoutMs` (ADR 27 §2.2). */
|
|
3
|
+
export declare const BPM_INSTANCE_GUARD_DEFAULT_TIMEOUT_MS = 5000;
|
|
4
|
+
export declare const BPM_INSTANCE_GUARD_TIMEOUT_CODE = "BPM_INSTANCE_GUARD_TIMEOUT";
|
|
5
|
+
export declare const BPM_INSTANCE_GUARD_FAILED_CODE = "BPM_INSTANCE_GUARD_FAILED";
|
|
6
|
+
export declare function isInstanceGuardError(error: unknown): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Runs the host guard for one engine path and throws if the path must stop.
|
|
9
|
+
*
|
|
10
|
+
* Returns normally only when the guard answered with an empty list in time.
|
|
11
|
+
* Call it inside the engine transaction, after the case lock is taken, so a
|
|
12
|
+
* throw rolls the whole change back.
|
|
13
|
+
*
|
|
14
|
+
* - non-empty issues: 400 `createFormDataBadRequest`
|
|
15
|
+
* - no answer within `timeoutMs`: 503 `BPM_INSTANCE_GUARD_TIMEOUT` (fail closed)
|
|
16
|
+
* - a thrown `HttpException`: rethrown unchanged
|
|
17
|
+
* - any other error, or a malformed answer: 503 `BPM_INSTANCE_GUARD_FAILED`
|
|
18
|
+
*/
|
|
19
|
+
export declare function runInstanceGuard(guard: BPMInstanceGuard, input: BPMInstanceGuardInput, timeoutMs: number): Promise<void>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BPM_INSTANCE_GUARD_FAILED_CODE = exports.BPM_INSTANCE_GUARD_TIMEOUT_CODE = exports.BPM_INSTANCE_GUARD_DEFAULT_TIMEOUT_MS = void 0;
|
|
4
|
+
exports.isInstanceGuardError = isInstanceGuardError;
|
|
5
|
+
exports.runInstanceGuard = runInstanceGuard;
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const form_data_issue_1 = require("../form/form-data-issue");
|
|
8
|
+
/** Default for `instanceGuardTimeoutMs` (ADR 27 §2.2). */
|
|
9
|
+
exports.BPM_INSTANCE_GUARD_DEFAULT_TIMEOUT_MS = 5000;
|
|
10
|
+
exports.BPM_INSTANCE_GUARD_TIMEOUT_CODE = 'BPM_INSTANCE_GUARD_TIMEOUT';
|
|
11
|
+
exports.BPM_INSTANCE_GUARD_FAILED_CODE = 'BPM_INSTANCE_GUARD_FAILED';
|
|
12
|
+
/**
|
|
13
|
+
* Every error the guard path raises: the 400 for refused issues, the 503 for a
|
|
14
|
+
* timeout or a failing guard, and an `HttpException` the host threw itself.
|
|
15
|
+
* Lets a caller tell a guard refusal apart from any other failure without
|
|
16
|
+
* matching on messages.
|
|
17
|
+
*/
|
|
18
|
+
const instanceGuardErrors = new WeakSet();
|
|
19
|
+
function markInstanceGuardError(error) {
|
|
20
|
+
instanceGuardErrors.add(error);
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
function isInstanceGuardError(error) {
|
|
24
|
+
return typeof error === 'object' && error !== null
|
|
25
|
+
? instanceGuardErrors.has(error)
|
|
26
|
+
: false;
|
|
27
|
+
}
|
|
28
|
+
function createGuardUnavailable(code, message) {
|
|
29
|
+
return markInstanceGuardError(new common_1.ServiceUnavailableException({
|
|
30
|
+
code,
|
|
31
|
+
error: 'Service Unavailable',
|
|
32
|
+
message,
|
|
33
|
+
statusCode: 503,
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
function isGuardIssue(value) {
|
|
37
|
+
if (typeof value !== 'object' || value === null) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const issue = value;
|
|
41
|
+
return (typeof issue.message === 'string' &&
|
|
42
|
+
typeof issue.path === 'string' &&
|
|
43
|
+
issue.reason === 'HOST_RULE' &&
|
|
44
|
+
(issue.code === undefined || typeof issue.code === 'string'));
|
|
45
|
+
}
|
|
46
|
+
function readIssueFormDataErrors(issues) {
|
|
47
|
+
return issues.map((issue) => ({
|
|
48
|
+
message: issue.message,
|
|
49
|
+
path: issue.path,
|
|
50
|
+
reason: issue.reason,
|
|
51
|
+
...(issue.code === undefined ? {} : { code: issue.code }),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Runs the host guard for one engine path and throws if the path must stop.
|
|
56
|
+
*
|
|
57
|
+
* Returns normally only when the guard answered with an empty list in time.
|
|
58
|
+
* Call it inside the engine transaction, after the case lock is taken, so a
|
|
59
|
+
* throw rolls the whole change back.
|
|
60
|
+
*
|
|
61
|
+
* - non-empty issues: 400 `createFormDataBadRequest`
|
|
62
|
+
* - no answer within `timeoutMs`: 503 `BPM_INSTANCE_GUARD_TIMEOUT` (fail closed)
|
|
63
|
+
* - a thrown `HttpException`: rethrown unchanged
|
|
64
|
+
* - any other error, or a malformed answer: 503 `BPM_INSTANCE_GUARD_FAILED`
|
|
65
|
+
*/
|
|
66
|
+
async function runInstanceGuard(guard, input, timeoutMs) {
|
|
67
|
+
const timeoutError = markInstanceGuardError(new Error(`BPM_INSTANCE_GUARD_TIMEOUT_${timeoutMs}MS`));
|
|
68
|
+
let timer;
|
|
69
|
+
let issues;
|
|
70
|
+
try {
|
|
71
|
+
issues = await Promise.race([
|
|
72
|
+
Promise.resolve().then(() => guard.check(input)),
|
|
73
|
+
new Promise((_resolve, reject) => {
|
|
74
|
+
timer = setTimeout(() => {
|
|
75
|
+
reject(timeoutError);
|
|
76
|
+
}, timeoutMs);
|
|
77
|
+
}),
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error === timeoutError) {
|
|
82
|
+
throw createGuardUnavailable(exports.BPM_INSTANCE_GUARD_TIMEOUT_CODE, `Instance guard did not answer within ${timeoutMs} ms`);
|
|
83
|
+
}
|
|
84
|
+
if (error instanceof common_1.HttpException) {
|
|
85
|
+
markInstanceGuardError(error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
throw createGuardUnavailable(exports.BPM_INSTANCE_GUARD_FAILED_CODE, 'Instance guard failed');
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
}
|
|
93
|
+
if (!Array.isArray(issues) || !issues.every(isGuardIssue)) {
|
|
94
|
+
throw createGuardUnavailable(exports.BPM_INSTANCE_GUARD_FAILED_CODE, 'Instance guard returned an answer of the wrong shape');
|
|
95
|
+
}
|
|
96
|
+
if (issues.length === 0) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const formDataErrors = readIssueFormDataErrors(issues);
|
|
100
|
+
throw markInstanceGuardError((0, form_data_issue_1.createFormDataBadRequest)((0, form_data_issue_1.readFormDataIssueMessage)(formDataErrors), formDataErrors));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=instance-guard.runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-guard.runner.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/workflow-engine/instance-guard.runner.ts"],"names":[],"mappings":"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"}
|