@nanobpm/workflow 0.4.0 → 0.5.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/README.md +19 -1
- package/dist/client.d.ts +25 -2
- package/dist/client.js +47 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/src/client.ts +51 -3
- package/src/index.ts +1 -1
package/README.md
CHANGED
|
@@ -183,7 +183,25 @@ once.
|
|
|
183
183
|
| `externalJobTypes(flow)` | The job types of a flow's external `task` steps (each overridable per-step via `w.task(name, { jobType })`). |
|
|
184
184
|
| `WorkflowClient` | `deploy`, `start`, `signal`, `getInstance` over REST v2. |
|
|
185
185
|
| `Worker` | Generic job runtime; routes job types → handlers, hosts the replay loop. |
|
|
186
|
-
| `toBpmn(workflow)` | The
|
|
186
|
+
| `toBpmn(workflow)` | The DI-less semantic BPMN the engine runs (for inspection / deployment). |
|
|
187
|
+
| `toDeployableBpmn(workflow, { layout? })` | The deployable BPMN **with an auto-generated diagram (DI)** so the deployed model is inspectable; what `deploy` sends by default. |
|
|
188
|
+
| `layoutBpmn(xml)` / `declarativeToLayoutedBpmn(flow)` | Add DI to a model with `bpmn-auto-layout`. |
|
|
189
|
+
|
|
190
|
+
### Inspectable deployments (diagram layout)
|
|
191
|
+
|
|
192
|
+
`client.deploy(flow)` deploys the model **with an auto-generated diagram
|
|
193
|
+
interchange (DI)** so it opens rendered and inspectable in a modeller/Operate
|
|
194
|
+
rather than as a blank canvas. DI is generated with the optional peer dependency
|
|
195
|
+
[`bpmn-auto-layout`](https://www.npmjs.com/package/bpmn-auto-layout):
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
npm i bpmn-auto-layout
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
If it is not installed, `deploy` degrades gracefully — it warns once and deploys
|
|
202
|
+
the DI-less model. Pass `deploy(flow, { layout: false })` to skip layout
|
|
203
|
+
deliberately. The semantic model stays authoritative; DI is derived and
|
|
204
|
+
regenerable.
|
|
187
205
|
|
|
188
206
|
See [ADR 0044](../docs/adr/0044-code-first-durable-orchestration.md) for the design
|
|
189
207
|
rationale and [ADR 0047](../docs/adr/0047-declarative-flow-control-and-typed-envelopes.md)
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import type { DeclarativeFlow, DeployResult, Job, JsonObject, StartResult, Workflow } from "./types.js";
|
|
2
2
|
/** Render a workflow (either surface) to its executable BPMN model. */
|
|
3
3
|
export declare function toBpmn(wf: Workflow): string;
|
|
4
|
+
/**
|
|
5
|
+
* Render a workflow to *deployable* BPMN — the executable model plus diagram
|
|
6
|
+
* interchange (DI), auto-generated with `bpmn-auto-layout` — so the deployed
|
|
7
|
+
* process opens rendered and inspectable in a modeller/Operate rather than as a
|
|
8
|
+
* blank canvas. The semantic model stays authoritative; DI is derived.
|
|
9
|
+
*
|
|
10
|
+
* DI generation needs the optional peer dependency `bpmn-auto-layout`. When it is
|
|
11
|
+
* absent, this degrades gracefully: it warns once and returns the DI-less model
|
|
12
|
+
* so `deploy` still works everywhere. Pass `{ layout: false }` to skip layout
|
|
13
|
+
* deliberately. A genuine layout failure (the dep is installed but errors) is
|
|
14
|
+
* surfaced, not swallowed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function toDeployableBpmn(wf: Workflow, opts?: {
|
|
17
|
+
layout?: boolean;
|
|
18
|
+
}): Promise<string>;
|
|
4
19
|
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
5
20
|
export interface WorkflowClientOptions {
|
|
6
21
|
/** Base URL of the nanobpmn gateway, e.g. `http://localhost:8080`. */
|
|
@@ -29,8 +44,16 @@ export declare class WorkflowClient {
|
|
|
29
44
|
/** Perform a request, throwing WorkflowError on transport error or !ok, and
|
|
30
45
|
* return the raw Response (for endpoints with an empty/no-content body). */
|
|
31
46
|
private send;
|
|
32
|
-
/**
|
|
33
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Deploy a workflow's derived BPMN model. The deployed model includes
|
|
49
|
+
* auto-generated diagram interchange (DI) so it is inspectable in a
|
|
50
|
+
* modeller/Operate; pass `{ layout: false }` to deploy the DI-less semantic
|
|
51
|
+
* model. DI needs the optional `bpmn-auto-layout` dependency — see
|
|
52
|
+
* `toDeployableBpmn` for the graceful-degradation behaviour when it is absent.
|
|
53
|
+
*/
|
|
54
|
+
deploy(wf: Workflow, opts?: {
|
|
55
|
+
layout?: boolean;
|
|
56
|
+
}): Promise<DeployResult>;
|
|
34
57
|
/**
|
|
35
58
|
* Start a workflow instance. For imperative workflows the engine variables are
|
|
36
59
|
* seeded with `{ input, journal: {}, wfDone: false }` (the replay state); for
|
package/dist/client.js
CHANGED
|
@@ -3,12 +3,50 @@
|
|
|
3
3
|
// low-level job activate/complete/fail used by the Worker runtime.
|
|
4
4
|
import { declarativeToBpmn, walkNodes } from "./declarative.js";
|
|
5
5
|
import { imperativeToBpmn } from "./imperative.js";
|
|
6
|
+
import { layoutBpmn } from "./layout.js";
|
|
6
7
|
import { assertWorkflowIds, messageName } from "./xml.js";
|
|
7
8
|
/** Render a workflow (either surface) to its executable BPMN model. */
|
|
8
9
|
export function toBpmn(wf) {
|
|
9
10
|
assertWorkflowIds(wf);
|
|
10
11
|
return wf.kind === "imperative" ? imperativeToBpmn(wf) : declarativeToBpmn(wf);
|
|
11
12
|
}
|
|
13
|
+
let warnedNoLayout = false;
|
|
14
|
+
/**
|
|
15
|
+
* Render a workflow to *deployable* BPMN — the executable model plus diagram
|
|
16
|
+
* interchange (DI), auto-generated with `bpmn-auto-layout` — so the deployed
|
|
17
|
+
* process opens rendered and inspectable in a modeller/Operate rather than as a
|
|
18
|
+
* blank canvas. The semantic model stays authoritative; DI is derived.
|
|
19
|
+
*
|
|
20
|
+
* DI generation needs the optional peer dependency `bpmn-auto-layout`. When it is
|
|
21
|
+
* absent, this degrades gracefully: it warns once and returns the DI-less model
|
|
22
|
+
* so `deploy` still works everywhere. Pass `{ layout: false }` to skip layout
|
|
23
|
+
* deliberately. A genuine layout failure (the dep is installed but errors) is
|
|
24
|
+
* surfaced, not swallowed.
|
|
25
|
+
*/
|
|
26
|
+
export async function toDeployableBpmn(wf, opts = {}) {
|
|
27
|
+
const semantic = toBpmn(wf);
|
|
28
|
+
if (opts.layout === false)
|
|
29
|
+
return semantic;
|
|
30
|
+
try {
|
|
31
|
+
return await layoutBpmn(semantic);
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
// Only fall back for the "optional dep not installed" case (layoutBpmn wraps
|
|
35
|
+
// it with an ERR_MODULE_NOT_FOUND cause). Any other failure is a real layout
|
|
36
|
+
// problem and must surface rather than silently deploy an uninspectable model.
|
|
37
|
+
const cause = e?.cause;
|
|
38
|
+
if (cause?.code !== "ERR_MODULE_NOT_FOUND")
|
|
39
|
+
throw e;
|
|
40
|
+
if (!warnedNoLayout) {
|
|
41
|
+
warnedNoLayout = true;
|
|
42
|
+
console.warn(`[@nanobpm/workflow] Deploying "${wf.id}" without a diagram: the optional ` +
|
|
43
|
+
'"bpmn-auto-layout" dependency is not installed, so the model will be ' +
|
|
44
|
+
"uninspectable in a modeller/Operate. Install it for diagram layout: " +
|
|
45
|
+
"npm i bpmn-auto-layout");
|
|
46
|
+
}
|
|
47
|
+
return semantic;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
12
50
|
export class WorkflowError extends Error {
|
|
13
51
|
status;
|
|
14
52
|
body;
|
|
@@ -51,9 +89,15 @@ export class WorkflowClient {
|
|
|
51
89
|
}
|
|
52
90
|
return res;
|
|
53
91
|
}
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Deploy a workflow's derived BPMN model. The deployed model includes
|
|
94
|
+
* auto-generated diagram interchange (DI) so it is inspectable in a
|
|
95
|
+
* modeller/Operate; pass `{ layout: false }` to deploy the DI-less semantic
|
|
96
|
+
* model. DI needs the optional `bpmn-auto-layout` dependency — see
|
|
97
|
+
* `toDeployableBpmn` for the graceful-degradation behaviour when it is absent.
|
|
98
|
+
*/
|
|
99
|
+
async deploy(wf, opts = {}) {
|
|
100
|
+
const xml = await toDeployableBpmn(wf, opts);
|
|
57
101
|
const form = new FormData();
|
|
58
102
|
form.append("resources", new Blob([xml], { type: "text/xml" }), `${wf.id}.bpmn`);
|
|
59
103
|
return this.json(`/v2/deployments`, { method: "POST", body: form }, "deploy");
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { FlowBuilder } from "./declarative.js";
|
|
|
5
5
|
export { layoutBpmn, declarativeToLayoutedBpmn } from "./layout.js";
|
|
6
6
|
export { envelope } from "./envelope.js";
|
|
7
7
|
export type { Envelope, EnvelopeType, EnvelopeField, FieldSpec, ScalarType, ScalarTs, FieldTs, } from "./envelope.js";
|
|
8
|
-
export { WorkflowClient, WorkflowError, toBpmn } from "./client.js";
|
|
8
|
+
export { WorkflowClient, WorkflowError, toBpmn, toDeployableBpmn } from "./client.js";
|
|
9
9
|
export type { WorkflowClientOptions, ActivateOptions } from "./client.js";
|
|
10
10
|
export { Worker } from "./worker.js";
|
|
11
11
|
export type { WorkerOptions, ActivityEvent } from "./worker.js";
|
package/dist/index.js
CHANGED
|
@@ -42,5 +42,5 @@ export { defineWorkflow, imperativeToBpmn, replayOnce } from "./imperative.js";
|
|
|
42
42
|
export { defineFlow, declarativeToBpmn, externalJobTypes, walkNodes } from "./declarative.js";
|
|
43
43
|
export { layoutBpmn, declarativeToLayoutedBpmn } from "./layout.js";
|
|
44
44
|
export { envelope } from "./envelope.js";
|
|
45
|
-
export { WorkflowClient, WorkflowError, toBpmn } from "./client.js";
|
|
45
|
+
export { WorkflowClient, WorkflowError, toBpmn, toDeployableBpmn } from "./client.js";
|
|
46
46
|
export { Worker } from "./worker.js";
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanobpm/workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Code-first durable orchestration for nanobpmn (ADR 0044/0045). Author a durable workflow as a declarative flow — `defineFlow(id, w => { w.run(...); w.signal(...); w.task(...) })` — and the SDK derives the executable BPMN model, the job types, and the message/correlation wiring, then hosts a generic worker. `w.run` is a local step, `w.signal` is a durable human-in-the-loop wait, `w.task` is a step serviced by an external worker. `defineFlow` is the single code-first surface; the imperative `defineWorkflow` replay function is experimental/internal, not a recommended API. No diagram, no task-type wiring, no correlation plumbing authored by hand — and you can optionally auto-generate a diagram (DI) for the derived model with `declarativeToLayoutedBpmn` via the optional `bpmn-auto-layout` peer dependency. Talks to a running nanobpmn gateway over the REST v2 API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/
|
|
10
|
-
"directory": "workflow"
|
|
9
|
+
"url": "https://github.com/jwulf/nano-ide.git",
|
|
10
|
+
"directory": "packages/workflow"
|
|
11
11
|
},
|
|
12
12
|
"main": "./dist/index.js",
|
|
13
13
|
"module": "./dist/index.js",
|
package/src/client.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { declarativeToBpmn, walkNodes } from "./declarative.js";
|
|
6
6
|
import { imperativeToBpmn } from "./imperative.js";
|
|
7
|
+
import { layoutBpmn } from "./layout.js";
|
|
7
8
|
import type { DeclarativeFlow, DeployResult, Job, JsonObject, StartResult, Workflow } from "./types.js";
|
|
8
9
|
import { assertWorkflowIds, messageName } from "./xml.js";
|
|
9
10
|
|
|
@@ -13,6 +14,47 @@ export function toBpmn(wf: Workflow): string {
|
|
|
13
14
|
return wf.kind === "imperative" ? imperativeToBpmn(wf) : declarativeToBpmn(wf);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
let warnedNoLayout = false;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Render a workflow to *deployable* BPMN — the executable model plus diagram
|
|
21
|
+
* interchange (DI), auto-generated with `bpmn-auto-layout` — so the deployed
|
|
22
|
+
* process opens rendered and inspectable in a modeller/Operate rather than as a
|
|
23
|
+
* blank canvas. The semantic model stays authoritative; DI is derived.
|
|
24
|
+
*
|
|
25
|
+
* DI generation needs the optional peer dependency `bpmn-auto-layout`. When it is
|
|
26
|
+
* absent, this degrades gracefully: it warns once and returns the DI-less model
|
|
27
|
+
* so `deploy` still works everywhere. Pass `{ layout: false }` to skip layout
|
|
28
|
+
* deliberately. A genuine layout failure (the dep is installed but errors) is
|
|
29
|
+
* surfaced, not swallowed.
|
|
30
|
+
*/
|
|
31
|
+
export async function toDeployableBpmn(
|
|
32
|
+
wf: Workflow,
|
|
33
|
+
opts: { layout?: boolean } = {},
|
|
34
|
+
): Promise<string> {
|
|
35
|
+
const semantic = toBpmn(wf);
|
|
36
|
+
if (opts.layout === false) return semantic;
|
|
37
|
+
try {
|
|
38
|
+
return await layoutBpmn(semantic);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// Only fall back for the "optional dep not installed" case (layoutBpmn wraps
|
|
41
|
+
// it with an ERR_MODULE_NOT_FOUND cause). Any other failure is a real layout
|
|
42
|
+
// problem and must surface rather than silently deploy an uninspectable model.
|
|
43
|
+
const cause = (e as { cause?: NodeJS.ErrnoException })?.cause;
|
|
44
|
+
if (cause?.code !== "ERR_MODULE_NOT_FOUND") throw e;
|
|
45
|
+
if (!warnedNoLayout) {
|
|
46
|
+
warnedNoLayout = true;
|
|
47
|
+
console.warn(
|
|
48
|
+
`[@nanobpm/workflow] Deploying "${wf.id}" without a diagram: the optional ` +
|
|
49
|
+
'"bpmn-auto-layout" dependency is not installed, so the model will be ' +
|
|
50
|
+
"uninspectable in a modeller/Operate. Install it for diagram layout: " +
|
|
51
|
+
"npm i bpmn-auto-layout",
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return semantic;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
16
58
|
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
17
59
|
|
|
18
60
|
export interface WorkflowClientOptions {
|
|
@@ -75,9 +117,15 @@ export class WorkflowClient {
|
|
|
75
117
|
return res;
|
|
76
118
|
}
|
|
77
119
|
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Deploy a workflow's derived BPMN model. The deployed model includes
|
|
122
|
+
* auto-generated diagram interchange (DI) so it is inspectable in a
|
|
123
|
+
* modeller/Operate; pass `{ layout: false }` to deploy the DI-less semantic
|
|
124
|
+
* model. DI needs the optional `bpmn-auto-layout` dependency — see
|
|
125
|
+
* `toDeployableBpmn` for the graceful-degradation behaviour when it is absent.
|
|
126
|
+
*/
|
|
127
|
+
async deploy(wf: Workflow, opts: { layout?: boolean } = {}): Promise<DeployResult> {
|
|
128
|
+
const xml = await toDeployableBpmn(wf, opts);
|
|
81
129
|
const form = new FormData();
|
|
82
130
|
form.append("resources", new Blob([xml], { type: "text/xml" }), `${wf.id}.bpmn`);
|
|
83
131
|
return this.json<DeployResult>(`/v2/deployments`, { method: "POST", body: form }, "deploy");
|
package/src/index.ts
CHANGED
|
@@ -54,7 +54,7 @@ export type {
|
|
|
54
54
|
ScalarTs,
|
|
55
55
|
FieldTs,
|
|
56
56
|
} from "./envelope.js";
|
|
57
|
-
export { WorkflowClient, WorkflowError, toBpmn } from "./client.js";
|
|
57
|
+
export { WorkflowClient, WorkflowError, toBpmn, toDeployableBpmn } from "./client.js";
|
|
58
58
|
export type { WorkflowClientOptions, ActivateOptions } from "./client.js";
|
|
59
59
|
export { Worker } from "./worker.js";
|
|
60
60
|
export type { WorkerOptions, ActivityEvent } from "./worker.js";
|