@sapiom/orchestration 0.1.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 +55 -0
- package/dist/cjs/build-manifest.d.ts +15 -0
- package/dist/cjs/build-manifest.js +146 -0
- package/dist/cjs/context.d.ts +45 -0
- package/dist/cjs/context.js +21 -0
- package/dist/cjs/directives.d.ts +89 -0
- package/dist/cjs/directives.js +56 -0
- package/dist/cjs/errors.d.ts +19 -0
- package/dist/cjs/errors.js +49 -0
- package/dist/cjs/index.d.ts +17 -0
- package/dist/cjs/index.js +41 -0
- package/dist/cjs/introspection.d.ts +11 -0
- package/dist/cjs/introspection.js +62 -0
- package/dist/cjs/manifest.d.ts +56 -0
- package/dist/cjs/manifest.js +27 -0
- package/dist/cjs/step.d.ts +42 -0
- package/dist/cjs/step.js +15 -0
- package/dist/cjs/workflow.d.ts +10 -0
- package/dist/cjs/workflow.js +38 -0
- package/dist/esm/build-manifest.d.ts +15 -0
- package/dist/esm/build-manifest.js +141 -0
- package/dist/esm/context.d.ts +45 -0
- package/dist/esm/context.js +17 -0
- package/dist/esm/directives.d.ts +89 -0
- package/dist/esm/directives.js +43 -0
- package/dist/esm/errors.d.ts +19 -0
- package/dist/esm/errors.js +42 -0
- package/dist/esm/index.d.ts +17 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/introspection.d.ts +11 -0
- package/dist/esm/introspection.js +56 -0
- package/dist/esm/manifest.d.ts +56 -0
- package/dist/esm/manifest.js +24 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/step.d.ts +42 -0
- package/dist/esm/step.js +12 -0
- package/dist/esm/workflow.d.ts +10 -0
- package/dist/esm/workflow.js +33 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Sapiom
|
|
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
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# @sapiom/orchestration
|
|
2
|
+
|
|
3
|
+
The versioned public contract for authoring Sapiom orchestrations.
|
|
4
|
+
|
|
5
|
+
A lean, dependency-light package (types + a small protocol runtime, with a single
|
|
6
|
+
strictly-pinned `zod` peer) shared by three consumers:
|
|
7
|
+
|
|
8
|
+
- **Customer orchestration definitions** — authored against this package's types and
|
|
9
|
+
compiled by the build.
|
|
10
|
+
- **The sandbox step-runner** — reads a step's input, builds `ctx`, runs one step.
|
|
11
|
+
- **The engine** — uses the directive guards + manifest schema; it never runs
|
|
12
|
+
customer code, only validates the pure-data completion payload.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install @sapiom/orchestration zod
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`zod` is a peer dependency, pinned to the `3.25.x` line (the SDK uses the `zod/v4`
|
|
21
|
+
subpath).
|
|
22
|
+
|
|
23
|
+
## Authoring surface
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { defineOrchestration, defineStep, goto, terminate } from '@sapiom/orchestration';
|
|
27
|
+
|
|
28
|
+
const start = defineStep({
|
|
29
|
+
name: 'start',
|
|
30
|
+
next: ['finish'],
|
|
31
|
+
async run(input, ctx) {
|
|
32
|
+
return goto('finish', { greeting: `hello ${input.name}` });
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const finish = defineStep({
|
|
37
|
+
name: 'finish',
|
|
38
|
+
next: [],
|
|
39
|
+
terminal: true,
|
|
40
|
+
async run() {
|
|
41
|
+
return terminate({ done: true });
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const hello = defineOrchestration({
|
|
46
|
+
name: 'hello',
|
|
47
|
+
entry: 'start',
|
|
48
|
+
steps: { start, finish },
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
A step declares the transitions it may take (`next` / `terminal` / `canFail` /
|
|
53
|
+
`pause`); the `run` return type is derived from those declarations, so an
|
|
54
|
+
undeclared transition is a compile error. The build reads those same declarations
|
|
55
|
+
to render the orchestration graph without executing anything.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type WorkflowManifest } from './manifest.js';
|
|
2
|
+
import type { OrchestrationDefinition } from './workflow.js';
|
|
3
|
+
export declare function buildManifest(def: OrchestrationDefinition, opts: {
|
|
4
|
+
sdkVersion: string;
|
|
5
|
+
artifact: {
|
|
6
|
+
sha256: string;
|
|
7
|
+
entryFile: string;
|
|
8
|
+
};
|
|
9
|
+
}): WorkflowManifest;
|
|
10
|
+
export interface GraphValidation {
|
|
11
|
+
readonly errors: string[];
|
|
12
|
+
readonly warnings: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function validateGraph(manifest: WorkflowManifest): GraphValidation;
|
|
15
|
+
export declare function assertValidGraph(manifest: WorkflowManifest): string[];
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildManifest = buildManifest;
|
|
4
|
+
exports.validateGraph = validateGraph;
|
|
5
|
+
exports.assertValidGraph = assertValidGraph;
|
|
6
|
+
const introspection_js_1 = require("./introspection.js");
|
|
7
|
+
const manifest_js_1 = require("./manifest.js");
|
|
8
|
+
function buildManifest(def, opts) {
|
|
9
|
+
const steps = {};
|
|
10
|
+
for (const [stepName, step] of Object.entries(def.steps)) {
|
|
11
|
+
let inputSchema = null;
|
|
12
|
+
if (step.inputSchema) {
|
|
13
|
+
const raw = (0, introspection_js_1.zodToJsonSchema)(step.inputSchema);
|
|
14
|
+
inputSchema = dropDefaultedFromRequired(raw);
|
|
15
|
+
}
|
|
16
|
+
steps[stepName] = {
|
|
17
|
+
timeoutMs: step.timeoutMs ?? null,
|
|
18
|
+
inputSchema,
|
|
19
|
+
transitions: transitionsFor(step),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
protocol: manifest_js_1.MANIFEST_PROTOCOL,
|
|
24
|
+
name: def.name,
|
|
25
|
+
entry: def.entry,
|
|
26
|
+
sdkVersion: opts.sdkVersion,
|
|
27
|
+
artifact: opts.artifact,
|
|
28
|
+
steps,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function transitionsFor(step) {
|
|
32
|
+
const transitions = [];
|
|
33
|
+
for (const target of step.next ?? []) {
|
|
34
|
+
transitions.push({ kind: 'continue', target });
|
|
35
|
+
}
|
|
36
|
+
if (step.pause) {
|
|
37
|
+
transitions.push({ kind: 'pause', signal: step.pause.signal, resumeStep: step.pause.resumeStep });
|
|
38
|
+
}
|
|
39
|
+
if (step.terminal)
|
|
40
|
+
transitions.push({ kind: 'terminate' });
|
|
41
|
+
if (step.canFail)
|
|
42
|
+
transitions.push({ kind: 'fail' });
|
|
43
|
+
return transitions;
|
|
44
|
+
}
|
|
45
|
+
function validateGraph(manifest) {
|
|
46
|
+
const errors = [];
|
|
47
|
+
const names = new Set(Object.keys(manifest.steps));
|
|
48
|
+
if (!names.has(manifest.entry)) {
|
|
49
|
+
errors.push(`entry step '${manifest.entry}' is not in the steps map`);
|
|
50
|
+
}
|
|
51
|
+
const forward = buildForwardEdges(manifest, names, errors);
|
|
52
|
+
const warnings = [];
|
|
53
|
+
if (names.has(manifest.entry)) {
|
|
54
|
+
const reachable = bfs([manifest.entry], forward);
|
|
55
|
+
for (const name of names) {
|
|
56
|
+
if (!reachable.has(name))
|
|
57
|
+
warnings.push(`step '${name}' is unreachable from entry '${manifest.entry}'`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
warnings.push(...terminalReachabilityWarnings(manifest, names, forward));
|
|
61
|
+
return { errors, warnings };
|
|
62
|
+
}
|
|
63
|
+
function assertValidGraph(manifest) {
|
|
64
|
+
const { errors, warnings } = validateGraph(manifest);
|
|
65
|
+
if (errors.length > 0) {
|
|
66
|
+
throw new Error(`Invalid workflow graph for '${manifest.name}':\n - ${errors.join('\n - ')}`);
|
|
67
|
+
}
|
|
68
|
+
return warnings;
|
|
69
|
+
}
|
|
70
|
+
function buildForwardEdges(manifest, names, errors) {
|
|
71
|
+
const forward = new Map();
|
|
72
|
+
for (const [name, step] of Object.entries(manifest.steps)) {
|
|
73
|
+
const targets = new Set();
|
|
74
|
+
for (const t of step.transitions) {
|
|
75
|
+
if (t.kind === 'continue') {
|
|
76
|
+
if (names.has(t.target))
|
|
77
|
+
targets.add(t.target);
|
|
78
|
+
else
|
|
79
|
+
errors.push(`step '${name}' has a continue target '${t.target}' that is not in the steps map`);
|
|
80
|
+
}
|
|
81
|
+
else if (t.kind === 'pause' && names.has(t.resumeStep)) {
|
|
82
|
+
targets.add(t.resumeStep);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (step.transitions.length === 0) {
|
|
86
|
+
errors.push(`step '${name}' is a dead-end: it declares no transitions (next/terminal/canFail/pause)`);
|
|
87
|
+
}
|
|
88
|
+
forward.set(name, targets);
|
|
89
|
+
}
|
|
90
|
+
return forward;
|
|
91
|
+
}
|
|
92
|
+
function terminalReachabilityWarnings(manifest, names, forward) {
|
|
93
|
+
const sinks = Object.entries(manifest.steps)
|
|
94
|
+
.filter(([, s]) => s.transitions.some((t) => t.kind === 'terminate' || t.kind === 'fail'))
|
|
95
|
+
.map(([name]) => name);
|
|
96
|
+
if (sinks.length === 0) {
|
|
97
|
+
return ['no step can terminate or fail — the workflow has no terminal state'];
|
|
98
|
+
}
|
|
99
|
+
const reverse = new Map();
|
|
100
|
+
for (const name of names)
|
|
101
|
+
reverse.set(name, new Set());
|
|
102
|
+
for (const [name, targets] of forward) {
|
|
103
|
+
for (const t of targets)
|
|
104
|
+
reverse.get(t)?.add(name);
|
|
105
|
+
}
|
|
106
|
+
const canReach = bfs(sinks, reverse);
|
|
107
|
+
const warnings = [];
|
|
108
|
+
for (const name of names) {
|
|
109
|
+
if (!canReach.has(name)) {
|
|
110
|
+
warnings.push(`step '${name}' cannot reach any terminate/fail (possible unbounded loop or missing terminal)`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return warnings;
|
|
114
|
+
}
|
|
115
|
+
function bfs(starts, edges) {
|
|
116
|
+
const seen = new Set();
|
|
117
|
+
const queue = [...starts];
|
|
118
|
+
while (queue.length > 0) {
|
|
119
|
+
const cur = queue.shift();
|
|
120
|
+
if (seen.has(cur))
|
|
121
|
+
continue;
|
|
122
|
+
seen.add(cur);
|
|
123
|
+
for (const next of edges.get(cur) ?? [])
|
|
124
|
+
if (!seen.has(next))
|
|
125
|
+
queue.push(next);
|
|
126
|
+
}
|
|
127
|
+
return seen;
|
|
128
|
+
}
|
|
129
|
+
function dropDefaultedFromRequired(schema) {
|
|
130
|
+
const required = schema.required;
|
|
131
|
+
const properties = schema.properties;
|
|
132
|
+
if (!Array.isArray(required) || !properties || typeof properties !== 'object') {
|
|
133
|
+
return schema;
|
|
134
|
+
}
|
|
135
|
+
const props = properties;
|
|
136
|
+
const filtered = required.filter((key) => {
|
|
137
|
+
if (typeof key !== 'string')
|
|
138
|
+
return true;
|
|
139
|
+
const prop = props[key];
|
|
140
|
+
return !(prop && typeof prop === 'object' && 'default' in prop);
|
|
141
|
+
});
|
|
142
|
+
if (filtered.length === required.length) {
|
|
143
|
+
return schema;
|
|
144
|
+
}
|
|
145
|
+
return { ...schema, required: filtered };
|
|
146
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { NextStepDirective } from './directives.js';
|
|
2
|
+
export interface StepLogger {
|
|
3
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
4
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
5
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
6
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
7
|
+
}
|
|
8
|
+
export type FinishedStepStatus = 'dispatched' | 'succeeded' | 'failed';
|
|
9
|
+
export interface OrchestrationExecutionContext<TShared extends Record<string, unknown> = Record<string, unknown>> {
|
|
10
|
+
readonly executionId: string;
|
|
11
|
+
readonly workflowName: string;
|
|
12
|
+
readonly organizationId: string | null;
|
|
13
|
+
readonly tenantId: string | null;
|
|
14
|
+
readonly input: unknown;
|
|
15
|
+
readonly shared: TypedContextStore<TShared>;
|
|
16
|
+
readonly history: readonly StepExecutionRecord[];
|
|
17
|
+
readonly attempts: number;
|
|
18
|
+
readonly logger: StepLogger;
|
|
19
|
+
}
|
|
20
|
+
export interface TypedContextStore<TShared extends Record<string, unknown>> {
|
|
21
|
+
get<K extends keyof TShared>(key: K): TShared[K] | undefined;
|
|
22
|
+
set<K extends keyof TShared>(key: K, value: TShared[K]): void;
|
|
23
|
+
has<K extends keyof TShared>(key: K): boolean;
|
|
24
|
+
snapshot(): Partial<TShared>;
|
|
25
|
+
}
|
|
26
|
+
export interface StepExecutionRecord {
|
|
27
|
+
readonly stepName: string;
|
|
28
|
+
readonly attempt: number;
|
|
29
|
+
readonly status: FinishedStepStatus;
|
|
30
|
+
readonly input: unknown;
|
|
31
|
+
readonly output: unknown;
|
|
32
|
+
readonly error: unknown;
|
|
33
|
+
readonly nextDirective: NextStepDirective | null;
|
|
34
|
+
readonly sharedStateAfter: Record<string, unknown> | null;
|
|
35
|
+
readonly startedAt: Date;
|
|
36
|
+
readonly finishedAt: Date;
|
|
37
|
+
}
|
|
38
|
+
export declare class InMemoryContextStore<TShared extends Record<string, unknown>> implements TypedContextStore<TShared> {
|
|
39
|
+
private state;
|
|
40
|
+
constructor(initial?: Partial<TShared>);
|
|
41
|
+
get<K extends keyof TShared>(key: K): TShared[K] | undefined;
|
|
42
|
+
set<K extends keyof TShared>(key: K, value: TShared[K]): void;
|
|
43
|
+
has<K extends keyof TShared>(key: K): boolean;
|
|
44
|
+
snapshot(): Partial<TShared>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InMemoryContextStore = void 0;
|
|
4
|
+
class InMemoryContextStore {
|
|
5
|
+
constructor(initial = {}) {
|
|
6
|
+
this.state = { ...initial };
|
|
7
|
+
}
|
|
8
|
+
get(key) {
|
|
9
|
+
return this.state[key];
|
|
10
|
+
}
|
|
11
|
+
set(key, value) {
|
|
12
|
+
this.state[key] = value;
|
|
13
|
+
}
|
|
14
|
+
has(key) {
|
|
15
|
+
return key in this.state;
|
|
16
|
+
}
|
|
17
|
+
snapshot() {
|
|
18
|
+
return { ...this.state };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.InMemoryContextStore = InMemoryContextStore;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export declare const DIRECTIVE_KIND: {
|
|
2
|
+
readonly CONTINUE: "continue";
|
|
3
|
+
readonly RETRY: "retry";
|
|
4
|
+
readonly PAUSE_UNTIL_SIGNAL: "pause_until_signal";
|
|
5
|
+
readonly TERMINATE: "terminate";
|
|
6
|
+
readonly FAIL: "fail";
|
|
7
|
+
};
|
|
8
|
+
export type DirectiveKind = (typeof DIRECTIVE_KIND)[keyof typeof DIRECTIVE_KIND];
|
|
9
|
+
export type NextStepDirective = ContinueDirective | RetryDirective | PauseUntilSignalDirective | TerminateDirective | FailDirective;
|
|
10
|
+
export interface ContinueDirective {
|
|
11
|
+
readonly kind: typeof DIRECTIVE_KIND.CONTINUE;
|
|
12
|
+
readonly stepName: string;
|
|
13
|
+
readonly input?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface RetryDirective {
|
|
16
|
+
readonly kind: typeof DIRECTIVE_KIND.RETRY;
|
|
17
|
+
readonly delayMs?: number;
|
|
18
|
+
readonly reason?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface PauseUntilSignalDirective {
|
|
21
|
+
readonly kind: typeof DIRECTIVE_KIND.PAUSE_UNTIL_SIGNAL;
|
|
22
|
+
readonly signal: {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly correlationId?: string;
|
|
25
|
+
};
|
|
26
|
+
readonly timeoutMs?: number;
|
|
27
|
+
readonly resumeStep?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface TerminateDirective {
|
|
30
|
+
readonly kind: typeof DIRECTIVE_KIND.TERMINATE;
|
|
31
|
+
readonly reason?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface FailDirective {
|
|
34
|
+
readonly kind: typeof DIRECTIVE_KIND.FAIL;
|
|
35
|
+
readonly reason?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function isContinue(d: NextStepDirective): d is ContinueDirective;
|
|
38
|
+
export declare function isRetry(d: NextStepDirective): d is RetryDirective;
|
|
39
|
+
export declare function isPause(d: NextStepDirective): d is PauseUntilSignalDirective;
|
|
40
|
+
export declare function isTerminate(d: NextStepDirective): d is TerminateDirective;
|
|
41
|
+
export declare function isFail(d: NextStepDirective): d is FailDirective;
|
|
42
|
+
export interface Goto<Target extends string> {
|
|
43
|
+
readonly kind: typeof DIRECTIVE_KIND.CONTINUE;
|
|
44
|
+
readonly stepName: Target;
|
|
45
|
+
readonly input?: unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface Terminate {
|
|
48
|
+
readonly kind: typeof DIRECTIVE_KIND.TERMINATE;
|
|
49
|
+
readonly output?: unknown;
|
|
50
|
+
readonly reason?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface Fail {
|
|
53
|
+
readonly kind: typeof DIRECTIVE_KIND.FAIL;
|
|
54
|
+
readonly reason?: string;
|
|
55
|
+
readonly output?: unknown;
|
|
56
|
+
}
|
|
57
|
+
export interface Pause<Resume extends string> {
|
|
58
|
+
readonly kind: typeof DIRECTIVE_KIND.PAUSE_UNTIL_SIGNAL;
|
|
59
|
+
readonly signal: {
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly correlationId?: string;
|
|
62
|
+
};
|
|
63
|
+
readonly resumeStep?: Resume;
|
|
64
|
+
readonly timeoutMs?: number;
|
|
65
|
+
readonly output?: unknown;
|
|
66
|
+
}
|
|
67
|
+
export interface Retry {
|
|
68
|
+
readonly kind: typeof DIRECTIVE_KIND.RETRY;
|
|
69
|
+
readonly delayMs?: number;
|
|
70
|
+
readonly reason?: string;
|
|
71
|
+
}
|
|
72
|
+
export declare function goto<const Target extends string>(target: Target, output?: unknown): Goto<Target>;
|
|
73
|
+
export declare function terminate(output?: unknown, opts?: {
|
|
74
|
+
reason?: string;
|
|
75
|
+
}): Terminate;
|
|
76
|
+
export declare function fail(reason?: string, opts?: {
|
|
77
|
+
output?: unknown;
|
|
78
|
+
}): Fail;
|
|
79
|
+
export declare function pauseUntilSignal<const Resume extends string>(args: {
|
|
80
|
+
signal: string;
|
|
81
|
+
resumeStep?: Resume;
|
|
82
|
+
correlationId?: string;
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
output?: unknown;
|
|
85
|
+
}): Pause<Resume>;
|
|
86
|
+
export declare function retry(opts?: {
|
|
87
|
+
delayMs?: number;
|
|
88
|
+
reason?: string;
|
|
89
|
+
}): Retry;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DIRECTIVE_KIND = void 0;
|
|
4
|
+
exports.isContinue = isContinue;
|
|
5
|
+
exports.isRetry = isRetry;
|
|
6
|
+
exports.isPause = isPause;
|
|
7
|
+
exports.isTerminate = isTerminate;
|
|
8
|
+
exports.isFail = isFail;
|
|
9
|
+
exports.goto = goto;
|
|
10
|
+
exports.terminate = terminate;
|
|
11
|
+
exports.fail = fail;
|
|
12
|
+
exports.pauseUntilSignal = pauseUntilSignal;
|
|
13
|
+
exports.retry = retry;
|
|
14
|
+
exports.DIRECTIVE_KIND = {
|
|
15
|
+
CONTINUE: 'continue',
|
|
16
|
+
RETRY: 'retry',
|
|
17
|
+
PAUSE_UNTIL_SIGNAL: 'pause_until_signal',
|
|
18
|
+
TERMINATE: 'terminate',
|
|
19
|
+
FAIL: 'fail',
|
|
20
|
+
};
|
|
21
|
+
function isContinue(d) {
|
|
22
|
+
return d.kind === exports.DIRECTIVE_KIND.CONTINUE;
|
|
23
|
+
}
|
|
24
|
+
function isRetry(d) {
|
|
25
|
+
return d.kind === exports.DIRECTIVE_KIND.RETRY;
|
|
26
|
+
}
|
|
27
|
+
function isPause(d) {
|
|
28
|
+
return d.kind === exports.DIRECTIVE_KIND.PAUSE_UNTIL_SIGNAL;
|
|
29
|
+
}
|
|
30
|
+
function isTerminate(d) {
|
|
31
|
+
return d.kind === exports.DIRECTIVE_KIND.TERMINATE;
|
|
32
|
+
}
|
|
33
|
+
function isFail(d) {
|
|
34
|
+
return d.kind === exports.DIRECTIVE_KIND.FAIL;
|
|
35
|
+
}
|
|
36
|
+
function goto(target, output) {
|
|
37
|
+
return { kind: exports.DIRECTIVE_KIND.CONTINUE, stepName: target, input: output };
|
|
38
|
+
}
|
|
39
|
+
function terminate(output, opts) {
|
|
40
|
+
return { kind: exports.DIRECTIVE_KIND.TERMINATE, output, reason: opts?.reason };
|
|
41
|
+
}
|
|
42
|
+
function fail(reason, opts) {
|
|
43
|
+
return { kind: exports.DIRECTIVE_KIND.FAIL, reason, output: opts?.output };
|
|
44
|
+
}
|
|
45
|
+
function pauseUntilSignal(args) {
|
|
46
|
+
return {
|
|
47
|
+
kind: exports.DIRECTIVE_KIND.PAUSE_UNTIL_SIGNAL,
|
|
48
|
+
signal: { name: args.signal, correlationId: args.correlationId },
|
|
49
|
+
resumeStep: args.resumeStep,
|
|
50
|
+
timeoutMs: args.timeoutMs,
|
|
51
|
+
output: args.output,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function retry(opts) {
|
|
55
|
+
return { kind: exports.DIRECTIVE_KIND.RETRY, delayMs: opts?.delayMs, reason: opts?.reason };
|
|
56
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { $ZodIssue } from 'zod/v4/core';
|
|
2
|
+
export declare class WorkflowError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class StepInputValidationError extends WorkflowError {
|
|
6
|
+
readonly stepName: string;
|
|
7
|
+
readonly issues: readonly $ZodIssue[];
|
|
8
|
+
constructor(stepName: string, issues: readonly $ZodIssue[]);
|
|
9
|
+
}
|
|
10
|
+
export declare class UnknownStepError extends WorkflowError {
|
|
11
|
+
readonly stepName: string;
|
|
12
|
+
constructor(stepName: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class DisallowedTransitionError extends WorkflowError {
|
|
15
|
+
readonly stepName: string;
|
|
16
|
+
readonly directiveKind: string;
|
|
17
|
+
readonly target?: string;
|
|
18
|
+
constructor(stepName: string, directiveKind: string, target?: string);
|
|
19
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DisallowedTransitionError = exports.UnknownStepError = exports.StepInputValidationError = exports.WorkflowError = void 0;
|
|
4
|
+
class WorkflowError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'WorkflowError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.WorkflowError = WorkflowError;
|
|
11
|
+
class StepInputValidationError extends WorkflowError {
|
|
12
|
+
constructor(stepName, issues) {
|
|
13
|
+
super(`Input for step '${stepName}' failed validation: ${formatIssues(issues)}`);
|
|
14
|
+
this.name = 'StepInputValidationError';
|
|
15
|
+
this.stepName = stepName;
|
|
16
|
+
this.issues = issues;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.StepInputValidationError = StepInputValidationError;
|
|
20
|
+
function formatIssues(issues) {
|
|
21
|
+
if (issues.length === 0)
|
|
22
|
+
return 'unknown validation error';
|
|
23
|
+
return issues
|
|
24
|
+
.map((issue) => {
|
|
25
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : '(root)';
|
|
26
|
+
return `${path}: ${issue.message}`;
|
|
27
|
+
})
|
|
28
|
+
.join('; ');
|
|
29
|
+
}
|
|
30
|
+
class UnknownStepError extends WorkflowError {
|
|
31
|
+
constructor(stepName) {
|
|
32
|
+
super(`Unknown step: ${stepName}`);
|
|
33
|
+
this.name = 'UnknownStepError';
|
|
34
|
+
this.stepName = stepName;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.UnknownStepError = UnknownStepError;
|
|
38
|
+
class DisallowedTransitionError extends WorkflowError {
|
|
39
|
+
constructor(stepName, directiveKind, target) {
|
|
40
|
+
super(`Step '${stepName}' returned a '${directiveKind}' directive` +
|
|
41
|
+
(target ? ` to '${target}'` : '') +
|
|
42
|
+
` that is not in its declared transitions`);
|
|
43
|
+
this.name = 'DisallowedTransitionError';
|
|
44
|
+
this.stepName = stepName;
|
|
45
|
+
this.directiveKind = directiveKind;
|
|
46
|
+
this.target = target;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.DisallowedTransitionError = DisallowedTransitionError;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { DIRECTIVE_KIND, isContinue, isRetry, isPause, isTerminate, isFail } from './directives.js';
|
|
2
|
+
export type { DirectiveKind, NextStepDirective, ContinueDirective, RetryDirective, PauseUntilSignalDirective, TerminateDirective, FailDirective, } from './directives.js';
|
|
3
|
+
export { goto, terminate, fail, pauseUntilSignal, retry } from './directives.js';
|
|
4
|
+
export type { Goto, Terminate, Fail, Pause, Retry } from './directives.js';
|
|
5
|
+
export { defineStep } from './step.js';
|
|
6
|
+
export type { Step, StepResult, StepDefinition, Allowed } from './step.js';
|
|
7
|
+
export type { OrchestrationExecutionContext, TypedContextStore, StepExecutionRecord, StepLogger, FinishedStepStatus, } from './context.js';
|
|
8
|
+
export { InMemoryContextStore } from './context.js';
|
|
9
|
+
export type { OrchestrationDefinition } from './workflow.js';
|
|
10
|
+
export { defineOrchestration, isOrchestrationDefinition, ORCHESTRATION_DEFINITION_BRAND } from './workflow.js';
|
|
11
|
+
export { WorkflowError, UnknownStepError, StepInputValidationError, DisallowedTransitionError } from './errors.js';
|
|
12
|
+
export { zodToJsonSchema, exampleFromJsonSchema, stepInputContract, workflowInputContract } from './introspection.js';
|
|
13
|
+
export type { StepInputContract, WorkflowInputContract } from './introspection.js';
|
|
14
|
+
export { MANIFEST_PROTOCOL, workflowManifestSchema } from './manifest.js';
|
|
15
|
+
export type { WorkflowManifest, WorkflowStepManifest, ManifestTransition } from './manifest.js';
|
|
16
|
+
export { buildManifest, validateGraph, assertValidGraph } from './build-manifest.js';
|
|
17
|
+
export type { GraphValidation } from './build-manifest.js';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertValidGraph = exports.validateGraph = exports.buildManifest = exports.workflowManifestSchema = exports.MANIFEST_PROTOCOL = exports.workflowInputContract = exports.stepInputContract = exports.exampleFromJsonSchema = exports.zodToJsonSchema = exports.DisallowedTransitionError = exports.StepInputValidationError = exports.UnknownStepError = exports.WorkflowError = exports.ORCHESTRATION_DEFINITION_BRAND = exports.isOrchestrationDefinition = exports.defineOrchestration = exports.InMemoryContextStore = exports.defineStep = exports.retry = exports.pauseUntilSignal = exports.terminate = exports.goto = exports.isFail = exports.isTerminate = exports.isPause = exports.isRetry = exports.isContinue = exports.DIRECTIVE_KIND = void 0;
|
|
4
|
+
var directives_js_1 = require("./directives.js");
|
|
5
|
+
Object.defineProperty(exports, "DIRECTIVE_KIND", { enumerable: true, get: function () { return directives_js_1.DIRECTIVE_KIND; } });
|
|
6
|
+
Object.defineProperty(exports, "isContinue", { enumerable: true, get: function () { return directives_js_1.isContinue; } });
|
|
7
|
+
Object.defineProperty(exports, "isRetry", { enumerable: true, get: function () { return directives_js_1.isRetry; } });
|
|
8
|
+
Object.defineProperty(exports, "isPause", { enumerable: true, get: function () { return directives_js_1.isPause; } });
|
|
9
|
+
Object.defineProperty(exports, "isTerminate", { enumerable: true, get: function () { return directives_js_1.isTerminate; } });
|
|
10
|
+
Object.defineProperty(exports, "isFail", { enumerable: true, get: function () { return directives_js_1.isFail; } });
|
|
11
|
+
var directives_js_2 = require("./directives.js");
|
|
12
|
+
Object.defineProperty(exports, "goto", { enumerable: true, get: function () { return directives_js_2.goto; } });
|
|
13
|
+
Object.defineProperty(exports, "terminate", { enumerable: true, get: function () { return directives_js_2.terminate; } });
|
|
14
|
+
Object.defineProperty(exports, "fail", { enumerable: true, get: function () { return directives_js_2.fail; } });
|
|
15
|
+
Object.defineProperty(exports, "pauseUntilSignal", { enumerable: true, get: function () { return directives_js_2.pauseUntilSignal; } });
|
|
16
|
+
Object.defineProperty(exports, "retry", { enumerable: true, get: function () { return directives_js_2.retry; } });
|
|
17
|
+
var step_js_1 = require("./step.js");
|
|
18
|
+
Object.defineProperty(exports, "defineStep", { enumerable: true, get: function () { return step_js_1.defineStep; } });
|
|
19
|
+
var context_js_1 = require("./context.js");
|
|
20
|
+
Object.defineProperty(exports, "InMemoryContextStore", { enumerable: true, get: function () { return context_js_1.InMemoryContextStore; } });
|
|
21
|
+
var workflow_js_1 = require("./workflow.js");
|
|
22
|
+
Object.defineProperty(exports, "defineOrchestration", { enumerable: true, get: function () { return workflow_js_1.defineOrchestration; } });
|
|
23
|
+
Object.defineProperty(exports, "isOrchestrationDefinition", { enumerable: true, get: function () { return workflow_js_1.isOrchestrationDefinition; } });
|
|
24
|
+
Object.defineProperty(exports, "ORCHESTRATION_DEFINITION_BRAND", { enumerable: true, get: function () { return workflow_js_1.ORCHESTRATION_DEFINITION_BRAND; } });
|
|
25
|
+
var errors_js_1 = require("./errors.js");
|
|
26
|
+
Object.defineProperty(exports, "WorkflowError", { enumerable: true, get: function () { return errors_js_1.WorkflowError; } });
|
|
27
|
+
Object.defineProperty(exports, "UnknownStepError", { enumerable: true, get: function () { return errors_js_1.UnknownStepError; } });
|
|
28
|
+
Object.defineProperty(exports, "StepInputValidationError", { enumerable: true, get: function () { return errors_js_1.StepInputValidationError; } });
|
|
29
|
+
Object.defineProperty(exports, "DisallowedTransitionError", { enumerable: true, get: function () { return errors_js_1.DisallowedTransitionError; } });
|
|
30
|
+
var introspection_js_1 = require("./introspection.js");
|
|
31
|
+
Object.defineProperty(exports, "zodToJsonSchema", { enumerable: true, get: function () { return introspection_js_1.zodToJsonSchema; } });
|
|
32
|
+
Object.defineProperty(exports, "exampleFromJsonSchema", { enumerable: true, get: function () { return introspection_js_1.exampleFromJsonSchema; } });
|
|
33
|
+
Object.defineProperty(exports, "stepInputContract", { enumerable: true, get: function () { return introspection_js_1.stepInputContract; } });
|
|
34
|
+
Object.defineProperty(exports, "workflowInputContract", { enumerable: true, get: function () { return introspection_js_1.workflowInputContract; } });
|
|
35
|
+
var manifest_js_1 = require("./manifest.js");
|
|
36
|
+
Object.defineProperty(exports, "MANIFEST_PROTOCOL", { enumerable: true, get: function () { return manifest_js_1.MANIFEST_PROTOCOL; } });
|
|
37
|
+
Object.defineProperty(exports, "workflowManifestSchema", { enumerable: true, get: function () { return manifest_js_1.workflowManifestSchema; } });
|
|
38
|
+
var build_manifest_js_1 = require("./build-manifest.js");
|
|
39
|
+
Object.defineProperty(exports, "buildManifest", { enumerable: true, get: function () { return build_manifest_js_1.buildManifest; } });
|
|
40
|
+
Object.defineProperty(exports, "validateGraph", { enumerable: true, get: function () { return build_manifest_js_1.validateGraph; } });
|
|
41
|
+
Object.defineProperty(exports, "assertValidGraph", { enumerable: true, get: function () { return build_manifest_js_1.assertValidGraph; } });
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import type { OrchestrationDefinition } from './workflow.js';
|
|
3
|
+
export interface StepInputContract {
|
|
4
|
+
readonly jsonSchema: Record<string, unknown>;
|
|
5
|
+
readonly example: unknown;
|
|
6
|
+
}
|
|
7
|
+
export type WorkflowInputContract = StepInputContract;
|
|
8
|
+
export declare function zodToJsonSchema(schema: z.ZodType): Record<string, unknown>;
|
|
9
|
+
export declare function stepInputContract(def: OrchestrationDefinition<unknown, Record<string, unknown>>, stepName: string): StepInputContract | null;
|
|
10
|
+
export declare function workflowInputContract(def: OrchestrationDefinition<unknown, Record<string, unknown>>): StepInputContract | null;
|
|
11
|
+
export declare function exampleFromJsonSchema(jsonSchema: Record<string, unknown>): unknown;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zodToJsonSchema = zodToJsonSchema;
|
|
4
|
+
exports.stepInputContract = stepInputContract;
|
|
5
|
+
exports.workflowInputContract = workflowInputContract;
|
|
6
|
+
exports.exampleFromJsonSchema = exampleFromJsonSchema;
|
|
7
|
+
const v4_1 = require("zod/v4");
|
|
8
|
+
function zodToJsonSchema(schema) {
|
|
9
|
+
return v4_1.z.toJSONSchema(schema);
|
|
10
|
+
}
|
|
11
|
+
function stepInputContract(def, stepName) {
|
|
12
|
+
const schema = def.steps[stepName]?.inputSchema;
|
|
13
|
+
if (!schema)
|
|
14
|
+
return null;
|
|
15
|
+
const jsonSchema = zodToJsonSchema(schema);
|
|
16
|
+
return { jsonSchema, example: exampleFromJsonSchema(jsonSchema) };
|
|
17
|
+
}
|
|
18
|
+
function workflowInputContract(def) {
|
|
19
|
+
return stepInputContract(def, def.entry);
|
|
20
|
+
}
|
|
21
|
+
function exampleFromJsonSchema(jsonSchema) {
|
|
22
|
+
const examples = jsonSchema.examples;
|
|
23
|
+
if (Array.isArray(examples) && examples.length > 0) {
|
|
24
|
+
return examples[0];
|
|
25
|
+
}
|
|
26
|
+
if ('example' in jsonSchema && jsonSchema.example !== undefined) {
|
|
27
|
+
return jsonSchema.example;
|
|
28
|
+
}
|
|
29
|
+
return skeletonFromJsonSchema(jsonSchema);
|
|
30
|
+
}
|
|
31
|
+
function skeletonFromJsonSchema(schema) {
|
|
32
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
33
|
+
return schema.enum[0];
|
|
34
|
+
}
|
|
35
|
+
const branches = (schema.anyOf ?? schema.oneOf);
|
|
36
|
+
if (Array.isArray(branches) && branches.length > 0) {
|
|
37
|
+
return skeletonFromJsonSchema(branches[0]);
|
|
38
|
+
}
|
|
39
|
+
switch (schema.type) {
|
|
40
|
+
case 'object': {
|
|
41
|
+
const props = (schema.properties ?? {});
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const [key, value] of Object.entries(props)) {
|
|
44
|
+
out[key] = skeletonFromJsonSchema(value);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
case 'array':
|
|
49
|
+
return [];
|
|
50
|
+
case 'string':
|
|
51
|
+
return '';
|
|
52
|
+
case 'number':
|
|
53
|
+
case 'integer':
|
|
54
|
+
return 0;
|
|
55
|
+
case 'boolean':
|
|
56
|
+
return false;
|
|
57
|
+
case 'null':
|
|
58
|
+
return null;
|
|
59
|
+
default:
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|