@miragon/pulse-engine-core 0.0.0-stage → 0.25.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/LICENSE +21 -0
- package/README.md +97 -2
- package/dist/activities.d.ts +31 -0
- package/dist/activities.d.ts.map +1 -0
- package/dist/activities.js +62 -0
- package/dist/activities.js.map +1 -0
- package/dist/advance-plan.d.ts +21 -0
- package/dist/advance-plan.d.ts.map +1 -0
- package/dist/advance-plan.js +192 -0
- package/dist/advance-plan.js.map +1 -0
- package/dist/conditions.d.ts +66 -0
- package/dist/conditions.d.ts.map +1 -0
- package/dist/conditions.js +119 -0
- package/dist/conditions.js.map +1 -0
- package/dist/dates.d.ts +59 -0
- package/dist/dates.d.ts.map +1 -0
- package/dist/dates.js +189 -0
- package/dist/dates.js.map +1 -0
- package/dist/durations.d.ts +4 -0
- package/dist/durations.d.ts.map +1 -0
- package/dist/durations.js +10 -0
- package/dist/durations.js.map +1 -0
- package/dist/engine-status.d.ts +57 -0
- package/dist/engine-status.d.ts.map +1 -0
- package/dist/engine-status.js +193 -0
- package/dist/engine-status.js.map +1 -0
- package/dist/errors.d.ts +101 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/filters.d.ts +53 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +74 -0
- package/dist/filters.js.map +1 -0
- package/dist/findings.d.ts +46 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +105 -0
- package/dist/findings.js.map +1 -0
- package/dist/incident-recovery.d.ts +35 -0
- package/dist/incident-recovery.d.ts.map +1 -0
- package/dist/incident-recovery.js +24 -0
- package/dist/incident-recovery.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +34 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +247 -0
- package/dist/inspect.js.map +1 -0
- package/dist/next.d.ts +26 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +83 -0
- package/dist/next.js.map +1 -0
- package/dist/operations.d.ts +9 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +41 -0
- package/dist/operations.js.map +1 -0
- package/dist/poll.d.ts +24 -0
- package/dist/poll.d.ts.map +1 -0
- package/dist/poll.js +29 -0
- package/dist/poll.js.map +1 -0
- package/dist/port.d.ts +95 -0
- package/dist/port.d.ts.map +1 -0
- package/dist/port.js +113 -0
- package/dist/port.js.map +1 -0
- package/dist/records.d.ts +27 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +58 -0
- package/dist/records.js.map +1 -0
- package/dist/requests.d.ts +24 -0
- package/dist/requests.d.ts.map +1 -0
- package/dist/requests.js +35 -0
- package/dist/requests.js.map +1 -0
- package/dist/retry-plan.d.ts +62 -0
- package/dist/retry-plan.d.ts.map +1 -0
- package/dist/retry-plan.js +140 -0
- package/dist/retry-plan.js.map +1 -0
- package/dist/root-cause.d.ts +17 -0
- package/dist/root-cause.d.ts.map +1 -0
- package/dist/root-cause.js +35 -0
- package/dist/root-cause.js.map +1 -0
- package/dist/select.d.ts +16 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +133 -0
- package/dist/select.js.map +1 -0
- package/dist/snapshot.d.ts +12 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +134 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/sorting.d.ts +20 -0
- package/dist/sorting.d.ts.map +1 -0
- package/dist/sorting.js +17 -0
- package/dist/sorting.js.map +1 -0
- package/dist/status.d.ts +91 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +222 -0
- package/dist/status.js.map +1 -0
- package/dist/testing/fake-port.d.ts +31 -0
- package/dist/testing/fake-port.d.ts.map +1 -0
- package/dist/testing/fake-port.js +50 -0
- package/dist/testing/fake-port.js.map +1 -0
- package/dist/testing/fixture.d.ts +39 -0
- package/dist/testing/fixture.d.ts.map +1 -0
- package/dist/testing/fixture.js +288 -0
- package/dist/testing/fixture.js.map +1 -0
- package/dist/testing/index.d.ts +23 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +23 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/inspect-routes.d.ts +12 -0
- package/dist/testing/inspect-routes.d.ts.map +1 -0
- package/dist/testing/inspect-routes.js +63 -0
- package/dist/testing/inspect-routes.js.map +1 -0
- package/dist/testing/status.d.ts +18 -0
- package/dist/testing/status.d.ts.map +1 -0
- package/dist/testing/status.js +12 -0
- package/dist/testing/status.js.map +1 -0
- package/dist/testing/waits.d.ts +60 -0
- package/dist/testing/waits.d.ts.map +1 -0
- package/dist/testing/waits.js +53 -0
- package/dist/testing/waits.js.map +1 -0
- package/dist/timeline.d.ts +9 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +63 -0
- package/dist/timeline.js.map +1 -0
- package/dist/tree.d.ts +19 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +61 -0
- package/dist/tree.js.map +1 -0
- package/dist/types.d.ts +254 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +26 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +44 -0
- package/dist/util.js.map +1 -0
- package/dist/variable-writes.d.ts +32 -0
- package/dist/variable-writes.d.ts.map +1 -0
- package/dist/variable-writes.js +113 -0
- package/dist/variable-writes.js.map +1 -0
- package/dist/variables.d.ts +28 -0
- package/dist/variables.d.ts.map +1 -0
- package/dist/variables.js +64 -0
- package/dist/variables.js.map +1 -0
- package/dist/waits.d.ts +11 -0
- package/dist/waits.d.ts.map +1 -0
- package/dist/waits.js +253 -0
- package/dist/waits.js.map +1 -0
- package/package.json +54 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miragon GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,98 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @miragon/pulse-engine-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@miragon/pulse-engine-core)
|
|
4
|
+
[](https://github.com/Miragon/pulse/actions/workflows/ci.yml)
|
|
5
|
+
[](https://miragon.github.io/pulse/)
|
|
6
|
+
|
|
7
|
+
The workflow domain of the Camunda 7 REST API family (Operaton, CIB seven, Camunda 7): where a
|
|
8
|
+
process instance waits and why, how an engine is doing, and what retry and advance would send,
|
|
9
|
+
and the pure engine REST rules every caller of this API needs (dates, filters, sorting, variable
|
|
10
|
+
writes, incident recovery). It runs on an engine port you implement and returns data.
|
|
11
|
+
|
|
12
|
+
## Who uses it
|
|
13
|
+
|
|
14
|
+
[pulse-cli](https://www.npmjs.com/package/@miragon/pulse-cli) bundles it: `inspect`, `status`,
|
|
15
|
+
`wait`, `advance` and `retry` run on it and word its results as command lines and CLI errors.
|
|
16
|
+
[@miragon/pulse-engine-connector](https://www.npmjs.com/package/@miragon/pulse-engine-connector)
|
|
17
|
+
runs inspect and status on it over its client, as the MCP tools `engine_inspect_process_instance`
|
|
18
|
+
and `engine_status`.
|
|
19
|
+
Pulse for VS Code bundles it in its C7 adapter: an instance's panel reads the instance through
|
|
20
|
+
`loadInstance` and the root cause of an incident through `rootCause` and `rootCauseLine`.
|
|
21
|
+
It is the shared domain of every Pulse interface to this API family, so an MCP tool and a CLI
|
|
22
|
+
command answer the same question by the same rules.
|
|
23
|
+
|
|
24
|
+
One port per API family: the vendors differ in runtime configuration, never in this package.
|
|
25
|
+
|
|
26
|
+
## What it is not
|
|
27
|
+
|
|
28
|
+
No HTTP, no authentication and no runtime dependency: it imports only its own modules. It names
|
|
29
|
+
no command, flag or tool: next steps are structured (`{ action: "retry", processInstanceId }`),
|
|
30
|
+
errors are `WorkflowError`s with a `reason` (`{ kind: "selection-ambiguous", candidates, more }`),
|
|
31
|
+
and the caller words both. The English texts that describe the engine's state are the package's
|
|
32
|
+
and shared by every caller: the finding messages of the status triage, its truncation notes and
|
|
33
|
+
the summaries of planned writes (`execute job j1`).
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npm install @miragon/pulse-engine-core
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## The API in brief
|
|
42
|
+
|
|
43
|
+
- **Port:** `createEnginePort(transport)` turns your `EngineTransport` (send an operation by its
|
|
44
|
+
REST operation id, read an answer as JSON or text, read an engine failure) into the
|
|
45
|
+
`EnginePort` the workflows run on, with the shared read rules: pages of 500, a missing resource
|
|
46
|
+
as undefined, blank texts as undefined. A missing resource is an engine 404 whose exception type
|
|
47
|
+
is neither `NotFoundException` (no such endpoint, a wrong REST root) nor `QueryParamException`,
|
|
48
|
+
so your `failure` reading must carry the engine's `engineType`: without it a missing instance
|
|
49
|
+
fails instead of reading as missing.
|
|
50
|
+
- **Inspect:** `inspectInstance(port, selection, options)` selects an instance by id, by business
|
|
51
|
+
key or by key with `latest`, and loads its view: wait states with their ids, root-cause
|
|
52
|
+
incidents, called instances, optionally variables, the history timeline and stacktraces (cut
|
|
53
|
+
after `MAX_STACKTRACE_LINES` lines).
|
|
54
|
+
- **Status:** `readStatus({ port, now }, options)` triages one engine: findings with severity, the
|
|
55
|
+
overall status, definitions, incident groups with their root cause, topics, jobs and batches,
|
|
56
|
+
every cut named in `truncated`.
|
|
57
|
+
- **Plans:** the pure parts of retry (`planRetry`, `retriesWrite`), advance (`chooseWait`,
|
|
58
|
+
`advanceSteps`) and wait (`parseCondition`, `decide`, `poll`).
|
|
59
|
+
- **Engine REST rules:** the one home of what the engine expects other than what a caller
|
|
60
|
+
naturally sends: dates (`toEngineDate`, `engineDateInput` in a `DateInputReading`:
|
|
61
|
+
`OFFSET_REQUIRED` refuses a time without an offset, `UTC_WITHOUT_OFFSET` reads it as UTC;
|
|
62
|
+
`engineDateMillis`, `latestEngineDate`), true-only and `…Like` filters (`trueOnly`,
|
|
63
|
+
`complementaryFlags`, `engineLike`, `engineKeyList`, `engineInstanceSearch`), paired sorting
|
|
64
|
+
(`engineSorting`), variable writes and typing (`toEngineVariable(s)`, `autoTypedValue`),
|
|
65
|
+
incident recovery (`incidentRecovery`), the raw variable read flag (`RAW_VARIABLES`) and root
|
|
66
|
+
causes (`rootCause`, and `rootCauseLine`, the line a viewer opens the text at).
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createEnginePort, type EngineTransport, inspectInstance } from "@miragon/pulse-engine-core"
|
|
70
|
+
|
|
71
|
+
// Your client's answer of one request, read right after it arrived.
|
|
72
|
+
type Answer = { readonly body?: unknown; readonly text?: string }
|
|
73
|
+
|
|
74
|
+
const transport: EngineTransport<Answer> = {
|
|
75
|
+
send: (operationId, input) => yourClient.send(operationId, input),
|
|
76
|
+
json: (answer) => answer.body,
|
|
77
|
+
text: (answer) => answer.text,
|
|
78
|
+
failure: (error) =>
|
|
79
|
+
error instanceof YourHttpError
|
|
80
|
+
? { status: error.status, engineType: error.type, engineMessage: error.message }
|
|
81
|
+
: undefined,
|
|
82
|
+
}
|
|
83
|
+
const port = createEnginePort(transport)
|
|
84
|
+
const view = await inspectInstance(
|
|
85
|
+
port,
|
|
86
|
+
{ businessKey: "B-1", latest: true },
|
|
87
|
+
{ variables: true, history: false, stacktrace: false },
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Testing helpers
|
|
92
|
+
|
|
93
|
+
`@miragon/pulse-engine-core/testing` exports the verified workflow fixture, the status fixture,
|
|
94
|
+
wait states of every kind, `fakePort` (a recording port over canned answers that refuses any
|
|
95
|
+
operation without a route) and `fakeClock`. It also exports the rules behind the entry's
|
|
96
|
+
functions that tests reach directly, and `INSPECT_OPERATIONS` and `STATUS_OPERATIONS`, the
|
|
97
|
+
operations each composite sends: a port that maps operations one by one holds its table equal to
|
|
98
|
+
them in a test.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The activity instance trees of the instances of a tree as one index: which activity instance an
|
|
3
|
+
* execution belongs to, which transition instance (async continuation) waits on it, and the leaf
|
|
4
|
+
* activity instances. Pure.
|
|
5
|
+
*/
|
|
6
|
+
import { type Rec } from "./records.js";
|
|
7
|
+
export interface ActivityNode {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly activityId: string;
|
|
10
|
+
readonly activityName?: string;
|
|
11
|
+
readonly activityType?: string;
|
|
12
|
+
readonly processInstanceId: string;
|
|
13
|
+
readonly depth: number;
|
|
14
|
+
/** The process instance itself (root of its activity instance tree). */
|
|
15
|
+
readonly root: boolean;
|
|
16
|
+
/** No child activity or transition instances. */
|
|
17
|
+
readonly leaf: boolean;
|
|
18
|
+
readonly transition: boolean;
|
|
19
|
+
readonly executionIds: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ActivityIndex {
|
|
22
|
+
readonly nodes: readonly ActivityNode[];
|
|
23
|
+
byId(id: string | undefined): ActivityNode | undefined;
|
|
24
|
+
/** The activity instance of an execution: one of `activityId` if possible, else the deepest. */
|
|
25
|
+
forExecution(executionId: string | undefined, activityId?: string): ActivityNode | undefined;
|
|
26
|
+
/** The transition instance (async continuation) of an execution. */
|
|
27
|
+
transition(executionId: string | undefined, activityId?: string): ActivityNode | undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Indexes the activity instance trees (ActivityInstanceDto) of the instances of a tree. */
|
|
30
|
+
export declare function indexActivities(trees: readonly Rec[]): ActivityIndex;
|
|
31
|
+
//# sourceMappingURL=activities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activities.d.ts","sourceRoot":"","sources":["../src/activities.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,KAAK,GAAG,EAAgB,MAAM,cAAc,CAAA;AAEzE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAA;IACtD,gGAAgG;IAChG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;IAC5F,oEAAoE;IACpE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAA;CAC3F;AAyDD,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,EAAE,GAAG,aAAa,CAmBpE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The activity instance trees of the instances of a tree as one index: which activity instance an
|
|
3
|
+
* execution belongs to, which transition instance (async continuation) waits on it, and the leaf
|
|
4
|
+
* activity instances. Pure.
|
|
5
|
+
*/
|
|
6
|
+
import { compareText, field, records, str } from "./records.js";
|
|
7
|
+
function strings(value) {
|
|
8
|
+
return Array.isArray(value)
|
|
9
|
+
? value.filter((item) => typeof item === "string")
|
|
10
|
+
: [];
|
|
11
|
+
}
|
|
12
|
+
function node(instance, position, flags, executionIds) {
|
|
13
|
+
const name = str(instance, "activityName") ?? str(instance, "name");
|
|
14
|
+
const type = str(instance, "activityType");
|
|
15
|
+
return {
|
|
16
|
+
id: field(instance, "id"),
|
|
17
|
+
activityId: field(instance, "activityId"),
|
|
18
|
+
...(name === undefined ? {} : { activityName: name }),
|
|
19
|
+
...(type === undefined ? {} : { activityType: type }),
|
|
20
|
+
...position,
|
|
21
|
+
...flags,
|
|
22
|
+
executionIds,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function walk(instance, position, nodes) {
|
|
26
|
+
const children = records(instance.childActivityInstances);
|
|
27
|
+
const transitions = records(instance.childTransitionInstances);
|
|
28
|
+
const leaf = children.length === 0 && transitions.length === 0;
|
|
29
|
+
const flags = { root: position.depth === 0, leaf, transition: false };
|
|
30
|
+
nodes.push(node(instance, position, flags, strings(instance.executionIds)));
|
|
31
|
+
const below = { ...position, depth: position.depth + 1 };
|
|
32
|
+
for (const child of children)
|
|
33
|
+
walk(child, below, nodes);
|
|
34
|
+
for (const transition of transitions) {
|
|
35
|
+
const executionId = str(transition, "executionId");
|
|
36
|
+
const transitionFlags = { root: false, leaf: false, transition: true };
|
|
37
|
+
nodes.push(node(transition, below, transitionFlags, executionId === undefined ? [] : [executionId]));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Deepest first, then by id: a deterministic choice among candidates. */
|
|
41
|
+
function best(candidates, activityId) {
|
|
42
|
+
const matching = candidates.filter((candidate) => candidate.activityId === activityId);
|
|
43
|
+
return (matching.length > 0 ? matching : candidates).toSorted((left, right) => right.depth - left.depth || compareText(left.id, right.id))[0];
|
|
44
|
+
}
|
|
45
|
+
/** Indexes the activity instance trees (ActivityInstanceDto) of the instances of a tree. */
|
|
46
|
+
export function indexActivities(trees) {
|
|
47
|
+
const nodes = [];
|
|
48
|
+
for (const tree of trees) {
|
|
49
|
+
const processInstanceId = str(tree, "processInstanceId") ?? field(tree, "id");
|
|
50
|
+
walk(tree, { processInstanceId, depth: 0 }, nodes);
|
|
51
|
+
}
|
|
52
|
+
const containing = (executionId, transition) => executionId === undefined
|
|
53
|
+
? []
|
|
54
|
+
: nodes.filter((candidate) => candidate.transition === transition && candidate.executionIds.includes(executionId));
|
|
55
|
+
return {
|
|
56
|
+
nodes,
|
|
57
|
+
byId: (id) => (id === undefined ? undefined : nodes.find((candidate) => candidate.id === id)),
|
|
58
|
+
forExecution: (executionId, activityId) => best(containing(executionId, false), activityId),
|
|
59
|
+
transition: (executionId, activityId) => best(containing(executionId, true), activityId),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=activities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activities.js","sourceRoot":"","sources":["../src/activities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning of advance: which wait state to move, which options apply to it, and the requests that
|
|
3
|
+
* move it. Pure.
|
|
4
|
+
*/
|
|
5
|
+
import type { PlannedWrite } from "./port.js";
|
|
6
|
+
import type { AdvanceInput, InstanceView, WaitState } from "./types.js";
|
|
7
|
+
/** Option combinations, checked before any request. */
|
|
8
|
+
export declare function checkAdvanceInput(input: AdvanceInput): void;
|
|
9
|
+
type ViewInput = Pick<InstanceView<unknown>, "id" | "state" | "waitingAt" | "children" | "truncated">;
|
|
10
|
+
/** The wait state to move: the only advanceable one (of `activityId`). */
|
|
11
|
+
export declare function chooseWait(view: ViewInput, activityId?: string): WaitState;
|
|
12
|
+
/** Options that do not apply to the chosen wait state are refused. */
|
|
13
|
+
export declare function checkOptions(wait: WaitState, input: AdvanceInput): void;
|
|
14
|
+
/** A suspended job is not executed behind the operator's back. */
|
|
15
|
+
export declare function checkSuspended(wait: WaitState): void;
|
|
16
|
+
/** A lock of another worker that has not expired is refused; `worker` is the caller's default. */
|
|
17
|
+
export declare function checkLock(wait: WaitState, input: AdvanceInput, now: number, worker: string): void;
|
|
18
|
+
/** The writes that move the wait state, in order; `worker` locks an external task by default. */
|
|
19
|
+
export declare function advanceSteps(wait: WaitState, input: AdvanceInput, worker: string): PlannedWrite[];
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=advance-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advance-plan.d.ts","sourceRoot":"","sources":["../src/advance-plan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAiB,YAAY,EAAY,SAAS,EAAE,MAAM,YAAY,CAAA;AAmBhG,uDAAuD;AACvD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAU3D;AAED,KAAK,SAAS,GAAG,IAAI,CACnB,YAAY,CAAC,OAAO,CAAC,EACrB,IAAI,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CACxD,CAAA;AAgBD,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAgB1E;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAYvE;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAOpD;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAWjG;AAqGD,iGAAiG;AACjG,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAYjG"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning of advance: which wait state to move, which options apply to it, and the requests that
|
|
3
|
+
* move it. Pure.
|
|
4
|
+
*/
|
|
5
|
+
import { WorkflowError } from "./errors.js";
|
|
6
|
+
import { isAdvanceable, isSuspendedJob } from "./next.js";
|
|
7
|
+
import { engineTime } from "./dates.js";
|
|
8
|
+
import { compact } from "./util.js";
|
|
9
|
+
import { waitId } from "./waits.js";
|
|
10
|
+
const LOCK_DURATION_MS = 60_000;
|
|
11
|
+
const TASKS = ["userTask", "externalTask"];
|
|
12
|
+
/** The kinds each option applies to, in the order the options are checked. */
|
|
13
|
+
const OPTION_KINDS = {
|
|
14
|
+
variables: ["userTask", "externalTask", "message", "signal", "other"],
|
|
15
|
+
localVariables: ["externalTask"],
|
|
16
|
+
bpmnError: TASKS,
|
|
17
|
+
errorMessage: TASKS,
|
|
18
|
+
fail: ["externalTask"],
|
|
19
|
+
retries: ["externalTask"],
|
|
20
|
+
workerId: ["externalTask"],
|
|
21
|
+
};
|
|
22
|
+
/** Option combinations, checked before any request. */
|
|
23
|
+
export function checkAdvanceInput(input) {
|
|
24
|
+
if (input.bpmnError !== undefined && input.fail !== undefined) {
|
|
25
|
+
throw new WorkflowError({ kind: "advance-input", rule: "bpmn-error-excludes-fail" });
|
|
26
|
+
}
|
|
27
|
+
if (input.errorMessage !== undefined && input.bpmnError === undefined) {
|
|
28
|
+
throw new WorkflowError({ kind: "advance-input", rule: "error-message-needs-bpmn-error" });
|
|
29
|
+
}
|
|
30
|
+
if (input.retries !== undefined && input.fail === undefined) {
|
|
31
|
+
throw new WorkflowError({ kind: "advance-input", rule: "retries-need-fail" });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function nothing(view, activityId) {
|
|
35
|
+
const firstChildId = view.truncated === true ? view.children[0]?.id : undefined;
|
|
36
|
+
return new WorkflowError({
|
|
37
|
+
kind: "advance-nothing",
|
|
38
|
+
id: view.id,
|
|
39
|
+
...compact({ activityId }),
|
|
40
|
+
waiting: view.waitingAt
|
|
41
|
+
.filter(isAdvanceable)
|
|
42
|
+
.map((wait) => ({ activityId: wait.activityId, kind: wait.kind })),
|
|
43
|
+
conditional: view.waitingAt.some((wait) => wait.kind === "conditional"),
|
|
44
|
+
...compact({ firstChildId }),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** The wait state to move: the only advanceable one (of `activityId`). */
|
|
48
|
+
export function chooseWait(view, activityId) {
|
|
49
|
+
if (view.state !== "ACTIVE" && view.state !== "SUSPENDED") {
|
|
50
|
+
throw new WorkflowError({ kind: "advance-ended", id: view.id, state: view.state });
|
|
51
|
+
}
|
|
52
|
+
if (view.state === "SUSPENDED")
|
|
53
|
+
throw new WorkflowError({ kind: "advance-suspended", id: view.id });
|
|
54
|
+
const matching = view.waitingAt.filter((wait) => isAdvanceable(wait) && (activityId === undefined || wait.activityId === activityId));
|
|
55
|
+
// a suspended job does not count as a place while something else can move (like the next steps)
|
|
56
|
+
const movable = matching.filter((wait) => !isSuspendedJob(wait));
|
|
57
|
+
const waits = movable.length > 0 ? movable : matching;
|
|
58
|
+
const [only, ...others] = waits;
|
|
59
|
+
if (only === undefined)
|
|
60
|
+
throw nothing(view, activityId);
|
|
61
|
+
if (others.length > 0)
|
|
62
|
+
throw new WorkflowError({ kind: "advance-ambiguous", id: view.id, waits });
|
|
63
|
+
return only;
|
|
64
|
+
}
|
|
65
|
+
/** Options that do not apply to the chosen wait state are refused. */
|
|
66
|
+
export function checkOptions(wait, input) {
|
|
67
|
+
for (const [option, kinds] of Object.entries(OPTION_KINDS)) {
|
|
68
|
+
if (input[option] !== undefined && !kinds.includes(wait.kind)) {
|
|
69
|
+
throw new WorkflowError({
|
|
70
|
+
kind: "advance-option-kind",
|
|
71
|
+
option,
|
|
72
|
+
appliesTo: kinds,
|
|
73
|
+
activityId: wait.activityId,
|
|
74
|
+
waitKind: wait.kind,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** A suspended job is not executed behind the operator's back. */
|
|
80
|
+
export function checkSuspended(wait) {
|
|
81
|
+
if (!isSuspendedJob(wait) || !("jobId" in wait))
|
|
82
|
+
return;
|
|
83
|
+
throw new WorkflowError({
|
|
84
|
+
kind: "advance-job-suspended",
|
|
85
|
+
jobId: wait.jobId,
|
|
86
|
+
activityId: wait.activityId,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** A lock of another worker that has not expired is refused; `worker` is the caller's default. */
|
|
90
|
+
export function checkLock(wait, input, now, worker) {
|
|
91
|
+
if (wait.kind !== "externalTask" || wait.workerId === undefined)
|
|
92
|
+
return;
|
|
93
|
+
const own = input.workerId ?? worker;
|
|
94
|
+
const until = engineTime(wait.lockExpirationTime);
|
|
95
|
+
if (wait.workerId === own || until === undefined || until <= now)
|
|
96
|
+
return;
|
|
97
|
+
throw new WorkflowError({
|
|
98
|
+
kind: "advance-locked",
|
|
99
|
+
externalTaskId: wait.externalTaskId,
|
|
100
|
+
workerId: wait.workerId,
|
|
101
|
+
...compact({ lockExpirationTime: wait.lockExpirationTime }),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function write(label, operationId, pathArgs, body) {
|
|
105
|
+
return {
|
|
106
|
+
label,
|
|
107
|
+
operationId,
|
|
108
|
+
input: { pathArgs, query: {}, ...(body === undefined ? {} : { body }) },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function variablesOf(input) {
|
|
112
|
+
return compact({ variables: input.variables, localVariables: input.localVariables });
|
|
113
|
+
}
|
|
114
|
+
function userTaskSteps(taskId, input) {
|
|
115
|
+
if (input.bpmnError === undefined) {
|
|
116
|
+
return [
|
|
117
|
+
write(`complete user task ${taskId}`, "complete", [taskId], compact({ variables: input.variables })),
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
const body = {
|
|
121
|
+
errorCode: input.bpmnError,
|
|
122
|
+
...compact({ errorMessage: input.errorMessage, variables: input.variables }),
|
|
123
|
+
};
|
|
124
|
+
return [
|
|
125
|
+
write(`throw BPMN error ${input.bpmnError} on user task ${taskId}`, "handleBpmnError", [taskId], body),
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
function externalTaskSteps(id, input, workerId) {
|
|
129
|
+
const lock = write(`lock external task ${id} as ${workerId}`, "lock", [id], {
|
|
130
|
+
workerId,
|
|
131
|
+
lockDuration: LOCK_DURATION_MS,
|
|
132
|
+
});
|
|
133
|
+
if (input.bpmnError !== undefined) {
|
|
134
|
+
const body = {
|
|
135
|
+
workerId,
|
|
136
|
+
errorCode: input.bpmnError,
|
|
137
|
+
...compact({ errorMessage: input.errorMessage, variables: input.variables }),
|
|
138
|
+
};
|
|
139
|
+
return [
|
|
140
|
+
lock,
|
|
141
|
+
write(`throw BPMN error ${input.bpmnError} on external task ${id}`, "handleExternalTaskBpmnError", [id], body),
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
if (input.fail !== undefined) {
|
|
145
|
+
const body = {
|
|
146
|
+
workerId,
|
|
147
|
+
errorMessage: input.fail,
|
|
148
|
+
retries: input.retries ?? 0,
|
|
149
|
+
retryTimeout: 0,
|
|
150
|
+
...variablesOf(input),
|
|
151
|
+
};
|
|
152
|
+
return [lock, write(`report a failure of external task ${id}`, "handleFailure", [id], body)];
|
|
153
|
+
}
|
|
154
|
+
return [
|
|
155
|
+
lock,
|
|
156
|
+
write(`complete external task ${id}`, "completeExternalTaskResource", [id], {
|
|
157
|
+
workerId,
|
|
158
|
+
...variablesOf(input),
|
|
159
|
+
}),
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
/** The write of a message, a signal or a receive task (`other`). */
|
|
163
|
+
function eventStep(wait, input) {
|
|
164
|
+
const variables = compact({ variables: input.variables });
|
|
165
|
+
if (wait.kind === "message") {
|
|
166
|
+
const name = wait.eventName ?? "";
|
|
167
|
+
const label = `trigger message ${name} of execution ${wait.executionId}`;
|
|
168
|
+
return write(label, "triggerEvent", [wait.executionId, name], variables);
|
|
169
|
+
}
|
|
170
|
+
if (wait.kind === "signal") {
|
|
171
|
+
const name = wait.eventName ?? "";
|
|
172
|
+
const body = { name, executionId: wait.executionId, ...variables };
|
|
173
|
+
return write(`send signal ${name} to execution ${wait.executionId}`, "throwSignal", [], body);
|
|
174
|
+
}
|
|
175
|
+
const executionId = waitId(wait);
|
|
176
|
+
return write(`signal execution ${executionId}`, "signalExecution", [executionId], variables);
|
|
177
|
+
}
|
|
178
|
+
/** The writes that move the wait state, in order; `worker` locks an external task by default. */
|
|
179
|
+
export function advanceSteps(wait, input, worker) {
|
|
180
|
+
switch (wait.kind) {
|
|
181
|
+
case "userTask":
|
|
182
|
+
return userTaskSteps(wait.taskId, input);
|
|
183
|
+
case "externalTask":
|
|
184
|
+
return externalTaskSteps(wait.externalTaskId, input, input.workerId ?? worker);
|
|
185
|
+
case "timer":
|
|
186
|
+
case "asyncContinuation":
|
|
187
|
+
return [write(`execute job ${wait.jobId}`, "executeJob", [wait.jobId])];
|
|
188
|
+
default:
|
|
189
|
+
return [eventStep(wait, input)];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=advance-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advance-plan.js","sourceRoot":"","sources":["../src/advance-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wait conditions: parsing, the requests each condition needs per poll, and the order in which a
|
|
3
|
+
* poll decides.
|
|
4
|
+
*/
|
|
5
|
+
import type { EnginePort } from "./port.js";
|
|
6
|
+
export type Condition = {
|
|
7
|
+
readonly kind: "idle" | "ended" | "incident";
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: "task";
|
|
10
|
+
readonly key?: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: "activity";
|
|
13
|
+
readonly id: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function parseCondition(raw: string): Condition;
|
|
16
|
+
export declare function conditionLabel(condition: Condition): string;
|
|
17
|
+
/** The instance as one poll saw it. */
|
|
18
|
+
export interface Probe {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly ended: boolean;
|
|
21
|
+
/** The active tree (empty once the instance ended). */
|
|
22
|
+
readonly tree: readonly string[];
|
|
23
|
+
/** The tree was cut: instances beyond the cut are not counted. */
|
|
24
|
+
readonly truncated?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface Measurement {
|
|
27
|
+
/** Instances of the tree with an incident. */
|
|
28
|
+
readonly incidents: number;
|
|
29
|
+
/** Labels of the conditions that hold, other than `incident`, in the given order. */
|
|
30
|
+
readonly held: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The jobs the job executor will run: retries left, due, and active. The engine's `executable`
|
|
34
|
+
* filter checks the suspension of the instance only, not of the job (a suspended job definition
|
|
35
|
+
* suspends its jobs), hence `active` (verified on all three engines).
|
|
36
|
+
*/
|
|
37
|
+
export declare const EXECUTABLE: {
|
|
38
|
+
readonly executable: "true";
|
|
39
|
+
readonly active: "true";
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The counts of one poll: only what the conditions need, then the incident check. The incident
|
|
43
|
+
* count is read after the condition counts, never in parallel with them: a job that fails for good
|
|
44
|
+
* loses its last retry and gets its incident in one transaction, so a job count that no longer sees
|
|
45
|
+
* the job is followed by an incident count that sees the incident. Read in parallel, the incident
|
|
46
|
+
* count could come from before that transaction and the job count from after it, and the poll
|
|
47
|
+
* would see neither (a stuck instance reported as idle).
|
|
48
|
+
*/
|
|
49
|
+
export declare function measure(port: EnginePort, probe: Probe, conditions: readonly Condition[], checkIncidents: boolean): Promise<Measurement>;
|
|
50
|
+
export type Verdict = {
|
|
51
|
+
readonly kind: "held";
|
|
52
|
+
readonly until: string;
|
|
53
|
+
} | {
|
|
54
|
+
readonly kind: "incident";
|
|
55
|
+
} | {
|
|
56
|
+
readonly kind: "ended";
|
|
57
|
+
} | {
|
|
58
|
+
readonly kind: "pending";
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* The decision of a poll: the condition `incident` with an incident, then an incident with fail fast
|
|
62
|
+
* (a job that failed for good is not executable, so `idle` would otherwise report success for a
|
|
63
|
+
* stuck instance), then any other condition, then an ended instance.
|
|
64
|
+
*/
|
|
65
|
+
export declare function decide(conditions: readonly Condition[], failOnIncident: boolean, probe: Probe, measurement: Measurement): Verdict;
|
|
66
|
+
//# sourceMappingURL=conditions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../src/conditions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAG3C,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAgBtD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAQrD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAS3D;AAED,uCAAuC;AACvC,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,kEAAkE;IAClE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CACjC;AAsBD;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAkD,CAAA;AA6BzE;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,cAAc,EAAE,OAAO,GACtB,OAAO,CAAC,WAAW,CAAC,CAOtB;AAED,MAAM,MAAM,OAAO,GACf;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAC7B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CAAA;AAEhC;;;;GAIG;AACH,wBAAgB,MAAM,CACpB,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,cAAc,EAAE,OAAO,EACvB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,GACvB,OAAO,CAOT"}
|