@lssm/lib.contracts 0.0.0-canary-20251217063201 → 0.0.0-canary-20251217072406
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/app-config.feature.js +53 -1
- package/dist/app-config/contracts.d.ts +50 -50
- package/dist/app-config/contracts.js +396 -1
- package/dist/app-config/docs/app-config.docblock.js +22 -220
- package/dist/app-config/events.d.ts +27 -27
- package/dist/app-config/events.js +168 -1
- package/dist/app-config/index.js +8 -1
- package/dist/app-config/lifecycle-contracts.d.ts +80 -80
- package/dist/app-config/lifecycle-contracts.js +441 -1
- package/dist/app-config/runtime.js +617 -1
- package/dist/app-config/spec.js +36 -1
- package/dist/app-config/validation.js +538 -1
- package/dist/capabilities/docs/capabilities.docblock.js +22 -1
- package/dist/capabilities/openbanking.js +92 -1
- package/dist/capabilities.js +50 -1
- package/dist/client/index.js +9 -1
- package/dist/client/react/drivers/rn-reusables.js +21 -1
- package/dist/client/react/drivers/shadcn.js +11 -1
- package/dist/client/react/feature-render.js +43 -1
- package/dist/client/react/form-render.js +298 -1
- package/dist/client/react/index.js +8 -1
- package/dist/contract-registry/index.js +3 -1
- package/dist/contract-registry/schemas.js +61 -1
- package/dist/contracts-adapter-hydration.js +41 -1
- package/dist/contracts-adapter-input.js +77 -1
- package/dist/data-views/docs/data-views.docblock.js +22 -1
- package/dist/data-views/query-generator.js +48 -1
- package/dist/data-views/runtime.js +39 -1
- package/dist/data-views.js +35 -1
- package/dist/docs/PUBLISHING.docblock.js +17 -76
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +17 -350
- package/dist/docs/index.js +33 -1
- package/dist/docs/meta.docs.js +15 -2
- package/dist/docs/presentations.js +77 -1
- package/dist/docs/registry.js +51 -1
- package/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +17 -383
- package/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +17 -68
- package/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +17 -140
- package/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +17 -86
- package/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +17 -1
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +25 -2
- package/dist/docs/tech/contracts/README.docblock.js +21 -1
- package/dist/docs/tech/contracts/create-subscription.docblock.js +21 -1
- package/dist/docs/tech/contracts/graphql-typed-outputs.docblock.js +21 -180
- package/dist/docs/tech/contracts/migrations.docblock.js +21 -1
- package/dist/docs/tech/contracts/openapi-export.docblock.js +22 -2
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +19 -60
- package/dist/docs/tech/contracts/overlays.docblock.js +21 -68
- package/dist/docs/tech/contracts/tests.docblock.js +21 -132
- package/dist/docs/tech/contracts/themes.docblock.js +21 -1
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +21 -106
- package/dist/docs/tech/lifecycle-stage-system.docblock.js +17 -213
- package/dist/docs/tech/llm/llm-integration.docblock.js +74 -5
- package/dist/docs/tech/mcp-endpoints.docblock.js +38 -1
- package/dist/docs/tech/presentation-runtime.docblock.js +17 -1
- package/dist/docs/tech/schema/README.docblock.js +21 -262
- package/dist/docs/tech/studio/learning-events.docblock.js +49 -1
- package/dist/docs/tech/studio/learning-journeys.docblock.js +25 -2
- package/dist/docs/tech/studio/platform-admin-panel.docblock.js +24 -2
- package/dist/docs/tech/studio/project-access-teams.docblock.js +26 -16
- package/dist/docs/tech/studio/project-routing.docblock.js +68 -1
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +23 -2
- package/dist/docs/tech/studio/team-invitations.docblock.js +41 -36
- package/dist/docs/tech/studio/workspace-ops.docblock.js +48 -1
- package/dist/docs/tech/studio/workspaces.docblock.js +24 -2
- package/dist/docs/tech/telemetry-ingest.docblock.js +37 -3
- package/dist/docs/tech/templates/runtime.docblock.js +21 -1
- package/dist/docs/tech/vscode-extension.docblock.js +37 -3
- package/dist/docs/tech/workflows/overview.docblock.js +21 -1
- package/dist/docs/tech-contracts.docs.js +19 -2
- package/dist/events.js +12 -1
- package/dist/experiments/docs/experiments.docblock.js +22 -128
- package/dist/experiments/evaluator.js +101 -1
- package/dist/experiments/spec.js +33 -1
- package/dist/features.js +68 -1
- package/dist/forms/docs/forms.docblock.js +22 -1
- package/dist/forms.js +119 -1
- package/dist/index.js +107 -1
- package/dist/install.js +40 -1
- package/dist/integrations/contracts.d.ts +102 -102
- package/dist/integrations/contracts.js +388 -1
- package/dist/integrations/docs/integrations.docblock.js +95 -1
- package/dist/integrations/health.js +69 -1
- package/dist/integrations/index.js +23 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +66 -66
- package/dist/integrations/openbanking/contracts/accounts.js +237 -1
- package/dist/integrations/openbanking/contracts/balances.d.ts +34 -34
- package/dist/integrations/openbanking/contracts/balances.js +167 -1
- package/dist/integrations/openbanking/contracts/index.js +12 -1
- package/dist/integrations/openbanking/contracts/transactions.d.ts +48 -48
- package/dist/integrations/openbanking/contracts/transactions.js +218 -1
- package/dist/integrations/openbanking/guards.js +32 -1
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/openbanking/models.js +242 -1
- package/dist/integrations/openbanking/openbanking.feature.js +68 -1
- package/dist/integrations/openbanking/telemetry.js +39 -1
- package/dist/integrations/providers/elevenlabs.js +56 -1
- package/dist/integrations/providers/gcs-storage.js +79 -1
- package/dist/integrations/providers/gmail.js +91 -1
- package/dist/integrations/providers/google-calendar.js +70 -1
- package/dist/integrations/providers/impls/elevenlabs-voice.js +95 -1
- package/dist/integrations/providers/impls/gcs-storage.js +88 -1
- package/dist/integrations/providers/impls/gmail-inbound.js +200 -1
- package/dist/integrations/providers/impls/gmail-outbound.js +104 -5
- package/dist/integrations/providers/impls/google-calendar.js +154 -1
- package/dist/integrations/providers/impls/index.js +16 -1
- package/dist/integrations/providers/impls/mistral-embedding.js +41 -1
- package/dist/integrations/providers/impls/mistral-llm.js +247 -1
- package/dist/integrations/providers/impls/postmark-email.js +55 -1
- package/dist/integrations/providers/impls/powens-client.js +171 -1
- package/dist/integrations/providers/impls/powens-openbanking.js +218 -1
- package/dist/integrations/providers/impls/provider-factory.js +142 -1
- package/dist/integrations/providers/impls/qdrant-vector.js +69 -1
- package/dist/integrations/providers/impls/stripe-payments.js +202 -1
- package/dist/integrations/providers/impls/twilio-sms.js +58 -1
- package/dist/integrations/providers/index.js +13 -1
- package/dist/integrations/providers/mistral.js +72 -1
- package/dist/integrations/providers/postmark.js +72 -1
- package/dist/integrations/providers/powens.js +120 -1
- package/dist/integrations/providers/qdrant.js +77 -1
- package/dist/integrations/providers/registry.js +34 -1
- package/dist/integrations/providers/stripe.js +87 -1
- package/dist/integrations/providers/twilio-sms.js +65 -1
- package/dist/integrations/runtime.js +186 -1
- package/dist/integrations/secrets/aws-secret-manager.js +231 -1
- package/dist/integrations/secrets/env-secret-provider.js +81 -1
- package/dist/integrations/secrets/gcp-secret-manager.js +229 -1
- package/dist/integrations/secrets/index.js +8 -1
- package/dist/integrations/secrets/manager.js +103 -1
- package/dist/integrations/secrets/provider.js +58 -1
- package/dist/integrations/secrets/scaleway-secret-manager.js +247 -1
- package/dist/integrations/spec.js +39 -1
- package/dist/jobs/define-job.js +16 -1
- package/dist/jobs/gcp-cloud-tasks.js +53 -1
- package/dist/jobs/gcp-pubsub.js +39 -1
- package/dist/jobs/handlers/gmail-sync-handler.js +9 -1
- package/dist/jobs/handlers/index.js +12 -1
- package/dist/jobs/handlers/ping-handler.js +15 -1
- package/dist/jobs/handlers/storage-document-handler.js +14 -1
- package/dist/jobs/index.js +4 -1
- package/dist/jobs/memory-queue.js +71 -1
- package/dist/jobs/queue.js +33 -1
- package/dist/jobs/scaleway-sqs-queue.js +153 -1
- package/dist/jsonschema.d.ts +3 -3
- package/dist/jsonschema.js +32 -1
- package/dist/knowledge/contracts.d.ts +66 -66
- package/dist/knowledge/contracts.js +317 -1
- package/dist/knowledge/docs/knowledge.docblock.js +22 -138
- package/dist/knowledge/index.js +10 -1
- package/dist/knowledge/ingestion/document-processor.js +54 -1
- package/dist/knowledge/ingestion/embedding-service.js +25 -1
- package/dist/knowledge/ingestion/gmail-adapter.js +50 -5
- package/dist/knowledge/ingestion/index.js +7 -1
- package/dist/knowledge/ingestion/storage-adapter.js +26 -1
- package/dist/knowledge/ingestion/vector-indexer.js +32 -1
- package/dist/knowledge/query/index.js +3 -1
- package/dist/knowledge/query/service.js +64 -2
- package/dist/knowledge/runtime.js +49 -1
- package/dist/knowledge/spaces/email-threads.js +38 -1
- package/dist/knowledge/spaces/financial-docs.js +38 -1
- package/dist/knowledge/spaces/financial-overview.js +42 -1
- package/dist/knowledge/spaces/index.js +8 -1
- package/dist/knowledge/spaces/product-canon.js +38 -1
- package/dist/knowledge/spaces/support-faq.js +41 -1
- package/dist/knowledge/spaces/uploaded-docs.js +38 -1
- package/dist/knowledge/spec.js +39 -1
- package/dist/llm/exporters.js +541 -8
- package/dist/llm/index.js +4 -1
- package/dist/llm/prompts.js +246 -56
- package/dist/markdown.js +116 -3
- package/dist/migrations.js +33 -1
- package/dist/onboarding-base.d.ts +29 -29
- package/dist/onboarding-base.js +196 -1
- package/dist/openapi.js +75 -1
- package/dist/openbanking/docs/openbanking.docblock.js +22 -109
- package/dist/ownership.js +40 -1
- package/dist/policy/docs/policy.docblock.js +22 -1
- package/dist/policy/engine.js +223 -1
- package/dist/policy/opa-adapter.js +71 -1
- package/dist/policy/spec.js +33 -1
- package/dist/presentations/docs/presentations-conventions.docblock.js +21 -7
- package/dist/presentations.backcompat.js +47 -1
- package/dist/presentations.d.ts +3 -3
- package/dist/presentations.js +66 -1
- package/dist/presentations.v2.js +278 -6
- package/dist/prompt.js +10 -1
- package/dist/promptRegistry.js +34 -1
- package/dist/regenerator/docs/regenerator.docblock.js +22 -184
- package/dist/regenerator/executor.js +86 -1
- package/dist/regenerator/index.js +6 -1
- package/dist/regenerator/service.js +92 -1
- package/dist/regenerator/sinks.js +32 -1
- package/dist/regenerator/utils.js +51 -1
- package/dist/registry.js +208 -1
- package/dist/resources.js +47 -1
- package/dist/schema/dist/EnumType.js +2 -1
- package/dist/schema/dist/FieldType.js +49 -1
- package/dist/schema/dist/ScalarTypeEnum.js +236 -1
- package/dist/schema/dist/SchemaModel.js +39 -1
- package/dist/schema/dist/entity/defineEntity.js +1 -1
- package/dist/schema/dist/entity/index.js +2 -1
- package/dist/schema/dist/entity/types.js +1 -1
- package/dist/schema/dist/index.js +6 -1
- package/dist/schema-to-markdown.js +214 -10
- package/dist/server/graphql-pothos.js +128 -1
- package/dist/server/index.js +10 -1
- package/dist/server/mcp/createMcpServer.js +28 -1
- package/dist/server/mcp/registerPresentations.js +151 -1
- package/dist/server/mcp/registerPrompts.js +36 -2
- package/dist/server/mcp/registerResources.js +35 -1
- package/dist/server/mcp/registerTools.js +22 -1
- package/dist/server/provider-mcp.js +3 -1
- package/dist/server/rest-elysia.js +20 -1
- package/dist/server/rest-express.js +39 -1
- package/dist/server/rest-generic.js +125 -1
- package/dist/server/rest-next-app.js +38 -1
- package/dist/server/rest-next-mcp.js +45 -1
- package/dist/server/rest-next-pages.js +25 -1
- package/dist/spec.js +35 -1
- package/dist/telemetry/anomaly.js +48 -1
- package/dist/telemetry/docs/telemetry.docblock.js +22 -139
- package/dist/telemetry/index.js +5 -1
- package/dist/telemetry/spec.js +69 -1
- package/dist/telemetry/tracker.js +76 -1
- package/dist/tests/index.js +4 -1
- package/dist/tests/runner.js +150 -1
- package/dist/tests/spec.js +33 -1
- package/dist/themes.js +39 -1
- package/dist/workflow/adapters/db-adapter.js +83 -1
- package/dist/workflow/adapters/file-adapter.js +11 -1
- package/dist/workflow/adapters/index.js +5 -1
- package/dist/workflow/adapters/memory-store.js +58 -1
- package/dist/workflow/expression.js +98 -1
- package/dist/workflow/index.js +9 -1
- package/dist/workflow/runner.js +337 -1
- package/dist/workflow/sla-monitor.js +47 -1
- package/dist/workflow/spec.js +32 -1
- package/dist/workflow/validation.js +175 -1
- package/package.json +11 -4
|
@@ -1 +1,83 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/workflow/adapters/db-adapter.ts
|
|
2
|
+
var PrismaStateStore = class {
|
|
3
|
+
constructor(prisma) {
|
|
4
|
+
this.prisma = prisma;
|
|
5
|
+
}
|
|
6
|
+
async create(state) {
|
|
7
|
+
await this.prisma.workflowState.create({ data: {
|
|
8
|
+
id: state.workflowId,
|
|
9
|
+
name: state.workflowName,
|
|
10
|
+
version: state.workflowVersion,
|
|
11
|
+
status: state.status,
|
|
12
|
+
currentStep: state.currentStep,
|
|
13
|
+
data: state.data,
|
|
14
|
+
history: state.history,
|
|
15
|
+
retryCounts: state.retryCounts ?? {},
|
|
16
|
+
createdAt: state.createdAt,
|
|
17
|
+
updatedAt: state.updatedAt
|
|
18
|
+
} });
|
|
19
|
+
}
|
|
20
|
+
async get(workflowId) {
|
|
21
|
+
const record = await this.prisma.workflowState.findUnique({ where: { id: workflowId } });
|
|
22
|
+
if (!record) return void 0;
|
|
23
|
+
return {
|
|
24
|
+
workflowId: record.id,
|
|
25
|
+
workflowName: record.name,
|
|
26
|
+
workflowVersion: record.version,
|
|
27
|
+
currentStep: record.currentStep,
|
|
28
|
+
data: record.data,
|
|
29
|
+
history: record.history,
|
|
30
|
+
retryCounts: record.retryCounts,
|
|
31
|
+
status: record.status,
|
|
32
|
+
createdAt: record.createdAt,
|
|
33
|
+
updatedAt: record.updatedAt
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async update(workflowId, updater) {
|
|
37
|
+
const current = await this.get(workflowId);
|
|
38
|
+
if (!current) throw new Error(`Workflow ${workflowId} not found`);
|
|
39
|
+
const next = updater(current);
|
|
40
|
+
const updated = await this.prisma.workflowState.update({
|
|
41
|
+
where: { id: workflowId },
|
|
42
|
+
data: {
|
|
43
|
+
status: next.status,
|
|
44
|
+
currentStep: next.currentStep,
|
|
45
|
+
data: next.data,
|
|
46
|
+
history: next.history,
|
|
47
|
+
retryCounts: next.retryCounts,
|
|
48
|
+
updatedAt: next.updatedAt
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
workflowId: updated.id,
|
|
53
|
+
workflowName: updated.name,
|
|
54
|
+
workflowVersion: updated.version,
|
|
55
|
+
currentStep: updated.currentStep,
|
|
56
|
+
data: updated.data,
|
|
57
|
+
history: updated.history,
|
|
58
|
+
retryCounts: updated.retryCounts,
|
|
59
|
+
status: updated.status,
|
|
60
|
+
createdAt: updated.createdAt,
|
|
61
|
+
updatedAt: updated.updatedAt
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async list(filters) {
|
|
65
|
+
const where = {};
|
|
66
|
+
if (filters?.status) where.status = filters.status;
|
|
67
|
+
return (await this.prisma.workflowState.findMany({ where })).map((record) => ({
|
|
68
|
+
workflowId: record.id,
|
|
69
|
+
workflowName: record.name,
|
|
70
|
+
workflowVersion: record.version,
|
|
71
|
+
currentStep: record.currentStep,
|
|
72
|
+
data: record.data,
|
|
73
|
+
history: record.history,
|
|
74
|
+
retryCounts: record.retryCounts,
|
|
75
|
+
status: record.status,
|
|
76
|
+
createdAt: record.createdAt,
|
|
77
|
+
updatedAt: record.updatedAt
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
export { PrismaStateStore };
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/workflow/adapters/file-adapter.ts
|
|
2
|
+
/**
|
|
3
|
+
* Placeholder for a file-backed state store adapter.
|
|
4
|
+
* Implementations should manage locking/concurrency and JSON serialization.
|
|
5
|
+
*/
|
|
6
|
+
function createFileStateStore(_options) {
|
|
7
|
+
throw new Error("File-backed state store adapter not implemented. Provide a custom adapter that satisfies StateStore.");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { createFileStateStore };
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
import{InMemoryStateStore
|
|
1
|
+
import { InMemoryStateStore } from "./memory-store.js";
|
|
2
|
+
import { PrismaStateStore } from "./db-adapter.js";
|
|
3
|
+
import { createFileStateStore } from "./file-adapter.js";
|
|
4
|
+
|
|
5
|
+
export { InMemoryStateStore, PrismaStateStore, createFileStateStore };
|
|
@@ -1 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/workflow/adapters/memory-store.ts
|
|
2
|
+
function cloneState(state) {
|
|
3
|
+
return {
|
|
4
|
+
...state,
|
|
5
|
+
data: deepCopy(state.data),
|
|
6
|
+
history: state.history.map((execution) => ({
|
|
7
|
+
...execution,
|
|
8
|
+
input: deepCopy(execution.input),
|
|
9
|
+
output: deepCopy(execution.output),
|
|
10
|
+
startedAt: new Date(execution.startedAt),
|
|
11
|
+
completedAt: execution.completedAt ? new Date(execution.completedAt) : void 0
|
|
12
|
+
})),
|
|
13
|
+
createdAt: new Date(state.createdAt),
|
|
14
|
+
updatedAt: new Date(state.updatedAt)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Naive in-memory state store. Suitable for tests and single-node development
|
|
19
|
+
* environments. Swap with a database-backed adapter in production.
|
|
20
|
+
*/
|
|
21
|
+
var InMemoryStateStore = class {
|
|
22
|
+
items = /* @__PURE__ */ new Map();
|
|
23
|
+
async create(state) {
|
|
24
|
+
if (this.items.has(state.workflowId)) throw new Error(`Workflow state already exists: ${state.workflowId}`);
|
|
25
|
+
this.items.set(state.workflowId, cloneState(state));
|
|
26
|
+
}
|
|
27
|
+
async get(workflowId) {
|
|
28
|
+
const state = this.items.get(workflowId);
|
|
29
|
+
return state ? cloneState(state) : void 0;
|
|
30
|
+
}
|
|
31
|
+
async update(workflowId, updater) {
|
|
32
|
+
const current = this.items.get(workflowId);
|
|
33
|
+
if (!current) throw new Error(`Workflow state not found for ${workflowId}`);
|
|
34
|
+
const next = cloneState(updater(cloneState(current)));
|
|
35
|
+
this.items.set(workflowId, next);
|
|
36
|
+
return cloneState(next);
|
|
37
|
+
}
|
|
38
|
+
async list(filters) {
|
|
39
|
+
const all = [...this.items.values()];
|
|
40
|
+
return (filters?.status ? all.filter((state) => state.status === filters.status) : all).map(cloneState);
|
|
41
|
+
}
|
|
42
|
+
clear() {
|
|
43
|
+
this.items.clear();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
function deepCopy(value) {
|
|
47
|
+
if (value instanceof Date) return new Date(value.getTime());
|
|
48
|
+
if (Array.isArray(value)) return value.map((item) => deepCopy(item));
|
|
49
|
+
if (value && typeof value === "object") {
|
|
50
|
+
const result = {};
|
|
51
|
+
for (const [key, val] of Object.entries(value)) result[key] = deepCopy(val);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { InMemoryStateStore };
|
|
@@ -1 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/workflow/expression.ts
|
|
2
|
+
function evaluateExpression(expression, ctx) {
|
|
3
|
+
if (!expression) return true;
|
|
4
|
+
const trimmed = expression.trim();
|
|
5
|
+
if (!trimmed) return true;
|
|
6
|
+
const orParts = splitByOperator(trimmed, "||");
|
|
7
|
+
if (orParts.length > 1) return orParts.some((part) => evaluateExpression(part, ctx));
|
|
8
|
+
const andParts = splitByOperator(trimmed, "&&");
|
|
9
|
+
if (andParts.length > 1) return andParts.every((part) => evaluateExpression(part, ctx));
|
|
10
|
+
return evaluateSingle(trimmed, ctx);
|
|
11
|
+
}
|
|
12
|
+
function evaluateSingle(expr, ctx) {
|
|
13
|
+
const trimmed = expr.trim();
|
|
14
|
+
if (!trimmed) return true;
|
|
15
|
+
if (trimmed.startsWith("!")) return !evaluateSingle(trimmed.slice(1), ctx);
|
|
16
|
+
const comparisonMatch = trimmed.match(/^(data|input|output)\.([A-Za-z0-9_.\[\]]+)\s*(===|==|!==|!=|>=|<=|>|<)\s*(.+)$/);
|
|
17
|
+
if (comparisonMatch) {
|
|
18
|
+
const [, root, path, operator, rawRight] = comparisonMatch;
|
|
19
|
+
return compare(resolveRoot(root, ctx, path), parseLiteral(rawRight), operator);
|
|
20
|
+
}
|
|
21
|
+
const truthyMatch = trimmed.match(/^(data|input|output)\.([A-Za-z0-9_.\[\]]+)$/);
|
|
22
|
+
if (truthyMatch) {
|
|
23
|
+
const [, root, path] = truthyMatch;
|
|
24
|
+
const value = resolveRoot(root, ctx, path);
|
|
25
|
+
return Boolean(value);
|
|
26
|
+
}
|
|
27
|
+
const literal = parseLiteral(trimmed);
|
|
28
|
+
return Boolean(literal);
|
|
29
|
+
}
|
|
30
|
+
function compare(left, right, operator) {
|
|
31
|
+
switch (operator) {
|
|
32
|
+
case "===":
|
|
33
|
+
case "==": return left === right;
|
|
34
|
+
case "!==":
|
|
35
|
+
case "!=": return left !== right;
|
|
36
|
+
case ">": return Number(left) > Number(right);
|
|
37
|
+
case ">=": return Number(left) >= Number(right);
|
|
38
|
+
case "<": return Number(left) < Number(right);
|
|
39
|
+
case "<=": return Number(left) <= Number(right);
|
|
40
|
+
default: return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function parseLiteral(value) {
|
|
44
|
+
const trimmed = (value ?? "").trim();
|
|
45
|
+
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
|
|
46
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed);
|
|
47
|
+
if (/^true$/i.test(trimmed)) return true;
|
|
48
|
+
if (/^false$/i.test(trimmed)) return false;
|
|
49
|
+
if (/^null$/i.test(trimmed)) return null;
|
|
50
|
+
if (/^undefined$/i.test(trimmed)) return void 0;
|
|
51
|
+
return trimmed;
|
|
52
|
+
}
|
|
53
|
+
function resolveRoot(root, ctx, path) {
|
|
54
|
+
return resolvePath(root === "data" ? ctx.data : root === "input" ? ctx.input : ctx.output, path);
|
|
55
|
+
}
|
|
56
|
+
function resolvePath(source, path) {
|
|
57
|
+
if (source == null) return void 0;
|
|
58
|
+
if (!path) return source;
|
|
59
|
+
const segments = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
60
|
+
let current = source;
|
|
61
|
+
for (const segment of segments) {
|
|
62
|
+
if (current == null) return void 0;
|
|
63
|
+
current = current[segment];
|
|
64
|
+
}
|
|
65
|
+
return current;
|
|
66
|
+
}
|
|
67
|
+
function splitByOperator(expr, operator) {
|
|
68
|
+
const parts = [];
|
|
69
|
+
let buffer = "";
|
|
70
|
+
let inSingleQuote = false;
|
|
71
|
+
let inDoubleQuote = false;
|
|
72
|
+
for (let i = 0; i < expr.length; i++) {
|
|
73
|
+
const char = expr[i];
|
|
74
|
+
const next = expr.slice(i, i + operator.length);
|
|
75
|
+
if (char === "'" && !inDoubleQuote) {
|
|
76
|
+
inSingleQuote = !inSingleQuote;
|
|
77
|
+
buffer += char;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (char === "\"" && !inSingleQuote) {
|
|
81
|
+
inDoubleQuote = !inDoubleQuote;
|
|
82
|
+
buffer += char;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (!inSingleQuote && !inDoubleQuote && next === operator) {
|
|
86
|
+
parts.push(buffer.trim());
|
|
87
|
+
buffer = "";
|
|
88
|
+
i += operator.length - 1;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
buffer += char;
|
|
92
|
+
}
|
|
93
|
+
if (buffer.trim().length) parts.push(buffer.trim());
|
|
94
|
+
return parts;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
export { evaluateExpression };
|
package/dist/workflow/index.js
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { WorkflowRegistry } from "./spec.js";
|
|
2
|
+
import { WorkflowValidationError, assertWorkflowSpecValid, validateWorkflowSpec } from "./validation.js";
|
|
3
|
+
import { evaluateExpression } from "./expression.js";
|
|
4
|
+
import { WorkflowPreFlightError, WorkflowRunner } from "./runner.js";
|
|
5
|
+
import { InMemoryStateStore } from "./adapters/memory-store.js";
|
|
6
|
+
import { PrismaStateStore } from "./adapters/db-adapter.js";
|
|
7
|
+
import { createFileStateStore } from "./adapters/file-adapter.js";
|
|
8
|
+
|
|
9
|
+
export { InMemoryStateStore, PrismaStateStore, WorkflowPreFlightError, WorkflowRegistry, WorkflowRunner, WorkflowValidationError, assertWorkflowSpecValid, createFileStateStore, evaluateExpression, validateWorkflowSpec };
|
package/dist/workflow/runner.js
CHANGED
|
@@ -1 +1,337 @@
|
|
|
1
|
-
import{evaluateExpression
|
|
1
|
+
import { evaluateExpression } from "./expression.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
|
|
4
|
+
//#region src/workflow/runner.ts
|
|
5
|
+
var WorkflowRunner = class {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
async preFlightCheck(workflowName, version, resolvedConfig) {
|
|
10
|
+
const spec = this.getSpec(workflowName, version);
|
|
11
|
+
return this.performPreFlight(spec, resolvedConfig);
|
|
12
|
+
}
|
|
13
|
+
async start(workflowName, version, initialData) {
|
|
14
|
+
const spec = this.getSpec(workflowName, version);
|
|
15
|
+
const entryStepId = resolveEntryStepId(spec);
|
|
16
|
+
const now = /* @__PURE__ */ new Date();
|
|
17
|
+
const workflowId = randomUUID();
|
|
18
|
+
const state = {
|
|
19
|
+
workflowId,
|
|
20
|
+
workflowName: spec.meta.name,
|
|
21
|
+
workflowVersion: spec.meta.version,
|
|
22
|
+
currentStep: entryStepId,
|
|
23
|
+
data: { ...initialData ?? {} },
|
|
24
|
+
retryCounts: {},
|
|
25
|
+
history: [],
|
|
26
|
+
status: "running",
|
|
27
|
+
createdAt: now,
|
|
28
|
+
updatedAt: now
|
|
29
|
+
};
|
|
30
|
+
const resolvedAppConfig = this.config.appConfigProvider ? await this.config.appConfigProvider(state) : void 0;
|
|
31
|
+
const preFlightResult = await this.performPreFlight(spec, resolvedAppConfig);
|
|
32
|
+
if (!preFlightResult.canStart) throw new WorkflowPreFlightError(preFlightResult.issues);
|
|
33
|
+
await this.config.stateStore.create(state);
|
|
34
|
+
this.emit("workflow.started", {
|
|
35
|
+
workflowId,
|
|
36
|
+
workflowName: spec.meta.name,
|
|
37
|
+
workflowVersion: spec.meta.version,
|
|
38
|
+
currentStep: entryStepId
|
|
39
|
+
});
|
|
40
|
+
return workflowId;
|
|
41
|
+
}
|
|
42
|
+
async executeStep(workflowId, input) {
|
|
43
|
+
const state = await this.getStateOrThrow(workflowId);
|
|
44
|
+
if (isTerminalStatus(state.status)) throw new Error(`Workflow ${workflowId} is in terminal status "${state.status}".`);
|
|
45
|
+
const spec = this.getSpec(state.workflowName, state.workflowVersion);
|
|
46
|
+
const step = getCurrentStep(spec, state.currentStep);
|
|
47
|
+
if (!await this.evaluateGuard(step, state, input)) throw new Error(`GuardRejected: ${state.workflowName} -> ${step.id}`);
|
|
48
|
+
const execution = {
|
|
49
|
+
stepId: step.id,
|
|
50
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
51
|
+
status: "running",
|
|
52
|
+
input
|
|
53
|
+
};
|
|
54
|
+
const workingState = {
|
|
55
|
+
...state,
|
|
56
|
+
data: { ...state.data },
|
|
57
|
+
history: [...state.history]
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
const output = await this.runStepAction(step, workingState, input);
|
|
61
|
+
execution.output = output;
|
|
62
|
+
execution.status = "completed";
|
|
63
|
+
execution.completedAt = /* @__PURE__ */ new Date();
|
|
64
|
+
workingState.history.push(execution);
|
|
65
|
+
workingState.updatedAt = /* @__PURE__ */ new Date();
|
|
66
|
+
if (isRecord(input)) workingState.data = {
|
|
67
|
+
...workingState.data,
|
|
68
|
+
...input
|
|
69
|
+
};
|
|
70
|
+
if (isRecord(output)) workingState.data = {
|
|
71
|
+
...workingState.data,
|
|
72
|
+
...output
|
|
73
|
+
};
|
|
74
|
+
const nextStepId = this.pickNextStepId(spec, workingState, step, input, output);
|
|
75
|
+
if (nextStepId) {
|
|
76
|
+
workingState.currentStep = nextStepId;
|
|
77
|
+
workingState.status = "running";
|
|
78
|
+
} else if (!hasOutgoing(spec, step.id)) workingState.status = "completed";
|
|
79
|
+
else throw new Error(`No transition matched after executing step "${step.id}".`);
|
|
80
|
+
await this.config.stateStore.update(workflowId, () => workingState);
|
|
81
|
+
this.emit("workflow.step_completed", {
|
|
82
|
+
workflowId,
|
|
83
|
+
workflowName: state.workflowName,
|
|
84
|
+
stepId: step.id,
|
|
85
|
+
status: workingState.status
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
execution.status = "failed";
|
|
89
|
+
execution.completedAt = /* @__PURE__ */ new Date();
|
|
90
|
+
execution.error = error instanceof Error ? error.message : String(error);
|
|
91
|
+
workingState.history.push(execution);
|
|
92
|
+
workingState.updatedAt = /* @__PURE__ */ new Date();
|
|
93
|
+
if (step.retry) {
|
|
94
|
+
const retries = state.retryCounts?.[step.id] ?? 0;
|
|
95
|
+
if (retries < step.retry.maxAttempts) {
|
|
96
|
+
const backoff = step.retry.backoff ?? "exponential";
|
|
97
|
+
const baseDelay = step.retry.delayMs ?? 1e3;
|
|
98
|
+
const delay = backoff === "exponential" ? baseDelay * Math.pow(2, retries) : baseDelay;
|
|
99
|
+
const cappedDelay = Math.min(delay, step.retry.maxDelayMs ?? Infinity);
|
|
100
|
+
workingState.retryCounts = {
|
|
101
|
+
...state.retryCounts ?? {},
|
|
102
|
+
[step.id]: retries + 1
|
|
103
|
+
};
|
|
104
|
+
workingState.status = "running";
|
|
105
|
+
await this.config.stateStore.update(workflowId, () => workingState);
|
|
106
|
+
this.emit("workflow.step_retrying", {
|
|
107
|
+
workflowId,
|
|
108
|
+
workflowName: state.workflowName,
|
|
109
|
+
stepId: step.id,
|
|
110
|
+
attempt: retries + 1,
|
|
111
|
+
delay: cappedDelay,
|
|
112
|
+
error: execution.error
|
|
113
|
+
});
|
|
114
|
+
await new Promise((resolve) => setTimeout(resolve, cappedDelay));
|
|
115
|
+
return this.executeStep(workflowId, input);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
workingState.status = "failed";
|
|
119
|
+
await this.config.stateStore.update(workflowId, () => workingState);
|
|
120
|
+
this.emit("workflow.step_failed", {
|
|
121
|
+
workflowId,
|
|
122
|
+
workflowName: state.workflowName,
|
|
123
|
+
stepId: step.id,
|
|
124
|
+
error: execution.error ?? "unknown"
|
|
125
|
+
});
|
|
126
|
+
if (spec.definition.compensation?.trigger === "on_failure") await this.rollback(workflowId);
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async rollback(workflowId) {
|
|
131
|
+
const state = await this.getStateOrThrow(workflowId);
|
|
132
|
+
const spec = this.getSpec(state.workflowName, state.workflowVersion);
|
|
133
|
+
if (!spec.definition.compensation) return;
|
|
134
|
+
this.emit("workflow.rollback_started", { workflowId });
|
|
135
|
+
const completedSteps = state.history.filter((h) => h.status === "completed").reverse();
|
|
136
|
+
for (const execution of completedSteps) {
|
|
137
|
+
const compStep = spec.definition.compensation.steps.find((s) => s.stepId === execution.stepId);
|
|
138
|
+
if (compStep) {
|
|
139
|
+
const input = {
|
|
140
|
+
stepId: execution.stepId,
|
|
141
|
+
originalInput: execution.input,
|
|
142
|
+
originalOutput: execution.output,
|
|
143
|
+
workflowData: state.data
|
|
144
|
+
};
|
|
145
|
+
try {
|
|
146
|
+
const step = getCurrentStep(spec, execution.stepId);
|
|
147
|
+
const resolvedAppConfig = this.config.appConfigProvider ? await this.config.appConfigProvider(state) : void 0;
|
|
148
|
+
const executorContext = {
|
|
149
|
+
workflow: state,
|
|
150
|
+
step,
|
|
151
|
+
resolvedAppConfig,
|
|
152
|
+
integrations: resolvedAppConfig?.integrations ?? [],
|
|
153
|
+
knowledge: resolvedAppConfig?.knowledge ?? [],
|
|
154
|
+
branding: resolvedAppConfig?.branding,
|
|
155
|
+
translation: resolvedAppConfig?.translation,
|
|
156
|
+
translationResolver: this.config.translationResolver,
|
|
157
|
+
secretProvider: this.config.secretProvider
|
|
158
|
+
};
|
|
159
|
+
await this.config.opExecutor(compStep.operation, input, executorContext);
|
|
160
|
+
this.emit("workflow.compensation_step_completed", {
|
|
161
|
+
workflowId,
|
|
162
|
+
stepId: execution.stepId,
|
|
163
|
+
compensationOp: compStep.operation.name
|
|
164
|
+
});
|
|
165
|
+
} catch (error) {
|
|
166
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
167
|
+
this.emit("workflow.compensation_step_failed", {
|
|
168
|
+
workflowId,
|
|
169
|
+
stepId: execution.stepId,
|
|
170
|
+
compensationOp: compStep.operation.name,
|
|
171
|
+
error: errorMessage
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
this.emit("workflow.rollback_completed", { workflowId });
|
|
177
|
+
}
|
|
178
|
+
async getState(workflowId) {
|
|
179
|
+
return this.getStateOrThrow(workflowId);
|
|
180
|
+
}
|
|
181
|
+
async cancel(workflowId) {
|
|
182
|
+
const state = await this.getStateOrThrow(workflowId);
|
|
183
|
+
if (state.status === "cancelled") return;
|
|
184
|
+
const nextState = {
|
|
185
|
+
...state,
|
|
186
|
+
status: "cancelled",
|
|
187
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
188
|
+
};
|
|
189
|
+
await this.config.stateStore.update(workflowId, () => nextState);
|
|
190
|
+
this.emit("workflow.cancelled", {
|
|
191
|
+
workflowId,
|
|
192
|
+
workflowName: state.workflowName
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async performPreFlight(spec, resolvedConfig) {
|
|
196
|
+
if (!resolvedConfig) return {
|
|
197
|
+
canStart: true,
|
|
198
|
+
issues: []
|
|
199
|
+
};
|
|
200
|
+
const issues = [];
|
|
201
|
+
const integrationBySlot = /* @__PURE__ */ new Map();
|
|
202
|
+
for (const integration of resolvedConfig.integrations) integrationBySlot.set(integration.slot.slotId, integration);
|
|
203
|
+
for (const step of spec.definition.steps) for (const slotId of step.requiredIntegrations ?? []) {
|
|
204
|
+
const integration = integrationBySlot.get(slotId);
|
|
205
|
+
if (!integration) {
|
|
206
|
+
issues.push({
|
|
207
|
+
stepId: step.id,
|
|
208
|
+
type: "integration",
|
|
209
|
+
identifier: slotId,
|
|
210
|
+
severity: "error",
|
|
211
|
+
reason: `Integration slot "${slotId}" is not bound in the resolved app config.`
|
|
212
|
+
});
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const status = integration.connection.status;
|
|
216
|
+
if (status === "disconnected" || status === "error") issues.push({
|
|
217
|
+
stepId: step.id,
|
|
218
|
+
type: "integration",
|
|
219
|
+
identifier: slotId,
|
|
220
|
+
severity: "error",
|
|
221
|
+
reason: `Integration slot "${slotId}" is in status "${status}".`
|
|
222
|
+
});
|
|
223
|
+
else if (status === "unknown") issues.push({
|
|
224
|
+
stepId: step.id,
|
|
225
|
+
type: "integration",
|
|
226
|
+
identifier: slotId,
|
|
227
|
+
severity: "warning",
|
|
228
|
+
reason: `Integration slot "${slotId}" reports unknown health status.`
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
const enabledCapabilities = new Set(resolvedConfig.capabilities.enabled.map(capabilityKey));
|
|
232
|
+
for (const step of spec.definition.steps) for (const required of step.requiredCapabilities ?? []) if (!enabledCapabilities.has(capabilityKey(required))) issues.push({
|
|
233
|
+
stepId: step.id,
|
|
234
|
+
type: "capability",
|
|
235
|
+
identifier: capabilityKey(required),
|
|
236
|
+
severity: "error",
|
|
237
|
+
reason: `Capability "${required.key}@${required.version}" is not enabled.`
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
canStart: issues.every((issue) => issue.severity !== "error"),
|
|
241
|
+
issues
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async evaluateGuard(step, state, input) {
|
|
245
|
+
if (!step.guard) return true;
|
|
246
|
+
if (this.config.guardEvaluator) return this.config.guardEvaluator(step.guard, {
|
|
247
|
+
workflow: state,
|
|
248
|
+
step,
|
|
249
|
+
input
|
|
250
|
+
});
|
|
251
|
+
if (step.guard.type === "expression") return evaluateExpression(step.guard.value, {
|
|
252
|
+
data: state.data,
|
|
253
|
+
input
|
|
254
|
+
});
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
async runStepAction(step, state, input) {
|
|
258
|
+
if (step.type === "automation") {
|
|
259
|
+
const op = step.action?.operation;
|
|
260
|
+
if (!op) throw new Error(`Automation step "${step.id}" requires an operation.`);
|
|
261
|
+
const resolvedAppConfig = this.config.appConfigProvider ? await this.config.appConfigProvider(state) : void 0;
|
|
262
|
+
const executorContext = {
|
|
263
|
+
workflow: state,
|
|
264
|
+
step,
|
|
265
|
+
resolvedAppConfig,
|
|
266
|
+
integrations: resolvedAppConfig?.integrations ?? [],
|
|
267
|
+
knowledge: resolvedAppConfig?.knowledge ?? [],
|
|
268
|
+
branding: resolvedAppConfig?.branding,
|
|
269
|
+
translation: resolvedAppConfig?.translation,
|
|
270
|
+
translationResolver: this.config.translationResolver,
|
|
271
|
+
secretProvider: this.config.secretProvider
|
|
272
|
+
};
|
|
273
|
+
if (this.config.enforceCapabilities) await this.config.enforceCapabilities(op, executorContext);
|
|
274
|
+
return this.config.opExecutor(op, input, executorContext);
|
|
275
|
+
}
|
|
276
|
+
if (step.type === "human") return input;
|
|
277
|
+
return input;
|
|
278
|
+
}
|
|
279
|
+
pickNextStepId(spec, state, step, input, output) {
|
|
280
|
+
const transitions = spec.definition.transitions.filter((t) => t.from === step.id);
|
|
281
|
+
for (const transition of transitions) if (evaluateExpression(transition.condition, {
|
|
282
|
+
data: state.data,
|
|
283
|
+
input,
|
|
284
|
+
output
|
|
285
|
+
})) {
|
|
286
|
+
const target = spec.definition.steps.find((s) => s.id === transition.to);
|
|
287
|
+
if (!target) throw new Error(`Transition ${transition.from} -> ${transition.to} points to missing step.`);
|
|
288
|
+
return target.id;
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
getSpec(name, version) {
|
|
293
|
+
const spec = this.config.registry.get(name, version);
|
|
294
|
+
if (!spec) throw new Error(`Workflow spec not found for ${name}${version ? `.v${version}` : ""}`);
|
|
295
|
+
return spec;
|
|
296
|
+
}
|
|
297
|
+
async getStateOrThrow(workflowId) {
|
|
298
|
+
const state = await this.config.stateStore.get(workflowId);
|
|
299
|
+
if (!state) throw new Error(`Workflow state not found for ${workflowId}`);
|
|
300
|
+
return state;
|
|
301
|
+
}
|
|
302
|
+
emit(event, payload) {
|
|
303
|
+
this.config.eventEmitter?.(event, payload);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
function resolveEntryStepId(spec) {
|
|
307
|
+
const entry = spec.definition.entryStepId ?? spec.definition.steps[0]?.id ?? null;
|
|
308
|
+
if (!entry) throw new Error(`Workflow ${spec.meta.name}.v${spec.meta.version} has no entry step.`);
|
|
309
|
+
return entry;
|
|
310
|
+
}
|
|
311
|
+
function getCurrentStep(spec, stepId) {
|
|
312
|
+
const step = spec.definition.steps.find((s) => s.id === stepId);
|
|
313
|
+
if (!step) throw new Error(`Step "${stepId}" not found in workflow ${spec.meta.name}.v${spec.meta.version}.`);
|
|
314
|
+
return step;
|
|
315
|
+
}
|
|
316
|
+
function hasOutgoing(spec, stepId) {
|
|
317
|
+
return spec.definition.transitions.some((t) => t.from === stepId);
|
|
318
|
+
}
|
|
319
|
+
function isRecord(value) {
|
|
320
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
321
|
+
}
|
|
322
|
+
function isTerminalStatus(status) {
|
|
323
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
324
|
+
}
|
|
325
|
+
var WorkflowPreFlightError = class extends Error {
|
|
326
|
+
constructor(issues) {
|
|
327
|
+
super(`Workflow pre-flight failed: ${issues.filter((issue) => issue.severity === "error").map((issue) => `${issue.type}:${issue.identifier}`).join(", ")}`);
|
|
328
|
+
this.issues = issues;
|
|
329
|
+
this.name = "WorkflowPreFlightError";
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
function capabilityKey(ref) {
|
|
333
|
+
return `${ref.key}@${ref.version}`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
//#endregion
|
|
337
|
+
export { WorkflowPreFlightError, WorkflowRunner };
|