@contractspec/lib.contracts 1.50.0 → 1.52.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/dist/app-config/contracts.d.ts +51 -51
- package/dist/app-config/events.d.ts +27 -27
- package/dist/app-config/lifecycle-contracts.d.ts +55 -55
- package/dist/app-config/runtime.d.ts +1 -1
- package/dist/app-config/spec.d.ts +1 -1
- package/dist/capabilities/capabilities.d.ts +40 -4
- package/dist/capabilities/capabilities.js +125 -0
- package/dist/capabilities/context.d.ts +88 -0
- package/dist/capabilities/context.js +87 -0
- package/dist/capabilities/docs/capabilities.docblock.js +191 -2
- package/dist/capabilities/guards.d.ts +110 -0
- package/dist/capabilities/guards.js +146 -0
- package/dist/capabilities/index.d.ts +4 -1
- package/dist/capabilities/index.js +4 -1
- package/dist/capabilities/validation.d.ts +76 -0
- package/dist/capabilities/validation.js +141 -0
- package/dist/client/react/feature-render.d.ts +2 -2
- package/dist/contract-registry/schemas.d.ts +4 -4
- package/dist/data-views/runtime.d.ts +1 -1
- package/dist/events.d.ts +6 -0
- package/dist/examples/schema.d.ts +7 -7
- package/dist/experiments/spec.d.ts +1 -1
- package/dist/features/install.d.ts +4 -4
- package/dist/features/types.d.ts +4 -4
- package/dist/index.d.ts +21 -13
- package/dist/index.js +11 -3
- package/dist/install.d.ts +1 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +67 -67
- package/dist/integrations/openbanking/contracts/balances.d.ts +35 -35
- package/dist/integrations/openbanking/contracts/transactions.d.ts +49 -49
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/operations.d.ts +103 -103
- package/dist/integrations/spec.d.ts +1 -1
- package/dist/knowledge/operations.d.ts +67 -67
- package/dist/llm/exporters.d.ts +2 -2
- package/dist/markdown.d.ts +1 -1
- package/dist/onboarding-base.d.ts +29 -29
- package/dist/operations/operation.d.ts +6 -0
- package/dist/policy/context.d.ts +237 -0
- package/dist/policy/context.js +227 -0
- package/dist/policy/guards.d.ts +145 -0
- package/dist/policy/guards.js +254 -0
- package/dist/policy/index.d.ts +12 -1
- package/dist/policy/index.js +11 -1
- package/dist/policy/spec.d.ts +1 -1
- package/dist/policy/validation.d.ts +67 -0
- package/dist/policy/validation.js +307 -0
- package/dist/presentations/presentations.d.ts +6 -0
- package/dist/tests/spec.d.ts +1 -1
- package/dist/themes.d.ts +1 -1
- package/dist/translations/index.d.ts +6 -0
- package/dist/translations/index.js +5 -0
- package/dist/translations/registry.d.ts +144 -0
- package/dist/translations/registry.js +223 -0
- package/dist/translations/spec.d.ts +126 -0
- package/dist/translations/spec.js +31 -0
- package/dist/translations/validation.d.ts +85 -0
- package/dist/translations/validation.js +328 -0
- package/dist/workflow/context.d.ts +191 -0
- package/dist/workflow/context.js +227 -0
- package/dist/workflow/index.d.ts +4 -2
- package/dist/workflow/index.js +4 -2
- package/dist/workflow/spec.d.ts +1 -1
- package/dist/workflow/validation.d.ts +64 -2
- package/dist/workflow/validation.js +194 -1
- package/package.json +18 -6
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
//#region src/workflow/context.ts
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when a workflow operation fails.
|
|
4
|
+
*/
|
|
5
|
+
var WorkflowContextError = class extends Error {
|
|
6
|
+
errorType;
|
|
7
|
+
workflowId;
|
|
8
|
+
details;
|
|
9
|
+
constructor(type, workflowId, message, details) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "WorkflowContextError";
|
|
12
|
+
this.errorType = type;
|
|
13
|
+
this.workflowId = workflowId;
|
|
14
|
+
this.details = details;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var WorkflowContextImpl = class {
|
|
18
|
+
constructor(state, spec) {
|
|
19
|
+
this.state = state;
|
|
20
|
+
this.spec = spec;
|
|
21
|
+
}
|
|
22
|
+
get workflowId() {
|
|
23
|
+
return this.state.workflowId;
|
|
24
|
+
}
|
|
25
|
+
get workflowKey() {
|
|
26
|
+
return this.state.workflowName;
|
|
27
|
+
}
|
|
28
|
+
get workflowVersion() {
|
|
29
|
+
return this.state.workflowVersion;
|
|
30
|
+
}
|
|
31
|
+
get currentStep() {
|
|
32
|
+
return this.state.currentStep;
|
|
33
|
+
}
|
|
34
|
+
get status() {
|
|
35
|
+
return this.state.status;
|
|
36
|
+
}
|
|
37
|
+
get data() {
|
|
38
|
+
return this.state.data;
|
|
39
|
+
}
|
|
40
|
+
get history() {
|
|
41
|
+
return this.state.history;
|
|
42
|
+
}
|
|
43
|
+
getState() {
|
|
44
|
+
return this.state;
|
|
45
|
+
}
|
|
46
|
+
getData(key) {
|
|
47
|
+
return this.state.data[key];
|
|
48
|
+
}
|
|
49
|
+
isTerminal() {
|
|
50
|
+
return this.state.status === "completed" || this.state.status === "failed" || this.state.status === "cancelled";
|
|
51
|
+
}
|
|
52
|
+
isRunning() {
|
|
53
|
+
return this.state.status === "running";
|
|
54
|
+
}
|
|
55
|
+
getCurrentStepDef() {
|
|
56
|
+
return this.spec.definition.steps.find((s) => s.id === this.state.currentStep);
|
|
57
|
+
}
|
|
58
|
+
getRetryCount(stepId) {
|
|
59
|
+
const id = stepId ?? this.state.currentStep;
|
|
60
|
+
return this.state.retryCounts?.[id] ?? 0;
|
|
61
|
+
}
|
|
62
|
+
canTransition(toStepId) {
|
|
63
|
+
return this.spec.definition.transitions.filter((t) => t.from === this.state.currentStep && t.to === toStepId).length > 0;
|
|
64
|
+
}
|
|
65
|
+
getAvailableTransitions() {
|
|
66
|
+
return this.spec.definition.transitions.filter((t) => t.from === this.state.currentStep).map((t) => ({
|
|
67
|
+
from: t.from,
|
|
68
|
+
to: t.to,
|
|
69
|
+
label: t.label,
|
|
70
|
+
condition: t.condition
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
hasNextStep() {
|
|
74
|
+
return this.spec.definition.transitions.some((t) => t.from === this.state.currentStep);
|
|
75
|
+
}
|
|
76
|
+
getRemainingTime(slaKey) {
|
|
77
|
+
const sla = this.spec.definition.sla;
|
|
78
|
+
if (!sla) return null;
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
if (slaKey === "totalDuration") {
|
|
81
|
+
if (!sla.totalDurationMs) return null;
|
|
82
|
+
const elapsed$1 = now - this.state.createdAt.getTime();
|
|
83
|
+
return Math.max(0, sla.totalDurationMs - elapsed$1);
|
|
84
|
+
}
|
|
85
|
+
const stepLimit = sla.stepDurationMs?.[slaKey];
|
|
86
|
+
if (!stepLimit) return null;
|
|
87
|
+
const stepExecution = this.state.history.find((h) => h.stepId === slaKey && h.status === "running");
|
|
88
|
+
if (!stepExecution) return stepLimit;
|
|
89
|
+
const elapsed = now - stepExecution.startedAt.getTime();
|
|
90
|
+
return Math.max(0, stepLimit - elapsed);
|
|
91
|
+
}
|
|
92
|
+
isSlaViolated(slaKey) {
|
|
93
|
+
const remaining = this.getRemainingTime(slaKey);
|
|
94
|
+
return remaining !== null && remaining <= 0;
|
|
95
|
+
}
|
|
96
|
+
getAllSlaStatuses() {
|
|
97
|
+
const sla = this.spec.definition.sla;
|
|
98
|
+
if (!sla) return [];
|
|
99
|
+
const statuses = [];
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
if (sla.totalDurationMs) {
|
|
102
|
+
const elapsed = now - this.state.createdAt.getTime();
|
|
103
|
+
const remaining = Math.max(0, sla.totalDurationMs - elapsed);
|
|
104
|
+
statuses.push({
|
|
105
|
+
key: "totalDuration",
|
|
106
|
+
type: "workflow",
|
|
107
|
+
limitMs: sla.totalDurationMs,
|
|
108
|
+
elapsedMs: elapsed,
|
|
109
|
+
remainingMs: remaining,
|
|
110
|
+
violated: remaining <= 0,
|
|
111
|
+
percentUsed: elapsed / sla.totalDurationMs * 100
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (sla.stepDurationMs) for (const [stepId, limitMs] of Object.entries(sla.stepDurationMs)) {
|
|
115
|
+
const stepExecution = this.state.history.find((h) => h.stepId === stepId && h.status === "running");
|
|
116
|
+
const elapsed = stepExecution ? now - stepExecution.startedAt.getTime() : 0;
|
|
117
|
+
const remaining = Math.max(0, limitMs - elapsed);
|
|
118
|
+
statuses.push({
|
|
119
|
+
key: stepId,
|
|
120
|
+
type: "step",
|
|
121
|
+
stepId,
|
|
122
|
+
limitMs,
|
|
123
|
+
elapsedMs: elapsed,
|
|
124
|
+
remainingMs: remaining,
|
|
125
|
+
violated: stepExecution !== void 0 && remaining <= 0,
|
|
126
|
+
percentUsed: elapsed / limitMs * 100
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return statuses;
|
|
130
|
+
}
|
|
131
|
+
hasCompensation() {
|
|
132
|
+
return this.spec.definition.compensation !== void 0;
|
|
133
|
+
}
|
|
134
|
+
getCompensableSteps() {
|
|
135
|
+
const compensation = this.spec.definition.compensation;
|
|
136
|
+
if (!compensation) return [];
|
|
137
|
+
return compensation.steps.map((s) => s.stepId);
|
|
138
|
+
}
|
|
139
|
+
getEvents() {
|
|
140
|
+
const events = [];
|
|
141
|
+
for (const execution of this.state.history) {
|
|
142
|
+
events.push({
|
|
143
|
+
timestamp: execution.startedAt,
|
|
144
|
+
type: "step_started",
|
|
145
|
+
stepId: execution.stepId,
|
|
146
|
+
input: execution.input
|
|
147
|
+
});
|
|
148
|
+
if (execution.completedAt) {
|
|
149
|
+
if (execution.status === "completed") events.push({
|
|
150
|
+
timestamp: execution.completedAt,
|
|
151
|
+
type: "step_completed",
|
|
152
|
+
stepId: execution.stepId,
|
|
153
|
+
output: execution.output
|
|
154
|
+
});
|
|
155
|
+
else if (execution.status === "failed") events.push({
|
|
156
|
+
timestamp: execution.completedAt,
|
|
157
|
+
type: "step_failed",
|
|
158
|
+
stepId: execution.stepId,
|
|
159
|
+
error: execution.error
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
164
|
+
return events;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Creates a workflow context from state and spec.
|
|
169
|
+
*
|
|
170
|
+
* @param state - Current workflow state
|
|
171
|
+
* @param spec - Workflow specification
|
|
172
|
+
* @returns WorkflowContext for interacting with the workflow
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const state = await runner.getState(workflowId);
|
|
177
|
+
* const spec = registry.get(state.workflowName, state.workflowVersion);
|
|
178
|
+
* const ctx = createWorkflowContext(state, spec);
|
|
179
|
+
*
|
|
180
|
+
* console.log('Current step:', ctx.currentStep);
|
|
181
|
+
* console.log('Available transitions:', ctx.getAvailableTransitions());
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
function createWorkflowContext(state, spec) {
|
|
185
|
+
return new WorkflowContextImpl(state, spec);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Calculate workflow progress as a percentage.
|
|
189
|
+
*
|
|
190
|
+
* @param ctx - Workflow context
|
|
191
|
+
* @returns Progress percentage (0-100)
|
|
192
|
+
*/
|
|
193
|
+
function calculateWorkflowProgress(ctx) {
|
|
194
|
+
const state = ctx.getState();
|
|
195
|
+
const completedSteps = new Set(state.history.filter((h) => h.status === "completed").map((h) => h.stepId));
|
|
196
|
+
completedSteps.size + (ctx.isTerminal() ? 0 : 1);
|
|
197
|
+
if (ctx.status === "completed") return 100;
|
|
198
|
+
if (ctx.status === "failed" || ctx.status === "cancelled") return completedSteps.size > 0 ? Math.min(99, completedSteps.size * 20) : 0;
|
|
199
|
+
return Math.min(99, completedSteps.size * 20);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get the duration of a workflow in milliseconds.
|
|
203
|
+
*
|
|
204
|
+
* @param ctx - Workflow context
|
|
205
|
+
* @returns Duration in milliseconds
|
|
206
|
+
*/
|
|
207
|
+
function getWorkflowDuration(ctx) {
|
|
208
|
+
const state = ctx.getState();
|
|
209
|
+
return (ctx.isTerminal() ? state.updatedAt.getTime() : Date.now()) - state.createdAt.getTime();
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get the average step duration in milliseconds.
|
|
213
|
+
*
|
|
214
|
+
* @param ctx - Workflow context
|
|
215
|
+
* @returns Average duration or 0 if no completed steps
|
|
216
|
+
*/
|
|
217
|
+
function getAverageStepDuration(ctx) {
|
|
218
|
+
const completedSteps = ctx.history.filter((h) => h.status === "completed" && h.completedAt);
|
|
219
|
+
if (completedSteps.length === 0) return 0;
|
|
220
|
+
return completedSteps.reduce((sum, step) => {
|
|
221
|
+
if (!step.completedAt) return sum;
|
|
222
|
+
return sum + (step.completedAt.getTime() - step.startedAt.getTime());
|
|
223
|
+
}, 0) / completedSteps.length;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
//#endregion
|
|
227
|
+
export { WorkflowContextError, calculateWorkflowProgress, createWorkflowContext, getAverageStepDuration, getWorkflowDuration };
|
package/dist/workflow/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FormRef } from "../features/types.js";
|
|
2
2
|
import { CompensationStep, CompensationStrategy, GuardCondition, GuardConditionKind, RetryPolicy, SLA, Step, StepAction, StepType, Transition, WorkflowDefinition, WorkflowMeta, WorkflowRegistry, WorkflowSpec, WorkflowStatus } from "./spec.js";
|
|
3
|
-
import { ValidateWorkflowSpecOptions, WorkflowValidationError, WorkflowValidationIssue, WorkflowValidationLevel, assertWorkflowSpecValid, validateWorkflowSpec } from "./validation.js";
|
|
3
|
+
import { ValidateWorkflowSpecOptions, WorkflowConsistencyDeps, WorkflowValidationError, WorkflowValidationIssue, WorkflowValidationLevel, WorkflowValidationResult, assertWorkflowConsistency, assertWorkflowSpecValid, validateCompensation, validateRetryConfig, validateSlaConfig, validateWorkflowComprehensive, validateWorkflowConsistency, validateWorkflowSpec } from "./validation.js";
|
|
4
4
|
import { StateStore, StepExecution, WorkflowState, WorkflowStateFilters } from "./state.js";
|
|
5
5
|
import { GuardContext, GuardEvaluator, OperationExecutor, OperationExecutorContext, WorkflowPreFlightError, WorkflowPreFlightIssue, WorkflowPreFlightIssueSeverity, WorkflowPreFlightIssueType, WorkflowPreFlightResult, WorkflowRunner, WorkflowRunnerConfig } from "./runner.js";
|
|
6
6
|
import { ExpressionContext, evaluateExpression } from "./expression.js";
|
|
@@ -8,6 +8,8 @@ import { InMemoryStateStore } from "./adapters/memory-store.js";
|
|
|
8
8
|
import { PrismaStateStore } from "./adapters/db-adapter.js";
|
|
9
9
|
import { FileStateStoreOptions, createFileStateStore } from "./adapters/file-adapter.js";
|
|
10
10
|
import "./adapters/index.js";
|
|
11
|
+
import { AvailableTransition, SlaStatus, WorkflowContext, WorkflowContextError, WorkflowContextErrorType, WorkflowEvent, WorkflowTransitionResult, calculateWorkflowProgress, createWorkflowContext, getAverageStepDuration, getWorkflowDuration } from "./context.js";
|
|
12
|
+
import { SLABreachEvent, SLAMonitor } from "./sla-monitor.js";
|
|
11
13
|
|
|
12
14
|
//#region src/workflow/index.d.ts
|
|
13
15
|
/**
|
|
@@ -15,4 +17,4 @@ import "./adapters/index.js";
|
|
|
15
17
|
*/
|
|
16
18
|
declare const defineWorkflow: (spec: WorkflowSpec) => WorkflowSpec;
|
|
17
19
|
//#endregion
|
|
18
|
-
export { CompensationStep, CompensationStrategy, ExpressionContext, FileStateStoreOptions, FormRef, GuardCondition, GuardConditionKind, GuardContext, GuardEvaluator, InMemoryStateStore, OperationExecutor, OperationExecutorContext, PrismaStateStore, RetryPolicy, SLA, StateStore, Step, StepAction, StepExecution, StepType, Transition, ValidateWorkflowSpecOptions, WorkflowDefinition, WorkflowMeta, WorkflowPreFlightError, WorkflowPreFlightIssue, WorkflowPreFlightIssueSeverity, WorkflowPreFlightIssueType, WorkflowPreFlightResult, WorkflowRegistry, WorkflowRunner, WorkflowRunnerConfig, WorkflowSpec, WorkflowState, WorkflowStateFilters, WorkflowStatus, WorkflowValidationError, WorkflowValidationIssue, WorkflowValidationLevel, assertWorkflowSpecValid, createFileStateStore, defineWorkflow, evaluateExpression, validateWorkflowSpec };
|
|
20
|
+
export { AvailableTransition, CompensationStep, CompensationStrategy, ExpressionContext, FileStateStoreOptions, FormRef, GuardCondition, GuardConditionKind, GuardContext, GuardEvaluator, InMemoryStateStore, OperationExecutor, OperationExecutorContext, PrismaStateStore, RetryPolicy, SLA, SLABreachEvent, SLAMonitor, SlaStatus, StateStore, Step, StepAction, StepExecution, StepType, Transition, ValidateWorkflowSpecOptions, WorkflowConsistencyDeps, WorkflowContext, WorkflowContextError, WorkflowContextErrorType, WorkflowDefinition, WorkflowEvent, WorkflowMeta, WorkflowPreFlightError, WorkflowPreFlightIssue, WorkflowPreFlightIssueSeverity, WorkflowPreFlightIssueType, WorkflowPreFlightResult, WorkflowRegistry, WorkflowRunner, WorkflowRunnerConfig, WorkflowSpec, WorkflowState, WorkflowStateFilters, WorkflowStatus, WorkflowTransitionResult, WorkflowValidationError, WorkflowValidationIssue, WorkflowValidationLevel, WorkflowValidationResult, assertWorkflowConsistency, assertWorkflowSpecValid, calculateWorkflowProgress, createFileStateStore, createWorkflowContext, defineWorkflow, evaluateExpression, getAverageStepDuration, getWorkflowDuration, validateCompensation, validateRetryConfig, validateSlaConfig, validateWorkflowComprehensive, validateWorkflowConsistency, validateWorkflowSpec };
|
package/dist/workflow/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { WorkflowRegistry } from "./spec.js";
|
|
2
|
-
import { WorkflowValidationError, assertWorkflowSpecValid, validateWorkflowSpec } from "./validation.js";
|
|
2
|
+
import { WorkflowValidationError, assertWorkflowConsistency, assertWorkflowSpecValid, validateCompensation, validateRetryConfig, validateSlaConfig, validateWorkflowComprehensive, validateWorkflowConsistency, validateWorkflowSpec } from "./validation.js";
|
|
3
3
|
import { evaluateExpression } from "./expression.js";
|
|
4
4
|
import { WorkflowPreFlightError, WorkflowRunner } from "./runner.js";
|
|
5
5
|
import { InMemoryStateStore } from "./adapters/memory-store.js";
|
|
6
6
|
import { PrismaStateStore } from "./adapters/db-adapter.js";
|
|
7
7
|
import { createFileStateStore } from "./adapters/file-adapter.js";
|
|
8
|
+
import { WorkflowContextError, calculateWorkflowProgress, createWorkflowContext, getAverageStepDuration, getWorkflowDuration } from "./context.js";
|
|
9
|
+
import { SLAMonitor } from "./sla-monitor.js";
|
|
8
10
|
|
|
9
11
|
//#region src/workflow/index.ts
|
|
10
12
|
/**
|
|
@@ -13,4 +15,4 @@ import { createFileStateStore } from "./adapters/file-adapter.js";
|
|
|
13
15
|
const defineWorkflow = (spec) => spec;
|
|
14
16
|
|
|
15
17
|
//#endregion
|
|
16
|
-
export { InMemoryStateStore, PrismaStateStore, WorkflowPreFlightError, WorkflowRegistry, WorkflowRunner, WorkflowValidationError, assertWorkflowSpecValid, createFileStateStore, defineWorkflow, evaluateExpression, validateWorkflowSpec };
|
|
18
|
+
export { InMemoryStateStore, PrismaStateStore, SLAMonitor, WorkflowContextError, WorkflowPreFlightError, WorkflowRegistry, WorkflowRunner, WorkflowValidationError, assertWorkflowConsistency, assertWorkflowSpecValid, calculateWorkflowProgress, createFileStateStore, createWorkflowContext, defineWorkflow, evaluateExpression, getAverageStepDuration, getWorkflowDuration, validateCompensation, validateRetryConfig, validateSlaConfig, validateWorkflowComprehensive, validateWorkflowConsistency, validateWorkflowSpec };
|
package/dist/workflow/spec.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { OwnerShipMeta } from "../ownership.js";
|
|
2
1
|
import { CapabilityRef } from "../capabilities/capabilities.js";
|
|
2
|
+
import { OwnerShipMeta } from "../ownership.js";
|
|
3
3
|
import "../capabilities/index.js";
|
|
4
4
|
import { ExperimentRef } from "../experiments/spec.js";
|
|
5
5
|
import { FormRef, OpRef } from "../features/types.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { CapabilityRegistry } from "../capabilities/capabilities.js";
|
|
1
2
|
import { OperationSpecRegistry } from "../operations/registry.js";
|
|
2
|
-
import { WorkflowSpec } from "./spec.js";
|
|
3
|
+
import { WorkflowRegistry, WorkflowSpec } from "./spec.js";
|
|
4
|
+
import { EventRegistry } from "../events.js";
|
|
3
5
|
import { FormRegistry } from "../forms/forms.js";
|
|
4
6
|
import "../forms/index.js";
|
|
5
7
|
|
|
@@ -25,5 +27,65 @@ declare class WorkflowValidationError extends Error {
|
|
|
25
27
|
*/
|
|
26
28
|
declare function validateWorkflowSpec(spec: WorkflowSpec, options?: ValidateWorkflowSpecOptions): WorkflowValidationIssue[];
|
|
27
29
|
declare function assertWorkflowSpecValid(spec: WorkflowSpec, options?: ValidateWorkflowSpecOptions): void;
|
|
30
|
+
interface WorkflowConsistencyDeps {
|
|
31
|
+
workflows: WorkflowRegistry;
|
|
32
|
+
operations?: OperationSpecRegistry;
|
|
33
|
+
forms?: FormRegistry;
|
|
34
|
+
events?: EventRegistry;
|
|
35
|
+
capabilities?: CapabilityRegistry;
|
|
36
|
+
}
|
|
37
|
+
interface WorkflowValidationResult {
|
|
38
|
+
valid: boolean;
|
|
39
|
+
issues: WorkflowValidationIssue[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate workflow consistency across registries.
|
|
43
|
+
*
|
|
44
|
+
* Checks that:
|
|
45
|
+
* - All workflow specs are internally valid
|
|
46
|
+
* - Operations referenced by steps exist
|
|
47
|
+
* - Forms referenced by steps exist
|
|
48
|
+
* - Capabilities required by steps exist
|
|
49
|
+
*
|
|
50
|
+
* @param deps - Registry dependencies
|
|
51
|
+
* @returns Validation result
|
|
52
|
+
*/
|
|
53
|
+
declare function validateWorkflowConsistency(deps: WorkflowConsistencyDeps): WorkflowValidationResult;
|
|
54
|
+
/**
|
|
55
|
+
* Assert workflow consistency across registries.
|
|
56
|
+
*
|
|
57
|
+
* @param deps - Registry dependencies
|
|
58
|
+
* @throws {WorkflowValidationError} If validation fails
|
|
59
|
+
*/
|
|
60
|
+
declare function assertWorkflowConsistency(deps: WorkflowConsistencyDeps): void;
|
|
61
|
+
/**
|
|
62
|
+
* Validate SLA configuration is reasonable.
|
|
63
|
+
*
|
|
64
|
+
* @param spec - Workflow spec to validate
|
|
65
|
+
* @returns Array of validation issues
|
|
66
|
+
*/
|
|
67
|
+
declare function validateSlaConfig(spec: WorkflowSpec): WorkflowValidationIssue[];
|
|
68
|
+
/**
|
|
69
|
+
* Validate compensation configuration.
|
|
70
|
+
*
|
|
71
|
+
* @param spec - Workflow spec to validate
|
|
72
|
+
* @returns Array of validation issues
|
|
73
|
+
*/
|
|
74
|
+
declare function validateCompensation(spec: WorkflowSpec): WorkflowValidationIssue[];
|
|
75
|
+
/**
|
|
76
|
+
* Validate retry configuration.
|
|
77
|
+
*
|
|
78
|
+
* @param spec - Workflow spec to validate
|
|
79
|
+
* @returns Array of validation issues
|
|
80
|
+
*/
|
|
81
|
+
declare function validateRetryConfig(spec: WorkflowSpec): WorkflowValidationIssue[];
|
|
82
|
+
/**
|
|
83
|
+
* Perform comprehensive workflow validation.
|
|
84
|
+
*
|
|
85
|
+
* @param spec - Workflow spec to validate
|
|
86
|
+
* @param options - Validation options
|
|
87
|
+
* @returns Validation result
|
|
88
|
+
*/
|
|
89
|
+
declare function validateWorkflowComprehensive(spec: WorkflowSpec, options?: ValidateWorkflowSpecOptions): WorkflowValidationResult;
|
|
28
90
|
//#endregion
|
|
29
|
-
export { ValidateWorkflowSpecOptions, WorkflowValidationError, WorkflowValidationIssue, WorkflowValidationLevel, assertWorkflowSpecValid, validateWorkflowSpec };
|
|
91
|
+
export { ValidateWorkflowSpecOptions, WorkflowConsistencyDeps, WorkflowValidationError, WorkflowValidationIssue, WorkflowValidationLevel, WorkflowValidationResult, assertWorkflowConsistency, assertWorkflowSpecValid, validateCompensation, validateRetryConfig, validateSlaConfig, validateWorkflowComprehensive, validateWorkflowConsistency, validateWorkflowSpec };
|
|
@@ -171,6 +171,199 @@ function detectCycles(adjacency, issues) {
|
|
|
171
171
|
};
|
|
172
172
|
for (const node of adjacency.keys()) dfs(node);
|
|
173
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Validate workflow consistency across registries.
|
|
176
|
+
*
|
|
177
|
+
* Checks that:
|
|
178
|
+
* - All workflow specs are internally valid
|
|
179
|
+
* - Operations referenced by steps exist
|
|
180
|
+
* - Forms referenced by steps exist
|
|
181
|
+
* - Capabilities required by steps exist
|
|
182
|
+
*
|
|
183
|
+
* @param deps - Registry dependencies
|
|
184
|
+
* @returns Validation result
|
|
185
|
+
*/
|
|
186
|
+
function validateWorkflowConsistency(deps) {
|
|
187
|
+
const issues = [];
|
|
188
|
+
for (const workflow of deps.workflows.list()) {
|
|
189
|
+
const specIssues = validateWorkflowSpec(workflow, {
|
|
190
|
+
operations: deps.operations,
|
|
191
|
+
forms: deps.forms
|
|
192
|
+
});
|
|
193
|
+
issues.push(...specIssues.map((i) => ({
|
|
194
|
+
...i,
|
|
195
|
+
message: `[${workflow.meta.key}.v${workflow.meta.version}] ${i.message}`
|
|
196
|
+
})));
|
|
197
|
+
if (deps.capabilities) {
|
|
198
|
+
for (const step of workflow.definition.steps) for (const capRef of step.requiredCapabilities ?? []) if (!deps.capabilities.get(capRef.key, capRef.version)) issues.push({
|
|
199
|
+
level: "error",
|
|
200
|
+
message: `[${workflow.meta.key}.v${workflow.meta.version}] Step "${step.id}" references unknown capability "${capRef.key}.v${capRef.version}"`,
|
|
201
|
+
context: {
|
|
202
|
+
stepId: step.id,
|
|
203
|
+
capability: capRef
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (workflow.definition.compensation && deps.operations) {
|
|
208
|
+
for (const compStep of workflow.definition.compensation.steps) if (!deps.operations.get(compStep.operation.key, compStep.operation.version)) issues.push({
|
|
209
|
+
level: "error",
|
|
210
|
+
message: `[${workflow.meta.key}.v${workflow.meta.version}] Compensation for step "${compStep.stepId}" references unknown operation "${compStep.operation.key}.v${compStep.operation.version}"`,
|
|
211
|
+
context: {
|
|
212
|
+
stepId: compStep.stepId,
|
|
213
|
+
operation: compStep.operation
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (workflow.definition.sla?.stepDurationMs) {
|
|
218
|
+
const stepIds = new Set(workflow.definition.steps.map((s) => s.id));
|
|
219
|
+
for (const stepId of Object.keys(workflow.definition.sla.stepDurationMs)) if (!stepIds.has(stepId)) issues.push({
|
|
220
|
+
level: "warning",
|
|
221
|
+
message: `[${workflow.meta.key}.v${workflow.meta.version}] SLA references unknown step "${stepId}"`,
|
|
222
|
+
context: { stepId }
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
valid: issues.filter((i) => i.level === "error").length === 0,
|
|
228
|
+
issues
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Assert workflow consistency across registries.
|
|
233
|
+
*
|
|
234
|
+
* @param deps - Registry dependencies
|
|
235
|
+
* @throws {WorkflowValidationError} If validation fails
|
|
236
|
+
*/
|
|
237
|
+
function assertWorkflowConsistency(deps) {
|
|
238
|
+
const result = validateWorkflowConsistency(deps);
|
|
239
|
+
if (!result.valid) throw new WorkflowValidationError("Workflow consistency check failed", result.issues);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Validate SLA configuration is reasonable.
|
|
243
|
+
*
|
|
244
|
+
* @param spec - Workflow spec to validate
|
|
245
|
+
* @returns Array of validation issues
|
|
246
|
+
*/
|
|
247
|
+
function validateSlaConfig(spec) {
|
|
248
|
+
const issues = [];
|
|
249
|
+
const sla = spec.definition.sla;
|
|
250
|
+
if (!sla) return issues;
|
|
251
|
+
if (sla.totalDurationMs !== void 0 && sla.totalDurationMs <= 0) issues.push({
|
|
252
|
+
level: "error",
|
|
253
|
+
message: "SLA totalDurationMs must be positive",
|
|
254
|
+
context: { totalDurationMs: sla.totalDurationMs }
|
|
255
|
+
});
|
|
256
|
+
if (sla.stepDurationMs) {
|
|
257
|
+
for (const [stepId, duration] of Object.entries(sla.stepDurationMs)) if (duration <= 0) issues.push({
|
|
258
|
+
level: "error",
|
|
259
|
+
message: `SLA stepDurationMs for "${stepId}" must be positive`,
|
|
260
|
+
context: {
|
|
261
|
+
stepId,
|
|
262
|
+
duration
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
const stepDurationsSum = Object.values(sla.stepDurationMs).reduce((sum, d) => sum + d, 0);
|
|
266
|
+
if (sla.totalDurationMs && stepDurationsSum > sla.totalDurationMs) issues.push({
|
|
267
|
+
level: "warning",
|
|
268
|
+
message: `Sum of step durations (${stepDurationsSum}ms) exceeds total duration (${sla.totalDurationMs}ms)`,
|
|
269
|
+
context: {
|
|
270
|
+
stepDurationsSum,
|
|
271
|
+
totalDurationMs: sla.totalDurationMs
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return issues;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Validate compensation configuration.
|
|
279
|
+
*
|
|
280
|
+
* @param spec - Workflow spec to validate
|
|
281
|
+
* @returns Array of validation issues
|
|
282
|
+
*/
|
|
283
|
+
function validateCompensation(spec) {
|
|
284
|
+
const issues = [];
|
|
285
|
+
const compensation = spec.definition.compensation;
|
|
286
|
+
if (!compensation) return issues;
|
|
287
|
+
const stepIds = new Set(spec.definition.steps.map((s) => s.id));
|
|
288
|
+
const coveredSteps = /* @__PURE__ */ new Set();
|
|
289
|
+
for (const compStep of compensation.steps) {
|
|
290
|
+
if (!stepIds.has(compStep.stepId)) issues.push({
|
|
291
|
+
level: "error",
|
|
292
|
+
message: `Compensation references unknown step "${compStep.stepId}"`,
|
|
293
|
+
context: { stepId: compStep.stepId }
|
|
294
|
+
});
|
|
295
|
+
if (coveredSteps.has(compStep.stepId)) issues.push({
|
|
296
|
+
level: "warning",
|
|
297
|
+
message: `Multiple compensation handlers for step "${compStep.stepId}"`,
|
|
298
|
+
context: { stepId: compStep.stepId }
|
|
299
|
+
});
|
|
300
|
+
coveredSteps.add(compStep.stepId);
|
|
301
|
+
if (!compStep.operation?.key || !compStep.operation?.version) issues.push({
|
|
302
|
+
level: "error",
|
|
303
|
+
message: `Compensation for step "${compStep.stepId}" must specify operation with key and version`,
|
|
304
|
+
context: { stepId: compStep.stepId }
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
const automationSteps = spec.definition.steps.filter((s) => s.type === "automation");
|
|
308
|
+
for (const step of automationSteps) if (!coveredSteps.has(step.id)) issues.push({
|
|
309
|
+
level: "warning",
|
|
310
|
+
message: `Automation step "${step.id}" has no compensation handler`,
|
|
311
|
+
context: { stepId: step.id }
|
|
312
|
+
});
|
|
313
|
+
return issues;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Validate retry configuration.
|
|
317
|
+
*
|
|
318
|
+
* @param spec - Workflow spec to validate
|
|
319
|
+
* @returns Array of validation issues
|
|
320
|
+
*/
|
|
321
|
+
function validateRetryConfig(spec) {
|
|
322
|
+
const issues = [];
|
|
323
|
+
for (const step of spec.definition.steps) {
|
|
324
|
+
if (!step.retry) continue;
|
|
325
|
+
if (step.retry.maxAttempts <= 0) issues.push({
|
|
326
|
+
level: "error",
|
|
327
|
+
message: `Step "${step.id}" retry maxAttempts must be positive`,
|
|
328
|
+
context: {
|
|
329
|
+
stepId: step.id,
|
|
330
|
+
maxAttempts: step.retry.maxAttempts
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
if (step.retry.delayMs <= 0) issues.push({
|
|
334
|
+
level: "error",
|
|
335
|
+
message: `Step "${step.id}" retry delayMs must be positive`,
|
|
336
|
+
context: {
|
|
337
|
+
stepId: step.id,
|
|
338
|
+
delayMs: step.retry.delayMs
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
if (step.retry.maxDelayMs !== void 0 && step.retry.maxDelayMs < step.retry.delayMs) issues.push({
|
|
342
|
+
level: "warning",
|
|
343
|
+
message: `Step "${step.id}" retry maxDelayMs (${step.retry.maxDelayMs}) is less than delayMs (${step.retry.delayMs})`,
|
|
344
|
+
context: { stepId: step.id }
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
return issues;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Perform comprehensive workflow validation.
|
|
351
|
+
*
|
|
352
|
+
* @param spec - Workflow spec to validate
|
|
353
|
+
* @param options - Validation options
|
|
354
|
+
* @returns Validation result
|
|
355
|
+
*/
|
|
356
|
+
function validateWorkflowComprehensive(spec, options = {}) {
|
|
357
|
+
const issues = [];
|
|
358
|
+
issues.push(...validateWorkflowSpec(spec, options));
|
|
359
|
+
issues.push(...validateSlaConfig(spec));
|
|
360
|
+
issues.push(...validateCompensation(spec));
|
|
361
|
+
issues.push(...validateRetryConfig(spec));
|
|
362
|
+
return {
|
|
363
|
+
valid: issues.filter((i) => i.level === "error").length === 0,
|
|
364
|
+
issues
|
|
365
|
+
};
|
|
366
|
+
}
|
|
174
367
|
|
|
175
368
|
//#endregion
|
|
176
|
-
export { WorkflowValidationError, assertWorkflowSpecValid, validateWorkflowSpec };
|
|
369
|
+
export { WorkflowValidationError, assertWorkflowConsistency, assertWorkflowSpecValid, validateCompensation, validateRetryConfig, validateSlaConfig, validateWorkflowComprehensive, validateWorkflowConsistency, validateWorkflowSpec };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/lib.contracts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.52.0",
|
|
4
4
|
"description": "Core contract specification definitions and runtime",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -25,18 +25,19 @@
|
|
|
25
25
|
"test": "bun test"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@contractspec/tool.tsdown": "1.
|
|
29
|
-
"@contractspec/tool.typescript": "1.
|
|
28
|
+
"@contractspec/tool.tsdown": "1.52.0",
|
|
29
|
+
"@contractspec/tool.typescript": "1.52.0",
|
|
30
30
|
"@types/express": "^5.0.3",
|
|
31
31
|
"@types/turndown": "^5.0.6",
|
|
32
32
|
"tsdown": "^0.19.0",
|
|
33
|
-
"typescript": "^5.9.3"
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"vitest": "^4.0.18"
|
|
34
35
|
},
|
|
35
36
|
"dependencies": {
|
|
36
37
|
"@aws-sdk/client-secrets-manager": "^3.966.0",
|
|
37
38
|
"@aws-sdk/client-sqs": "^3.966.0",
|
|
38
|
-
"@contractspec/lib.logger": "1.
|
|
39
|
-
"@contractspec/lib.schema": "1.
|
|
39
|
+
"@contractspec/lib.logger": "1.52.0",
|
|
40
|
+
"@contractspec/lib.schema": "1.52.0",
|
|
40
41
|
"@elevenlabs/elevenlabs-js": "^2.30.0",
|
|
41
42
|
"@google-cloud/secret-manager": "^6.1.1",
|
|
42
43
|
"@google-cloud/storage": "^7.18.0",
|
|
@@ -95,8 +96,11 @@
|
|
|
95
96
|
"./app-config/validation": "./dist/app-config/validation.js",
|
|
96
97
|
"./capabilities": "./dist/capabilities/index.js",
|
|
97
98
|
"./capabilities/capabilities": "./dist/capabilities/capabilities.js",
|
|
99
|
+
"./capabilities/context": "./dist/capabilities/context.js",
|
|
98
100
|
"./capabilities/docs/capabilities.docblock": "./dist/capabilities/docs/capabilities.docblock.js",
|
|
101
|
+
"./capabilities/guards": "./dist/capabilities/guards.js",
|
|
99
102
|
"./capabilities/openbanking": "./dist/capabilities/openbanking.js",
|
|
103
|
+
"./capabilities/validation": "./dist/capabilities/validation.js",
|
|
100
104
|
"./client": "./dist/client/index.js",
|
|
101
105
|
"./client/react": "./dist/client/react/index.js",
|
|
102
106
|
"./client/react/drivers/rn-reusables": "./dist/client/react/drivers/rn-reusables.js",
|
|
@@ -282,11 +286,14 @@
|
|
|
282
286
|
"./operations/registry": "./dist/operations/registry.js",
|
|
283
287
|
"./ownership": "./dist/ownership.js",
|
|
284
288
|
"./policy": "./dist/policy/index.js",
|
|
289
|
+
"./policy/context": "./dist/policy/context.js",
|
|
285
290
|
"./policy/docs/policy.docblock": "./dist/policy/docs/policy.docblock.js",
|
|
286
291
|
"./policy/engine": "./dist/policy/engine.js",
|
|
292
|
+
"./policy/guards": "./dist/policy/guards.js",
|
|
287
293
|
"./policy/opa-adapter": "./dist/policy/opa-adapter.js",
|
|
288
294
|
"./policy/registry": "./dist/policy/registry.js",
|
|
289
295
|
"./policy/spec": "./dist/policy/spec.js",
|
|
296
|
+
"./policy/validation": "./dist/policy/validation.js",
|
|
290
297
|
"./presentations": "./dist/presentations/index.js",
|
|
291
298
|
"./presentations/docs/presentations-conventions.docblock": "./dist/presentations/docs/presentations-conventions.docblock.js",
|
|
292
299
|
"./presentations/presentations": "./dist/presentations/presentations.js",
|
|
@@ -335,8 +342,12 @@
|
|
|
335
342
|
"./tests/runner": "./dist/tests/runner.js",
|
|
336
343
|
"./tests/spec": "./dist/tests/spec.js",
|
|
337
344
|
"./themes": "./dist/themes.js",
|
|
345
|
+
"./translations": "./dist/translations/index.js",
|
|
338
346
|
"./translations/catalog": "./dist/translations/catalog.js",
|
|
347
|
+
"./translations/registry": "./dist/translations/registry.js",
|
|
348
|
+
"./translations/spec": "./dist/translations/spec.js",
|
|
339
349
|
"./translations/tenant": "./dist/translations/tenant.js",
|
|
350
|
+
"./translations/validation": "./dist/translations/validation.js",
|
|
340
351
|
"./types": "./dist/types.js",
|
|
341
352
|
"./versioning": "./dist/versioning/index.js",
|
|
342
353
|
"./versioning/refs": "./dist/versioning/refs.js",
|
|
@@ -347,6 +358,7 @@
|
|
|
347
358
|
"./workflow/adapters/db-adapter": "./dist/workflow/adapters/db-adapter.js",
|
|
348
359
|
"./workflow/adapters/file-adapter": "./dist/workflow/adapters/file-adapter.js",
|
|
349
360
|
"./workflow/adapters/memory-store": "./dist/workflow/adapters/memory-store.js",
|
|
361
|
+
"./workflow/context": "./dist/workflow/context.js",
|
|
350
362
|
"./workflow/expression": "./dist/workflow/expression.js",
|
|
351
363
|
"./workflow/overview.docblock": "./dist/workflow/overview.docblock.js",
|
|
352
364
|
"./workflow/runner": "./dist/workflow/runner.js",
|