@lssm/lib.contracts 1.7.3 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -325
- package/dist/app-config/contracts.d.ts +51 -49
- package/dist/app-config/contracts.d.ts.map +1 -1
- package/dist/app-config/contracts.js +1 -1
- package/dist/app-config/contracts.js.map +1 -1
- package/dist/app-config/events.d.ts +28 -26
- package/dist/app-config/events.d.ts.map +1 -1
- package/dist/app-config/events.js +1 -1
- package/dist/app-config/events.js.map +1 -1
- package/dist/app-config/lifecycle-contracts.d.ts +81 -79
- package/dist/app-config/lifecycle-contracts.d.ts.map +1 -1
- package/dist/app-config/lifecycle-contracts.js +1 -1
- package/dist/app-config/lifecycle-contracts.js.map +1 -1
- package/dist/app-config/runtime.d.ts.map +1 -1
- package/dist/app-config/runtime.js.map +1 -1
- package/dist/app-config/spec.d.ts +2 -2
- package/dist/app-config/spec.d.ts.map +1 -1
- package/dist/app-config/spec.js.map +1 -1
- package/dist/app-config/validation.d.ts.map +1 -1
- package/dist/app-config/validation.js.map +1 -1
- package/dist/capabilities/openbanking.d.ts.map +1 -1
- package/dist/capabilities/openbanking.js.map +1 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +1 -1
- package/dist/capabilities.js.map +1 -1
- package/dist/client/react/form-render.d.ts +1 -0
- package/dist/client/react/form-render.d.ts.map +1 -1
- package/dist/contracts-adapter-input.d.ts +1 -0
- package/dist/contracts-adapter-input.d.ts.map +1 -1
- package/dist/data-views/query-generator.d.ts +40 -0
- package/dist/data-views/query-generator.d.ts.map +1 -0
- package/dist/data-views/query-generator.js +2 -0
- package/dist/data-views/query-generator.js.map +1 -0
- package/dist/data-views/runtime.d.ts +27 -0
- package/dist/data-views/runtime.d.ts.map +1 -0
- package/dist/data-views/runtime.js +2 -0
- package/dist/data-views/runtime.js.map +1 -0
- package/dist/data-views.js.map +1 -1
- package/dist/events.d.ts +1 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +1 -1
- package/dist/events.js.map +1 -1
- package/dist/experiments/evaluator.d.ts.map +1 -1
- package/dist/experiments/evaluator.js.map +1 -1
- package/dist/experiments/spec-resolver.d.ts +17 -0
- package/dist/experiments/spec-resolver.d.ts.map +1 -0
- package/dist/experiments/spec-resolver.js +0 -0
- package/dist/experiments/spec.js.map +1 -1
- package/dist/forms.d.ts +1 -0
- package/dist/forms.d.ts.map +1 -1
- package/dist/graphql-federation/dist/index.js +2 -0
- package/dist/graphql-federation/dist/index.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/install.d.ts +1 -0
- package/dist/install.d.ts.map +1 -1
- package/dist/integrations/connection.d.ts.map +1 -1
- package/dist/integrations/contracts.d.ts +103 -101
- package/dist/integrations/contracts.d.ts.map +1 -1
- package/dist/integrations/contracts.js +1 -1
- package/dist/integrations/contracts.js.map +1 -1
- package/dist/integrations/health.d.ts.map +1 -1
- package/dist/integrations/health.js.map +1 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +67 -65
- package/dist/integrations/openbanking/contracts/accounts.d.ts.map +1 -1
- package/dist/integrations/openbanking/contracts/accounts.js +1 -1
- package/dist/integrations/openbanking/contracts/accounts.js.map +1 -1
- package/dist/integrations/openbanking/contracts/balances.d.ts +35 -33
- package/dist/integrations/openbanking/contracts/balances.d.ts.map +1 -1
- package/dist/integrations/openbanking/contracts/balances.js +1 -1
- package/dist/integrations/openbanking/contracts/balances.js.map +1 -1
- package/dist/integrations/openbanking/contracts/index.js.map +1 -1
- package/dist/integrations/openbanking/contracts/transactions.d.ts +49 -47
- package/dist/integrations/openbanking/contracts/transactions.d.ts.map +1 -1
- package/dist/integrations/openbanking/contracts/transactions.js +1 -1
- package/dist/integrations/openbanking/contracts/transactions.js.map +1 -1
- package/dist/integrations/openbanking/guards.js.map +1 -1
- package/dist/integrations/openbanking/models.d.ts +57 -54
- package/dist/integrations/openbanking/models.d.ts.map +1 -1
- package/dist/integrations/openbanking/models.js +1 -1
- package/dist/integrations/openbanking/models.js.map +1 -1
- package/dist/integrations/openbanking/telemetry.js.map +1 -1
- package/dist/integrations/providers/elevenlabs.d.ts.map +1 -1
- package/dist/integrations/providers/elevenlabs.js.map +1 -1
- package/dist/integrations/providers/gcs-storage.js.map +1 -1
- package/dist/integrations/providers/gmail.d.ts.map +1 -1
- package/dist/integrations/providers/gmail.js.map +1 -1
- package/dist/integrations/providers/google-calendar.js.map +1 -1
- package/dist/integrations/providers/impls/elevenlabs-voice.js.map +1 -1
- package/dist/integrations/providers/impls/gcs-storage.js.map +1 -1
- package/dist/integrations/providers/impls/gmail-inbound.js.map +1 -1
- package/dist/integrations/providers/impls/gmail-outbound.d.ts.map +1 -1
- package/dist/integrations/providers/impls/gmail-outbound.js.map +1 -1
- package/dist/integrations/providers/impls/google-calendar.d.ts.map +1 -1
- package/dist/integrations/providers/impls/google-calendar.js.map +1 -1
- package/dist/integrations/providers/impls/mistral-embedding.js.map +1 -1
- package/dist/integrations/providers/impls/mistral-llm.js.map +1 -1
- package/dist/integrations/providers/impls/postmark-email.js.map +1 -1
- package/dist/integrations/providers/impls/powens-client.d.ts.map +1 -1
- package/dist/integrations/providers/impls/powens-client.js.map +1 -1
- package/dist/integrations/providers/impls/powens-openbanking.d.ts.map +1 -1
- package/dist/integrations/providers/impls/powens-openbanking.js.map +1 -1
- package/dist/integrations/providers/impls/provider-factory.d.ts.map +1 -1
- package/dist/integrations/providers/impls/provider-factory.js.map +1 -1
- package/dist/integrations/providers/impls/qdrant-vector.d.ts.map +1 -1
- package/dist/integrations/providers/impls/qdrant-vector.js.map +1 -1
- package/dist/integrations/providers/impls/stripe-payments.d.ts.map +1 -1
- package/dist/integrations/providers/impls/stripe-payments.js.map +1 -1
- package/dist/integrations/providers/impls/twilio-sms.js.map +1 -1
- package/dist/integrations/providers/llm.d.ts.map +1 -1
- package/dist/integrations/providers/mistral.d.ts.map +1 -1
- package/dist/integrations/providers/mistral.js.map +1 -1
- package/dist/integrations/providers/payments.d.ts.map +1 -1
- package/dist/integrations/providers/postmark.d.ts.map +1 -1
- package/dist/integrations/providers/postmark.js.map +1 -1
- package/dist/integrations/providers/powens.js.map +1 -1
- package/dist/integrations/providers/qdrant.d.ts.map +1 -1
- package/dist/integrations/providers/qdrant.js.map +1 -1
- package/dist/integrations/providers/stripe.js.map +1 -1
- package/dist/integrations/providers/twilio-sms.js.map +1 -1
- package/dist/integrations/runtime.d.ts.map +1 -1
- package/dist/integrations/runtime.js.map +1 -1
- package/dist/integrations/secrets/env-secret-provider.js.map +1 -1
- package/dist/integrations/secrets/gcp-secret-manager.d.ts.map +1 -1
- package/dist/integrations/secrets/gcp-secret-manager.js.map +1 -1
- package/dist/integrations/secrets/manager.d.ts +2 -2
- package/dist/integrations/secrets/manager.d.ts.map +1 -1
- package/dist/integrations/secrets/manager.js.map +1 -1
- package/dist/integrations/secrets/provider.js.map +1 -1
- package/dist/integrations/spec.d.ts.map +1 -1
- package/dist/integrations/spec.js.map +1 -1
- package/dist/jobs/gcp-cloud-tasks.js.map +1 -1
- package/dist/jobs/gcp-pubsub.d.ts.map +1 -1
- package/dist/jobs/gcp-pubsub.js.map +1 -1
- package/dist/jobs/handlers/gmail-sync-handler.js.map +1 -1
- package/dist/jobs/handlers/storage-document-handler.js.map +1 -1
- package/dist/jobs/memory-queue.d.ts.map +1 -1
- package/dist/jobs/memory-queue.js.map +1 -1
- package/dist/jobs/queue.d.ts.map +1 -1
- package/dist/jsonschema.d.ts +1 -1
- package/dist/jsonschema.d.ts.map +1 -1
- package/dist/knowledge/contracts.d.ts +67 -65
- package/dist/knowledge/contracts.d.ts.map +1 -1
- package/dist/knowledge/contracts.js +1 -1
- package/dist/knowledge/contracts.js.map +1 -1
- package/dist/knowledge/ingestion/document-processor.js.map +1 -1
- package/dist/knowledge/ingestion/embedding-service.d.ts.map +1 -1
- package/dist/knowledge/ingestion/embedding-service.js.map +1 -1
- package/dist/knowledge/ingestion/gmail-adapter.d.ts.map +1 -1
- package/dist/knowledge/ingestion/gmail-adapter.js.map +1 -1
- package/dist/knowledge/ingestion/storage-adapter.js.map +1 -1
- package/dist/knowledge/ingestion/vector-indexer.js.map +1 -1
- package/dist/knowledge/query/service.d.ts +2 -2
- package/dist/knowledge/query/service.d.ts.map +1 -1
- package/dist/knowledge/query/service.js.map +1 -1
- package/dist/knowledge/runtime.d.ts.map +1 -1
- package/dist/knowledge/runtime.js.map +1 -1
- package/dist/knowledge/spaces/email-threads.js.map +1 -1
- package/dist/knowledge/spaces/financial-docs.js.map +1 -1
- package/dist/knowledge/spaces/financial-overview.js.map +1 -1
- package/dist/knowledge/spaces/product-canon.js.map +1 -1
- package/dist/knowledge/spaces/support-faq.js.map +1 -1
- package/dist/knowledge/spaces/uploaded-docs.js.map +1 -1
- package/dist/knowledge/spec.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js.map +1 -1
- package/dist/onboarding-base.d.ts +30 -28
- package/dist/onboarding-base.d.ts.map +1 -1
- package/dist/onboarding-base.js +1 -1
- package/dist/onboarding-base.js.map +1 -1
- package/dist/policy/engine.js.map +1 -1
- package/dist/policy/opa-adapter.d.ts.map +1 -1
- package/dist/policy/opa-adapter.js.map +1 -1
- package/dist/policy/spec.d.ts.map +1 -1
- package/dist/policy/spec.js.map +1 -1
- package/dist/presentations.d.ts +1 -0
- package/dist/presentations.d.ts.map +1 -1
- package/dist/presentations.v2.d.ts +1 -0
- package/dist/presentations.v2.d.ts.map +1 -1
- package/dist/regenerator/executor.d.ts.map +1 -1
- package/dist/regenerator/executor.js.map +1 -1
- package/dist/regenerator/service.d.ts.map +1 -1
- package/dist/regenerator/service.js.map +1 -1
- package/dist/regenerator/sinks.d.ts.map +1 -1
- package/dist/regenerator/sinks.js.map +1 -1
- package/dist/regenerator/types.d.ts.map +1 -1
- package/dist/regenerator/utils.js.map +1 -1
- package/dist/registry.d.ts +37 -9
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/schema/dist/FieldType.js +2 -0
- package/dist/schema/dist/FieldType.js.map +1 -0
- package/dist/schema/dist/ScalarTypeEnum.js +2 -0
- package/dist/schema/dist/ScalarTypeEnum.js.map +1 -0
- package/dist/schema/{src → dist}/SchemaModel.js +1 -1
- package/dist/schema/dist/SchemaModel.js.map +1 -0
- package/dist/schema/dist/index.js +1 -0
- package/dist/server/graphql-pothos.d.ts +15 -2
- package/dist/server/graphql-pothos.d.ts.map +1 -1
- package/dist/server/graphql-pothos.js.map +1 -1
- package/dist/server/graphql-schema-export.js +1 -1
- package/dist/server/graphql-schema-export.js.map +1 -1
- package/dist/server/provider-mcp.d.ts +22 -4
- package/dist/server/provider-mcp.d.ts.map +1 -1
- package/dist/server/provider-mcp.js.map +1 -1
- package/dist/server/rest-next-app.d.ts +23 -3
- package/dist/server/rest-next-app.d.ts.map +1 -1
- package/dist/server/rest-next-app.js.map +1 -1
- package/dist/spec.d.ts +23 -0
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/telemetry/anomaly.js.map +1 -1
- package/dist/telemetry/spec.d.ts.map +1 -1
- package/dist/telemetry/spec.js.map +1 -1
- package/dist/telemetry/tracker.d.ts.map +1 -1
- package/dist/telemetry/tracker.js.map +1 -1
- package/dist/tests/runner.js.map +1 -1
- package/dist/tests/spec.js.map +1 -1
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js.map +1 -1
- package/dist/types/all.d.ts +2 -2
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow/adapters/db-adapter.d.ts +30 -10
- package/dist/workflow/adapters/db-adapter.d.ts.map +1 -1
- package/dist/workflow/adapters/db-adapter.js +1 -1
- package/dist/workflow/adapters/db-adapter.js.map +1 -1
- package/dist/workflow/adapters/file-adapter.js.map +1 -1
- package/dist/workflow/adapters/index.d.ts +2 -2
- package/dist/workflow/adapters/index.js +1 -1
- package/dist/workflow/adapters/memory-store.d.ts.map +1 -1
- package/dist/workflow/adapters/memory-store.js.map +1 -1
- package/dist/workflow/expression.js.map +1 -1
- package/dist/workflow/index.d.ts +2 -2
- package/dist/workflow/index.js +1 -1
- package/dist/workflow/runner.d.ts +1 -0
- package/dist/workflow/runner.d.ts.map +1 -1
- package/dist/workflow/runner.js +1 -1
- package/dist/workflow/runner.js.map +1 -1
- package/dist/workflow/sla-monitor.d.ts +21 -0
- package/dist/workflow/sla-monitor.d.ts.map +1 -0
- package/dist/workflow/sla-monitor.js +2 -0
- package/dist/workflow/sla-monitor.js.map +1 -0
- package/dist/workflow/spec.d.ts.map +1 -1
- package/dist/workflow/spec.js.map +1 -1
- package/dist/workflow/state.d.ts +1 -0
- package/dist/workflow/state.d.ts.map +1 -1
- package/dist/workflow/validation.d.ts.map +1 -1
- package/dist/workflow/validation.js.map +1 -1
- package/package.json +181 -177
- package/dist/graphql-federation/src/index.js +0 -2
- package/dist/graphql-federation/src/index.js.map +0 -1
- package/dist/schema/src/FieldType.js +0 -2
- package/dist/schema/src/FieldType.js.map +0 -1
- package/dist/schema/src/ScalarTypeEnum.js +0 -2
- package/dist/schema/src/ScalarTypeEnum.js.map +0 -1
- package/dist/schema/src/SchemaModel.js.map +0 -1
- package/dist/schema/src/index.js +0 -1
- /package/dist/schema/{src → dist}/EnumType.js +0 -0
package/dist/types.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { TelemetryTracker } from "./telemetry/tracker.js";
|
|
|
4
4
|
import { Locale, MessageKey } from "./translations/catalog.js";
|
|
5
5
|
import { ResolvedAppConfig, ResolvedIntegration, ResolvedKnowledge, ResolvedTranslation } from "./app-config/runtime.js";
|
|
6
6
|
import { SecretProvider } from "./integrations/secrets/provider.js";
|
|
7
|
+
import { SpecVariantResolver } from "./experiments/spec-resolver.js";
|
|
7
8
|
|
|
8
9
|
//#region src/types.d.ts
|
|
9
10
|
/**
|
|
@@ -80,6 +81,8 @@ interface HandlerCtx {
|
|
|
80
81
|
config: ResolvedTranslation;
|
|
81
82
|
resolve?: TranslationResolver;
|
|
82
83
|
};
|
|
84
|
+
/** Optional spec variant resolver for experiments */
|
|
85
|
+
specVariantResolver?: SpecVariantResolver;
|
|
83
86
|
}
|
|
84
87
|
//#endregion
|
|
85
88
|
export { Actor, Channel, EventPublisher, FieldLevelDecision, HandlerCtx, PolicyDecider, PolicyDeciderInput, PolicyDecision, RateLimiter, TranslationResolver };
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;KAGY,KAAA;KACA,OAAA;AAyBK,UANA,kBAAA,CAMc;EAI3B,KAAA,EAAA,MAAA;EADU,MAAA,EAAA,OAAA,GAAA,MAAA;EAKK,MAAA,CAAA,EAAA,MAAA;;AAEE,UAVJ,cAAA,CAUI;EAAiB,MAAA,EAAA,OAAA,GAAA,MAAA;EAIrB,MAAA,CAAA,EAAA,MAAA;EAYL,SAAA,CAAA,EAvBE,IAuBW,CAtBrB,mBAsBqB,EAAA,KAAA,GAAA,KAAA,GAAA,eAAA,GAAA,OAAA,CAAA;EAChB,QAAA,CAAA,EAAA,cAAA,GAAA,IAAA;EACI,cAAA,CAAA,EApBM,kBAoBN,EAAA;EAAR,GAAA,CAAA,EAnBG,UAmBH,CAAA,KAAA,CAAA;EAAO,gBAAA,CAAA,EAlBS,iBAkBT,EAAA;EAEA,WAAA,CAAA,EAAW,QAAA,GAAA,KAIlB;AAEL;AACO,UAvBU,kBAAA,CAuBV;EACI,OAAA,EAAA,MAAA;EACN,OAAA,EAAA,MAAA;EAAO,OAAA,EAAA,MAAA;EAGA,KAAA,EAxBH,KAwBG;EAOK,OAAA,CAAA,EA9BL,OA8Be;EAKjB,KAAA,CAAA,EAAA,MAAA,EAAA;EACE,cAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAID,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAEG,KAAA,CAAA,EAAA,MAAA,EAAA;;AAIK,KAvCP,aAAA,GAuCO,CAAA,KAAA,EAtCV,kBAsCU,EAAA,GArCd,OAqCc,CArCN,cAqCM,CAAA;AAEA,KArCP,WAAA,GAqCO,CAAA,GAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,EAAA,GAjCd,OAiCc,CAAA,IAAA,CAAA;AAOZ,KAtCK,mBAAA,GAsCL,CAAA,GAAA,EArCA,UAqCA,EAAA,MAAA,CAAA,EApCI,MAoCJ,EAAA,GAnCF,OAmCE,CAAA,MAAA,GAAA,IAAA,CAAA,GAAA,MAAA,GAAA,IAAA;;AAIU,KApCL,cAAA,GAoCK,CAAA,QAAA,EAAA;EAEH,IAAA,EAAA,MAAA;EAED,OAAA,EAAA,MAAA;EAGD,OAAA,EAAA,OAAA;EACE,OAAA,CAAA,EAAA,MAAA;CAGU,EAAA,GA1ClB,OA0CkB,CAAA,IAAA,CAAA;AAAmB,UAxC1B,UAAA,CAwC0B;;;;;UAnCjC;YACE;;;WAID;;cAEG;;cAEA;;mBAEK;;mBAEA;;uEAOZ;;cAEO;;iBAEG;;cAEH;;aAED;;;YAGD;cACE;;;wBAGU"}
|
|
@@ -1,15 +1,35 @@
|
|
|
1
|
-
import { StateStore } from "../state.js";
|
|
1
|
+
import { StateStore, WorkflowState, WorkflowStateFilters } from "../state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/workflow/adapters/db-adapter.d.ts
|
|
4
|
-
interface
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
interface PrismaClientLike {
|
|
5
|
+
workflowState: {
|
|
6
|
+
create: (args: {
|
|
7
|
+
data: any;
|
|
8
|
+
}) => Promise<any>;
|
|
9
|
+
findUnique: (args: {
|
|
10
|
+
where: {
|
|
11
|
+
id: string;
|
|
12
|
+
};
|
|
13
|
+
}) => Promise<any>;
|
|
14
|
+
update: (args: {
|
|
15
|
+
where: {
|
|
16
|
+
id: string;
|
|
17
|
+
};
|
|
18
|
+
data: any;
|
|
19
|
+
}) => Promise<any>;
|
|
20
|
+
findMany: (args: {
|
|
21
|
+
where?: any;
|
|
22
|
+
}) => Promise<any[]>;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
declare class PrismaStateStore implements StateStore {
|
|
26
|
+
private readonly prisma;
|
|
27
|
+
constructor(prisma: PrismaClientLike);
|
|
28
|
+
create(state: WorkflowState): Promise<void>;
|
|
29
|
+
get(workflowId: string): Promise<WorkflowState | undefined>;
|
|
30
|
+
update(workflowId: string, updater: (current: WorkflowState) => WorkflowState): Promise<WorkflowState>;
|
|
31
|
+
list(filters?: WorkflowStateFilters): Promise<WorkflowState[]>;
|
|
7
32
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Placeholder factory to guide future database adapters (PostgreSQL, MongoDB, etc.).
|
|
10
|
-
* Consumers should provide their own implementation that satisfies {@link StateStore}.
|
|
11
|
-
*/
|
|
12
|
-
declare function createDatabaseStateStore(_options: DatabaseStateStoreOptions): StateStore;
|
|
13
33
|
//#endregion
|
|
14
|
-
export {
|
|
34
|
+
export { PrismaStateStore };
|
|
15
35
|
//# sourceMappingURL=db-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-adapter.d.ts","names":[],"sources":["../../../src/workflow/adapters/db-adapter.ts"],"sourcesContent":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"db-adapter.d.ts","names":[],"sources":["../../../src/workflow/adapters/db-adapter.ts"],"sourcesContent":[],"mappings":";;;UAGU,gBAAA;;IAAA,MAAA,EAAA,CAAA,IAAA,EAAgB;MAEW,IAAA,EAAA,GAAA;IACgB,CAAA,EAAA,GADhB,OACgB,CAAA,GAAA,CAAA;IACO,UAAA,EAAA,CAAA,IAAA,EAAA;MACnB,KAAA,EAAA;QAAO,EAAA,EAAA,MAAA;MAInC,CAAA;IAC0B,CAAA,EAAA,GAPc,OAOd,CAAA,GAAA,CAAA;IAEjB,MAAA,EAAA,CAAA,IAAA,EAAA;MAAgB,KAAA,EAAA;QAiBG,EAAA,EAAA,MAAA;MAAR,CAAA;MAuBV,IAAA,EAAA,GAAA;IAAkB,CAAA,EAAA,GAhDmB,OAgDnB,CAAA,GAAA,CAAA;IAC5B,QAAA,EAAA,CAAA,IAAA,EAAA;MAAR,KAAA,CAAA,EAAA,GAAA;IAkCkB,CAAA,EAAA,GAlFkB,OAkFlB,CAAA,GAAA,EAAA,CAAA;EAA+B,CAAA;;AA9Eb,cAA5B,gBAAA,YAA4B,UAAA,CAAA;EAAU,iBAAA,MAAA;sBACZ;gBAEjB,gBAAgB;2BAiBL,QAAQ;gDAuBlB,kBAAkB,gBACpC,QAAQ;iBAkCU,uBAAuB,QAAQ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
var e=class{constructor(e){this.prisma=e}async create(e){await this.prisma.workflowState.create({data:{id:e.workflowId,name:e.workflowName,version:e.workflowVersion,status:e.status,currentStep:e.currentStep,data:e.data,history:e.history,retryCounts:e.retryCounts??{},createdAt:e.createdAt,updatedAt:e.updatedAt}})}async get(e){let t=await this.prisma.workflowState.findUnique({where:{id:e}});if(t)return{workflowId:t.id,workflowName:t.name,workflowVersion:t.version,currentStep:t.currentStep,data:t.data,history:t.history,retryCounts:t.retryCounts,status:t.status,createdAt:t.createdAt,updatedAt:t.updatedAt}}async update(e,t){let n=await this.get(e);if(!n)throw Error(`Workflow ${e} not found`);let r=t(n),i=await this.prisma.workflowState.update({where:{id:e},data:{status:r.status,currentStep:r.currentStep,data:r.data,history:r.history,retryCounts:r.retryCounts,updatedAt:r.updatedAt}});return{workflowId:i.id,workflowName:i.name,workflowVersion:i.version,currentStep:i.currentStep,data:i.data,history:i.history,retryCounts:i.retryCounts,status:i.status,createdAt:i.createdAt,updatedAt:i.updatedAt}}async list(e){let t={};return e?.status&&(t.status=e.status),(await this.prisma.workflowState.findMany({where:t})).map(e=>({workflowId:e.id,workflowName:e.name,workflowVersion:e.version,currentStep:e.currentStep,data:e.data,history:e.history,retryCounts:e.retryCounts,status:e.status,createdAt:e.createdAt,updatedAt:e.updatedAt}))}};export{e as PrismaStateStore};
|
|
2
2
|
//# sourceMappingURL=db-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-adapter.js","names":[],"sources":["../../../src/workflow/adapters/db-adapter.ts"],"sourcesContent":["import type { StateStore } from '../state';\n\
|
|
1
|
+
{"version":3,"file":"db-adapter.js","names":["prisma: PrismaClientLike","where: any"],"sources":["../../../src/workflow/adapters/db-adapter.ts"],"sourcesContent":["import type { StateStore, WorkflowState, WorkflowStateFilters } from '../state';\n\n// Generic interface for Prisma Client to avoid hard dependency on generated client\ninterface PrismaClientLike {\n workflowState: {\n create: (args: { data: any }) => Promise<any>;\n findUnique: (args: { where: { id: string } }) => Promise<any>;\n update: (args: { where: { id: string }; data: any }) => Promise<any>;\n findMany: (args: { where?: any }) => Promise<any[]>;\n };\n}\n\nexport class PrismaStateStore implements StateStore {\n constructor(private readonly prisma: PrismaClientLike) {}\n\n async create(state: WorkflowState): Promise<void> {\n await this.prisma.workflowState.create({\n data: {\n id: state.workflowId,\n name: state.workflowName,\n version: state.workflowVersion,\n status: state.status,\n currentStep: state.currentStep,\n data: state.data, // Assumes Prisma handles JSON\n history: state.history, // Assumes Prisma handles JSON\n retryCounts: state.retryCounts ?? {},\n createdAt: state.createdAt,\n updatedAt: state.updatedAt,\n },\n });\n }\n\n async get(workflowId: string): Promise<WorkflowState | undefined> {\n const record = await this.prisma.workflowState.findUnique({\n where: { id: workflowId },\n });\n\n if (!record) return undefined;\n\n return {\n workflowId: record.id,\n workflowName: record.name,\n workflowVersion: record.version,\n currentStep: record.currentStep,\n data: record.data as Record<string, unknown>,\n history: record.history as any[],\n retryCounts: record.retryCounts as Record<string, number>,\n status: record.status as any,\n createdAt: record.createdAt,\n updatedAt: record.updatedAt,\n };\n }\n\n async update(\n workflowId: string,\n updater: (current: WorkflowState) => WorkflowState\n ): Promise<WorkflowState> {\n const current = await this.get(workflowId);\n if (!current) {\n throw new Error(`Workflow ${workflowId} not found`);\n }\n\n const next = updater(current);\n\n const updated = await this.prisma.workflowState.update({\n where: { id: workflowId },\n data: {\n status: next.status,\n currentStep: next.currentStep,\n data: next.data,\n history: next.history,\n retryCounts: next.retryCounts,\n updatedAt: next.updatedAt,\n },\n });\n\n return {\n workflowId: updated.id,\n workflowName: updated.name,\n workflowVersion: updated.version,\n currentStep: updated.currentStep,\n data: updated.data as Record<string, unknown>,\n history: updated.history as any[],\n retryCounts: updated.retryCounts as Record<string, number>,\n status: updated.status as any,\n createdAt: updated.createdAt,\n updatedAt: updated.updatedAt,\n };\n }\n\n async list(filters?: WorkflowStateFilters): Promise<WorkflowState[]> {\n const where: any = {};\n if (filters?.status) {\n where.status = filters.status;\n }\n\n const records = await this.prisma.workflowState.findMany({\n where,\n });\n\n return records.map((record) => ({\n workflowId: record.id,\n workflowName: record.name,\n workflowVersion: record.version,\n currentStep: record.currentStep,\n data: record.data as Record<string, unknown>,\n history: record.history as any[],\n retryCounts: record.retryCounts as Record<string, number>,\n status: record.status as any,\n createdAt: record.createdAt,\n updatedAt: record.updatedAt,\n }));\n }\n}\n"],"mappings":"AAYA,IAAa,EAAb,KAAoD,CAClD,YAAY,EAA2C,CAA1B,KAAA,OAAA,EAE7B,MAAM,OAAO,EAAqC,CAChD,MAAM,KAAK,OAAO,cAAc,OAAO,CACrC,KAAM,CACJ,GAAI,EAAM,WACV,KAAM,EAAM,aACZ,QAAS,EAAM,gBACf,OAAQ,EAAM,OACd,YAAa,EAAM,YACnB,KAAM,EAAM,KACZ,QAAS,EAAM,QACf,YAAa,EAAM,aAAe,EAAE,CACpC,UAAW,EAAM,UACjB,UAAW,EAAM,UAClB,CACF,CAAC,CAGJ,MAAM,IAAI,EAAwD,CAChE,IAAM,EAAS,MAAM,KAAK,OAAO,cAAc,WAAW,CACxD,MAAO,CAAE,GAAI,EAAY,CAC1B,CAAC,CAEG,KAEL,MAAO,CACL,WAAY,EAAO,GACnB,aAAc,EAAO,KACrB,gBAAiB,EAAO,QACxB,YAAa,EAAO,YACpB,KAAM,EAAO,KACb,QAAS,EAAO,QAChB,YAAa,EAAO,YACpB,OAAQ,EAAO,OACf,UAAW,EAAO,UAClB,UAAW,EAAO,UACnB,CAGH,MAAM,OACJ,EACA,EACwB,CACxB,IAAM,EAAU,MAAM,KAAK,IAAI,EAAW,CAC1C,GAAI,CAAC,EACH,MAAU,MAAM,YAAY,EAAW,YAAY,CAGrD,IAAM,EAAO,EAAQ,EAAQ,CAEvB,EAAU,MAAM,KAAK,OAAO,cAAc,OAAO,CACrD,MAAO,CAAE,GAAI,EAAY,CACzB,KAAM,CACJ,OAAQ,EAAK,OACb,YAAa,EAAK,YAClB,KAAM,EAAK,KACX,QAAS,EAAK,QACd,YAAa,EAAK,YAClB,UAAW,EAAK,UACjB,CACF,CAAC,CAEF,MAAO,CACL,WAAY,EAAQ,GACpB,aAAc,EAAQ,KACtB,gBAAiB,EAAQ,QACzB,YAAa,EAAQ,YACrB,KAAM,EAAQ,KACd,QAAS,EAAQ,QACjB,YAAa,EAAQ,YACrB,OAAQ,EAAQ,OAChB,UAAW,EAAQ,UACnB,UAAW,EAAQ,UACpB,CAGH,MAAM,KAAK,EAA0D,CACnE,IAAMC,EAAa,EAAE,CASrB,OARI,GAAS,SACX,EAAM,OAAS,EAAQ,SAGT,MAAM,KAAK,OAAO,cAAc,SAAS,CACvD,QACD,CAAC,EAEa,IAAK,IAAY,CAC9B,WAAY,EAAO,GACnB,aAAc,EAAO,KACrB,gBAAiB,EAAO,QACxB,YAAa,EAAO,YACpB,KAAM,EAAO,KACb,QAAS,EAAO,QAChB,YAAa,EAAO,YACpB,OAAQ,EAAO,OACf,UAAW,EAAO,UAClB,UAAW,EAAO,UACnB,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-adapter.js","names":[],"sources":["../../../src/workflow/adapters/file-adapter.ts"],"sourcesContent":["import type { StateStore } from '../state';\n\nexport interface FileStateStoreOptions {\n /** Absolute or relative path to the persistence file. */\n filePath: string;\n}\n\n/**\n * Placeholder for a file-backed state store adapter.\n * Implementations should manage locking/concurrency and JSON serialization.\n */\nexport function createFileStateStore(\n _options: FileStateStoreOptions\n): StateStore {\n throw new Error(\n 'File-backed state store adapter not implemented. Provide a custom adapter that satisfies StateStore.'\n );\n}\n
|
|
1
|
+
{"version":3,"file":"file-adapter.js","names":[],"sources":["../../../src/workflow/adapters/file-adapter.ts"],"sourcesContent":["import type { StateStore } from '../state';\n\nexport interface FileStateStoreOptions {\n /** Absolute or relative path to the persistence file. */\n filePath: string;\n}\n\n/**\n * Placeholder for a file-backed state store adapter.\n * Implementations should manage locking/concurrency and JSON serialization.\n */\nexport function createFileStateStore(\n _options: FileStateStoreOptions\n): StateStore {\n throw new Error(\n 'File-backed state store adapter not implemented. Provide a custom adapter that satisfies StateStore.'\n );\n}\n"],"mappings":"AAWA,SAAgB,EACd,EACY,CACZ,MAAU,MACR,uGACD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { InMemoryStateStore } from "./memory-store.js";
|
|
2
|
-
import {
|
|
2
|
+
import { PrismaStateStore } from "./db-adapter.js";
|
|
3
3
|
import { FileStateStoreOptions, createFileStateStore } from "./file-adapter.js";
|
|
4
|
-
export {
|
|
4
|
+
export { FileStateStoreOptions, InMemoryStateStore, PrismaStateStore, createFileStateStore };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{InMemoryStateStore as e}from"./memory-store.js";import{
|
|
1
|
+
import{InMemoryStateStore as e}from"./memory-store.js";import{PrismaStateStore as t}from"./db-adapter.js";import{createFileStateStore as n}from"./file-adapter.js";export{e as InMemoryStateStore,t as PrismaStateStore,n as createFileStateStore};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.d.ts","names":[],"sources":["../../../src/workflow/adapters/memory-store.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","names":[],"sources":["../../../src/workflow/adapters/memory-store.ts"],"sourcesContent":[],"mappings":";;;;;;AAwBA;;AAGsC,cAHzB,kBAAA,YAA8B,UAGL,CAAA;EAMG,iBAAA,KAAA;EAAR,MAAA,CAAA,KAAA,EANX,aAMW,CAAA,EANK,OAML,CAAA,IAAA,CAAA;EAOV,GAAA,CAAA,UAAA,EAAA,MAAA,CAAA,EAPU,OAOV,CAPkB,aAOlB,GAAA,SAAA,CAAA;EAAkB,MAAA,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EAAA,CAAA,OAAA,EAAlB,aAAkB,EAAA,GAAA,aAAA,CAAA,EACpC,OADoC,CAC5B,aAD4B,CAAA;EAC5B,IAAA,CAAA,OAAA,CAAA,EAQU,oBARV,CAAA,EAQiC,OARjC,CAQyC,aARzC,EAAA,CAAA;EAAR,KAAA,CAAA,CAAA,EAAA,IAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.js","names":["result: Record<string, unknown>"],"sources":["../../../src/workflow/adapters/memory-store.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"memory-store.js","names":["result: Record<string, unknown>"],"sources":["../../../src/workflow/adapters/memory-store.ts"],"sourcesContent":["import type { StateStore, WorkflowState, WorkflowStateFilters } from '../state';\n\nfunction cloneState(state: WorkflowState): WorkflowState {\n return {\n ...state,\n data: deepCopy(state.data),\n history: state.history.map((execution) => ({\n ...execution,\n input: deepCopy(execution.input),\n output: deepCopy(execution.output),\n startedAt: new Date(execution.startedAt),\n completedAt: execution.completedAt\n ? new Date(execution.completedAt)\n : undefined,\n })),\n createdAt: new Date(state.createdAt),\n updatedAt: new Date(state.updatedAt),\n };\n}\n\n/**\n * Naive in-memory state store. Suitable for tests and single-node development\n * environments. Swap with a database-backed adapter in production.\n */\nexport class InMemoryStateStore implements StateStore {\n private readonly items = new Map<string, WorkflowState>();\n\n async create(state: WorkflowState): Promise<void> {\n if (this.items.has(state.workflowId))\n throw new Error(`Workflow state already exists: ${state.workflowId}`);\n this.items.set(state.workflowId, cloneState(state));\n }\n\n async get(workflowId: string): Promise<WorkflowState | undefined> {\n const state = this.items.get(workflowId);\n return state ? cloneState(state) : undefined;\n }\n\n async update(\n workflowId: string,\n updater: (current: WorkflowState) => WorkflowState\n ): Promise<WorkflowState> {\n const current = this.items.get(workflowId);\n if (!current) throw new Error(`Workflow state not found for ${workflowId}`);\n const next = cloneState(updater(cloneState(current)));\n this.items.set(workflowId, next);\n return cloneState(next);\n }\n\n async list(filters?: WorkflowStateFilters): Promise<WorkflowState[]> {\n const all = [...this.items.values()];\n const filtered = filters?.status\n ? all.filter((state) => state.status === filters.status)\n : all;\n return filtered.map(cloneState);\n }\n\n clear() {\n this.items.clear();\n }\n}\n\nfunction deepCopy<T>(value: T): T {\n if (value instanceof Date) return new Date(value.getTime()) as T;\n if (Array.isArray(value)) return value.map((item) => deepCopy(item)) as T;\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = deepCopy(val);\n }\n return result as T;\n }\n return value;\n}\n"],"mappings":"AAEA,SAAS,EAAW,EAAqC,CACvD,MAAO,CACL,GAAG,EACH,KAAM,EAAS,EAAM,KAAK,CAC1B,QAAS,EAAM,QAAQ,IAAK,IAAe,CACzC,GAAG,EACH,MAAO,EAAS,EAAU,MAAM,CAChC,OAAQ,EAAS,EAAU,OAAO,CAClC,UAAW,IAAI,KAAK,EAAU,UAAU,CACxC,YAAa,EAAU,YACnB,IAAI,KAAK,EAAU,YAAY,CAC/B,IAAA,GACL,EAAE,CACH,UAAW,IAAI,KAAK,EAAM,UAAU,CACpC,UAAW,IAAI,KAAK,EAAM,UAAU,CACrC,CAOH,IAAa,EAAb,KAAsD,CACpD,MAAyB,IAAI,IAE7B,MAAM,OAAO,EAAqC,CAChD,GAAI,KAAK,MAAM,IAAI,EAAM,WAAW,CAClC,MAAU,MAAM,kCAAkC,EAAM,aAAa,CACvE,KAAK,MAAM,IAAI,EAAM,WAAY,EAAW,EAAM,CAAC,CAGrD,MAAM,IAAI,EAAwD,CAChE,IAAM,EAAQ,KAAK,MAAM,IAAI,EAAW,CACxC,OAAO,EAAQ,EAAW,EAAM,CAAG,IAAA,GAGrC,MAAM,OACJ,EACA,EACwB,CACxB,IAAM,EAAU,KAAK,MAAM,IAAI,EAAW,CAC1C,GAAI,CAAC,EAAS,MAAU,MAAM,gCAAgC,IAAa,CAC3E,IAAM,EAAO,EAAW,EAAQ,EAAW,EAAQ,CAAC,CAAC,CAErD,OADA,KAAK,MAAM,IAAI,EAAY,EAAK,CACzB,EAAW,EAAK,CAGzB,MAAM,KAAK,EAA0D,CACnE,IAAM,EAAM,CAAC,GAAG,KAAK,MAAM,QAAQ,CAAC,CAIpC,OAHiB,GAAS,OACtB,EAAI,OAAQ,GAAU,EAAM,SAAW,EAAQ,OAAO,CACtD,GACY,IAAI,EAAW,CAGjC,OAAQ,CACN,KAAK,MAAM,OAAO,GAItB,SAAS,EAAY,EAAa,CAChC,GAAI,aAAiB,KAAM,OAAO,IAAI,KAAK,EAAM,SAAS,CAAC,CAC3D,GAAI,MAAM,QAAQ,EAAM,CAAE,OAAO,EAAM,IAAK,GAAS,EAAS,EAAK,CAAC,CACpE,GAAI,GAAS,OAAO,GAAU,SAAU,CACtC,IAAMA,EAAkC,EAAE,CAC1C,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,EAAiC,CACvE,EAAO,GAAO,EAAS,EAAI,CAE7B,OAAO,EAET,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expression.js","names":["current: any","parts: string[]"],"sources":["../../src/workflow/expression.ts"],"sourcesContent":["export interface ExpressionContext {\n data: Record<string, unknown>;\n input?: unknown;\n output?: unknown;\n}\n\nexport function evaluateExpression(\n expression: string | undefined,\n ctx: ExpressionContext\n): boolean {\n if (!expression) return true;\n const trimmed = expression.trim();\n if (!trimmed) return true;\n\n const orParts = splitByOperator(trimmed, '||');\n if (orParts.length > 1)
|
|
1
|
+
{"version":3,"file":"expression.js","names":["current: any","parts: string[]"],"sources":["../../src/workflow/expression.ts"],"sourcesContent":["export interface ExpressionContext {\n data: Record<string, unknown>;\n input?: unknown;\n output?: unknown;\n}\n\nexport function evaluateExpression(\n expression: string | undefined,\n ctx: ExpressionContext\n): boolean {\n if (!expression) return true;\n const trimmed = expression.trim();\n if (!trimmed) return true;\n\n const orParts = splitByOperator(trimmed, '||');\n if (orParts.length > 1)\n return orParts.some((part) => evaluateExpression(part, ctx));\n\n const andParts = splitByOperator(trimmed, '&&');\n if (andParts.length > 1)\n return andParts.every((part) => evaluateExpression(part, ctx));\n\n return evaluateSingle(trimmed, ctx);\n}\n\nfunction evaluateSingle(expr: string, ctx: ExpressionContext): boolean {\n const trimmed = expr.trim();\n if (!trimmed) return true;\n if (trimmed.startsWith('!')) return !evaluateSingle(trimmed.slice(1), ctx);\n\n const comparisonMatch = trimmed.match(\n /^(data|input|output)\\.([A-Za-z0-9_.\\[\\]]+)\\s*(===|==|!==|!=|>=|<=|>|<)\\s*(.+)$/\n );\n if (comparisonMatch) {\n const [, root, path, operator, rawRight] = comparisonMatch as [\n string,\n string,\n string,\n ComparisonOperator,\n string,\n ];\n const left = resolveRoot(root, ctx, path);\n const right = parseLiteral(rawRight);\n return compare(left, right, operator);\n }\n\n const truthyMatch = trimmed.match(\n /^(data|input|output)\\.([A-Za-z0-9_.\\[\\]]+)$/\n );\n if (truthyMatch) {\n const [, root, path] = truthyMatch as [string, string, string];\n const value = resolveRoot(root, ctx, path);\n return Boolean(value);\n }\n\n const literal = parseLiteral(trimmed);\n return Boolean(literal);\n}\n\ntype ComparisonOperator = '===' | '==' | '!==' | '!=' | '>=' | '<=' | '>' | '<';\n\nfunction compare(\n left: unknown,\n right: unknown,\n operator: ComparisonOperator\n): boolean {\n switch (operator) {\n case '===':\n case '==':\n return left === right;\n case '!==':\n case '!=':\n return left !== right;\n case '>':\n return Number(left) > Number(right);\n case '>=':\n return Number(left) >= Number(right);\n case '<':\n return Number(left) < Number(right);\n case '<=':\n return Number(left) <= Number(right);\n default:\n return false;\n }\n}\n\nfunction parseLiteral(value: string): unknown {\n const trimmed = (value ?? '').trim();\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n )\n return trimmed.slice(1, -1);\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) return Number(trimmed);\n if (/^true$/i.test(trimmed)) return true;\n if (/^false$/i.test(trimmed)) return false;\n if (/^null$/i.test(trimmed)) return null;\n if (/^undefined$/i.test(trimmed)) return undefined;\n return trimmed;\n}\n\nfunction resolveRoot(\n root: string,\n ctx: ExpressionContext,\n path: string\n): unknown {\n const source =\n root === 'data' ? ctx.data : root === 'input' ? ctx.input : ctx.output;\n return resolvePath(source, path);\n}\n\nfunction resolvePath(source: unknown, path: string): unknown {\n if (source == null) return undefined;\n if (!path) return source;\n const segments = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n\n let current: any = source;\n for (const segment of segments) {\n if (current == null) return undefined;\n current = current[segment as keyof typeof current];\n }\n return current;\n}\n\nfunction splitByOperator(expr: string, operator: '&&' | '||'): string[] {\n const parts: string[] = [];\n let buffer = '';\n let inSingleQuote = false;\n let inDoubleQuote = false;\n\n for (let i = 0; i < expr.length; i++) {\n const char = expr[i]!;\n const next = expr.slice(i, i + operator.length);\n\n if (char === \"'\" && !inDoubleQuote) {\n inSingleQuote = !inSingleQuote;\n buffer += char;\n continue;\n }\n if (char === '\"' && !inSingleQuote) {\n inDoubleQuote = !inDoubleQuote;\n buffer += char;\n continue;\n }\n\n if (!inSingleQuote && !inDoubleQuote && next === operator) {\n parts.push(buffer.trim());\n buffer = '';\n i += operator.length - 1;\n continue;\n }\n\n buffer += char;\n }\n\n if (buffer.trim().length) parts.push(buffer.trim());\n return parts;\n}\n"],"mappings":"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"}
|
package/dist/workflow/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { StateStore, StepExecution, WorkflowState, WorkflowStateFilters } from "
|
|
|
4
4
|
import { GuardContext, GuardEvaluator, OperationExecutor, OperationExecutorContext, WorkflowPreFlightError, WorkflowPreFlightIssue, WorkflowPreFlightIssueSeverity, WorkflowPreFlightIssueType, WorkflowPreFlightResult, WorkflowRunner, WorkflowRunnerConfig } from "./runner.js";
|
|
5
5
|
import { ExpressionContext, evaluateExpression } from "./expression.js";
|
|
6
6
|
import { InMemoryStateStore } from "./adapters/memory-store.js";
|
|
7
|
-
import {
|
|
7
|
+
import { PrismaStateStore } from "./adapters/db-adapter.js";
|
|
8
8
|
import { FileStateStoreOptions, createFileStateStore } from "./adapters/file-adapter.js";
|
|
9
9
|
import "./adapters/index.js";
|
|
10
|
-
export { CompensationStep, CompensationStrategy,
|
|
10
|
+
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, evaluateExpression, validateWorkflowSpec };
|
package/dist/workflow/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{WorkflowRegistry as e}from"./spec.js";import{WorkflowValidationError as t,assertWorkflowSpecValid as n,validateWorkflowSpec as r}from"./validation.js";import{evaluateExpression as i}from"./expression.js";import{WorkflowPreFlightError as a,WorkflowRunner as o}from"./runner.js";import{InMemoryStateStore as s}from"./adapters/memory-store.js";import{
|
|
1
|
+
import{WorkflowRegistry as e}from"./spec.js";import{WorkflowValidationError as t,assertWorkflowSpecValid as n,validateWorkflowSpec as r}from"./validation.js";import{evaluateExpression as i}from"./expression.js";import{WorkflowPreFlightError as a,WorkflowRunner as o}from"./runner.js";import{InMemoryStateStore as s}from"./adapters/memory-store.js";import{PrismaStateStore as c}from"./adapters/db-adapter.js";import{createFileStateStore as l}from"./adapters/file-adapter.js";export{s as InMemoryStateStore,c as PrismaStateStore,a as WorkflowPreFlightError,e as WorkflowRegistry,o as WorkflowRunner,t as WorkflowValidationError,n as assertWorkflowSpecValid,l as createFileStateStore,i as evaluateExpression,r as validateWorkflowSpec};
|
|
@@ -55,6 +55,7 @@ declare class WorkflowRunner {
|
|
|
55
55
|
preFlightCheck(workflowName: string, version?: number, resolvedConfig?: ResolvedAppConfig): Promise<WorkflowPreFlightResult>;
|
|
56
56
|
start(workflowName: string, version?: number, initialData?: Record<string, unknown>): Promise<string>;
|
|
57
57
|
executeStep(workflowId: string, input?: unknown): Promise<void>;
|
|
58
|
+
rollback(workflowId: string): Promise<void>;
|
|
58
59
|
getState(workflowId: string): Promise<WorkflowState>;
|
|
59
60
|
cancel(workflowId: string): Promise<void>;
|
|
60
61
|
private performPreFlight;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","names":[],"sources":["../../src/workflow/runner.ts"],"sourcesContent":[],"mappings":";;;;;;;;;UAqBiB,wBAAA;YACL;EADK,IAAA,EAET,IAFS;EACL,iBAAA,CAAA,EAEU,iBAFV;EACJ,YAAA,CAAA,EAES,mBAFT,EAAA;EACc,SAAA,CAAA,EAER,iBAFQ,EAAA;EACL,QAAA,CAAA,EAEJ,gBAFI;EACH,WAAA,CAAA,EAEE,mBAFF;EACD,mBAAA,CAAA,EAEW,mBAFX;EACG,cAAA,CAAA,EAEG,cAFH;;AAEG,KAGP,iBAAA,GAHO,CAAA,EAAA,EAIb,KAJa,EAAA,KAAA,EAAA,OAAA,EAAA,OAAA,EAMR,wBANQ,EAAA,GAOd,OAPc,CAAA,OAAA,CAAA;AAAc,KASrB,0BAAA,GATqB,aAAA,GAAA,YAAA;AAGrB,KAQA,8BAAA,GARiB,OAAA,GAAA,SAAA;AACvB,UASW,sBAAA,CATX;EAEK,MAAA,EAAA,MAAA;EACN,IAAA,EAQG,0BARH;EAAO,UAAA,EAAA,MAAA;EAEA,QAAA,EAQA,8BAR0B;EAE1B,MAAA,EAAA,MAAA;AAEZ;AAQiB,UAAA,uBAAA,CAAuB;EAKvB,QAAA,EAAA,OAAY;EAMjB,MAAA,EATF,sBASgB,EAAA;;AAEf,UARM,YAAA,CAQN;EACN,QAAA,EARO,aAQP;EAAO,IAAA,EAPJ,IAOI;EAEK,KAAA,CAAA,EAAA,OAAA;;AAEH,KAPF,cAAA,GAOE,CAAA,KAAA,EANL,cAMK,EAAA,OAAA,EALH,YAKG,EAAA,GAJT,OAIS,CAAA,OAAA,CAAA,GAAA,OAAA;AACA,UAHG,oBAAA,CAGH;EACK,QAAA,EAHP,gBAGO;EACuB,UAAA,EAH5B,UAG4B;EAE/B,UAAA,EAJG,iBAIH;EACJ,cAAA,CAAA,EAJY,cAIZ;EAAwC,YAAA,CAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,OAAA,EAHL,MAGK,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;EAAR,iBAAA,CAAA,EAAA,CAAA,KAAA,EAD5B,aAC4B,EAAA,GAAhC,iBAAgC,GAAA,SAAA,GAAA,OAAA,CAAQ,iBAAR,GAAA,SAAA,CAAA;EAExB,mBAAA,CAAA,EAAA,CAAA,SAAA,EAAA,KAAA,EAAA,OAAA,EACF,wBADE,EAAA,GAAA,IAAA,GAED,OAFC,CAAA,IAAA,CAAA;EACF,cAAA,CAAA,EAEM,cAFN;EACC,mBAAA,CAAA,EAEU,mBAFV;;AAEU,cAGX,cAAA,CAHW;EAAmB,iBAAA,MAAA;EAG9B,WAAA,CAAA,MAAc,EACY,oBADZ;EACY,cAAA,CAAA,YAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,MAAA,EAAA,cAAA,CAAA,EAKlB,iBALkB,CAAA,EAMlC,OANkC,CAM1B,uBAN0B,CAAA;EAKlB,KAAA,CAAA,YAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,MAAA,EAAA,WAAA,CAAA,EASH,MATG,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAUhB,OAVgB,CAAA,MAAA,CAAA;EACR,WAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAA,OAAA,CAAA,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","names":[],"sources":["../../src/workflow/runner.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/workflow/runner.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{evaluateExpression as e}from"./expression.js";import{randomUUID as t}from"node:crypto";var n=class{constructor(e){this.config=e}async preFlightCheck(e,t,n){let r=this.getSpec(e,t);return this.performPreFlight(r,n)}async start(e,n,i){let a=this.getSpec(e,n),o=r(a),s=new Date,l=t(),u={workflowId:l,workflowName:a.meta.name,workflowVersion:a.meta.version,currentStep:o,data:{...i??{}},history:[],status:`running`,createdAt:s,updatedAt:s},d=this.config.appConfigProvider?await this.config.appConfigProvider(u):void 0,f=await this.performPreFlight(a,d);if(!f.canStart)throw new c(f.issues);return await this.config.stateStore.create(u),this.emit(`workflow.started`,{workflowId:l,workflowName:a.meta.name,workflowVersion:a.meta.version,currentStep:o}),l}async executeStep(e,t){let n=await this.getStateOrThrow(e);if(s(n.status))throw Error(`Workflow ${e} is in terminal status "${n.status}".`);let r=this.getSpec(n.workflowName,n.workflowVersion),c=i(r,n.currentStep);if(!await this.evaluateGuard(c,n,t))throw Error(`GuardRejected: ${n.workflowName} -> ${c.id}`);let l={stepId:c.id,startedAt:new Date,status:`running`,input:t},u={...n,data:{...n.data},history:[...n.history]};try{let i=await this.runStepAction(c,u,t);l.output=i,l.status=`completed`,l.completedAt=new Date,u.history.push(l),u.updatedAt=new Date,o(t)&&(u.data={...u.data,...t}),o(i)&&(u.data={...u.data,...i});let s=this.pickNextStepId(r,u,c,t,i);if(s)u.currentStep=s,u.status=`running`;else if(!a(r,c.id))u.status=`completed`;else throw Error(`No transition matched after executing step "${c.id}".`);await this.config.stateStore.update(e,()=>u),this.emit(`workflow.step_completed`,{workflowId:e,workflowName:n.workflowName,stepId:c.id,status:u.status})}catch(
|
|
1
|
+
import{evaluateExpression as e}from"./expression.js";import{randomUUID as t}from"node:crypto";var n=class{constructor(e){this.config=e}async preFlightCheck(e,t,n){let r=this.getSpec(e,t);return this.performPreFlight(r,n)}async start(e,n,i){let a=this.getSpec(e,n),o=r(a),s=new Date,l=t(),u={workflowId:l,workflowName:a.meta.name,workflowVersion:a.meta.version,currentStep:o,data:{...i??{}},retryCounts:{},history:[],status:`running`,createdAt:s,updatedAt:s},d=this.config.appConfigProvider?await this.config.appConfigProvider(u):void 0,f=await this.performPreFlight(a,d);if(!f.canStart)throw new c(f.issues);return await this.config.stateStore.create(u),this.emit(`workflow.started`,{workflowId:l,workflowName:a.meta.name,workflowVersion:a.meta.version,currentStep:o}),l}async executeStep(e,t){let n=await this.getStateOrThrow(e);if(s(n.status))throw Error(`Workflow ${e} is in terminal status "${n.status}".`);let r=this.getSpec(n.workflowName,n.workflowVersion),c=i(r,n.currentStep);if(!await this.evaluateGuard(c,n,t))throw Error(`GuardRejected: ${n.workflowName} -> ${c.id}`);let l={stepId:c.id,startedAt:new Date,status:`running`,input:t},u={...n,data:{...n.data},history:[...n.history]};try{let i=await this.runStepAction(c,u,t);l.output=i,l.status=`completed`,l.completedAt=new Date,u.history.push(l),u.updatedAt=new Date,o(t)&&(u.data={...u.data,...t}),o(i)&&(u.data={...u.data,...i});let s=this.pickNextStepId(r,u,c,t,i);if(s)u.currentStep=s,u.status=`running`;else if(!a(r,c.id))u.status=`completed`;else throw Error(`No transition matched after executing step "${c.id}".`);await this.config.stateStore.update(e,()=>u),this.emit(`workflow.step_completed`,{workflowId:e,workflowName:n.workflowName,stepId:c.id,status:u.status})}catch(i){if(l.status=`failed`,l.completedAt=new Date,l.error=i instanceof Error?i.message:String(i),u.history.push(l),u.updatedAt=new Date,c.retry){let r=n.retryCounts?.[c.id]??0;if(r<c.retry.maxAttempts){let i=c.retry.backoff??`exponential`,a=c.retry.delayMs??1e3,o=i===`exponential`?a*2**r:a,s=Math.min(o,c.retry.maxDelayMs??1/0);return u.retryCounts={...n.retryCounts??{},[c.id]:r+1},u.status=`running`,await this.config.stateStore.update(e,()=>u),this.emit(`workflow.step_retrying`,{workflowId:e,workflowName:n.workflowName,stepId:c.id,attempt:r+1,delay:s,error:l.error}),await new Promise(e=>setTimeout(e,s)),this.executeStep(e,t)}}throw u.status=`failed`,await this.config.stateStore.update(e,()=>u),this.emit(`workflow.step_failed`,{workflowId:e,workflowName:n.workflowName,stepId:c.id,error:l.error??`unknown`}),r.definition.compensation?.trigger===`on_failure`&&await this.rollback(e),i}}async rollback(e){let t=await this.getStateOrThrow(e),n=this.getSpec(t.workflowName,t.workflowVersion);if(!n.definition.compensation)return;this.emit(`workflow.rollback_started`,{workflowId:e});let r=t.history.filter(e=>e.status===`completed`).reverse();for(let a of r){let r=n.definition.compensation.steps.find(e=>e.stepId===a.stepId);if(r){let o={stepId:a.stepId,originalInput:a.input,originalOutput:a.output,workflowData:t.data};try{let s=i(n,a.stepId),c=this.config.appConfigProvider?await this.config.appConfigProvider(t):void 0,l={workflow:t,step:s,resolvedAppConfig:c,integrations:c?.integrations??[],knowledge:c?.knowledge??[],branding:c?.branding,translation:c?.translation,translationResolver:this.config.translationResolver,secretProvider:this.config.secretProvider};await this.config.opExecutor(r.operation,o,l),this.emit(`workflow.compensation_step_completed`,{workflowId:e,stepId:a.stepId,compensationOp:r.operation.name})}catch(t){let n=t instanceof Error?t.message:String(t);this.emit(`workflow.compensation_step_failed`,{workflowId:e,stepId:a.stepId,compensationOp:r.operation.name,error:n})}}}this.emit(`workflow.rollback_completed`,{workflowId:e})}async getState(e){return this.getStateOrThrow(e)}async cancel(e){let t=await this.getStateOrThrow(e);if(t.status===`cancelled`)return;let n={...t,status:`cancelled`,updatedAt:new Date};await this.config.stateStore.update(e,()=>n),this.emit(`workflow.cancelled`,{workflowId:e,workflowName:t.workflowName})}async performPreFlight(e,t){if(!t)return{canStart:!0,issues:[]};let n=[],r=new Map;for(let e of t.integrations)r.set(e.slot.slotId,e);for(let t of e.definition.steps)for(let e of t.requiredIntegrations??[]){let i=r.get(e);if(!i){n.push({stepId:t.id,type:`integration`,identifier:e,severity:`error`,reason:`Integration slot "${e}" is not bound in the resolved app config.`});continue}let a=i.connection.status;a===`disconnected`||a===`error`?n.push({stepId:t.id,type:`integration`,identifier:e,severity:`error`,reason:`Integration slot "${e}" is in status "${a}".`}):a===`unknown`&&n.push({stepId:t.id,type:`integration`,identifier:e,severity:`warning`,reason:`Integration slot "${e}" reports unknown health status.`})}let i=new Set(t.capabilities.enabled.map(l));for(let t of e.definition.steps)for(let e of t.requiredCapabilities??[])i.has(l(e))||n.push({stepId:t.id,type:`capability`,identifier:l(e),severity:`error`,reason:`Capability "${e.key}@${e.version}" is not enabled.`});return{canStart:n.every(e=>e.severity!==`error`),issues:n}}async evaluateGuard(t,n,r){return t.guard?this.config.guardEvaluator?this.config.guardEvaluator(t.guard,{workflow:n,step:t,input:r}):t.guard.type===`expression`?e(t.guard.value,{data:n.data,input:r}):!0:!0}async runStepAction(e,t,n){if(e.type===`automation`){let r=e.action?.operation;if(!r)throw Error(`Automation step "${e.id}" requires an operation.`);let i=this.config.appConfigProvider?await this.config.appConfigProvider(t):void 0,a={workflow:t,step:e,resolvedAppConfig:i,integrations:i?.integrations??[],knowledge:i?.knowledge??[],branding:i?.branding,translation:i?.translation,translationResolver:this.config.translationResolver,secretProvider:this.config.secretProvider};return this.config.enforceCapabilities&&await this.config.enforceCapabilities(r,a),this.config.opExecutor(r,n,a)}return e.type,n}pickNextStepId(t,n,r,i,a){let o=t.definition.transitions.filter(e=>e.from===r.id);for(let r of o)if(e(r.condition,{data:n.data,input:i,output:a})){let e=t.definition.steps.find(e=>e.id===r.to);if(!e)throw Error(`Transition ${r.from} -> ${r.to} points to missing step.`);return e.id}return null}getSpec(e,t){let n=this.config.registry.get(e,t);if(!n)throw Error(`Workflow spec not found for ${e}${t?`.v${t}`:``}`);return n}async getStateOrThrow(e){let t=await this.config.stateStore.get(e);if(!t)throw Error(`Workflow state not found for ${e}`);return t}emit(e,t){this.config.eventEmitter?.(e,t)}};function r(e){let t=e.definition.entryStepId??e.definition.steps[0]?.id??null;if(!t)throw Error(`Workflow ${e.meta.name}.v${e.meta.version} has no entry step.`);return t}function i(e,t){let n=e.definition.steps.find(e=>e.id===t);if(!n)throw Error(`Step "${t}" not found in workflow ${e.meta.name}.v${e.meta.version}.`);return n}function a(e,t){return e.definition.transitions.some(e=>e.from===t)}function o(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function s(e){return e===`completed`||e===`failed`||e===`cancelled`}var c=class extends Error{constructor(e){super(`Workflow pre-flight failed: ${e.filter(e=>e.severity===`error`).map(e=>`${e.type}:${e.identifier}`).join(`, `)}`),this.issues=e,this.name=`WorkflowPreFlightError`}};function l(e){return`${e.key}@${e.version}`}export{c as WorkflowPreFlightError,n as WorkflowRunner};
|
|
2
2
|
//# sourceMappingURL=runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","names":["config: WorkflowRunnerConfig","state: WorkflowState","execution: StepExecution","workingState: WorkflowState","nextState: WorkflowState","issues: WorkflowPreFlightIssue[]","executorContext: OperationExecutorContext"],"sources":["../../src/workflow/runner.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type {\n GuardCondition,\n Step,\n WorkflowRegistry,\n WorkflowSpec,\n} from './spec';\nimport type { StateStore, WorkflowState, StepExecution } from './state';\nimport { evaluateExpression } from './expression';\nimport type { OpRef } from '../features';\nimport type { CapabilityRef } from '../capabilities';\nimport type {\n ResolvedAppConfig,\n ResolvedIntegration,\n ResolvedKnowledge,\n ResolvedTranslation,\n} from '../app-config/runtime';\nimport type { ResolvedBranding } from '../app-config/branding';\nimport type { TranslationResolver } from '../types';\nimport type { SecretProvider } from '../integrations/secrets/provider';\n\nexport interface OperationExecutorContext {\n workflow: WorkflowState;\n step: Step;\n resolvedAppConfig?: ResolvedAppConfig;\n integrations?: ResolvedIntegration[];\n knowledge?: ResolvedKnowledge[];\n branding?: ResolvedBranding;\n translation?: ResolvedTranslation;\n translationResolver?: TranslationResolver;\n secretProvider?: SecretProvider;\n}\n\nexport type OperationExecutor = (\n op: OpRef,\n input: unknown,\n context: OperationExecutorContext\n) => Promise<unknown>;\n\nexport type WorkflowPreFlightIssueType = 'integration' | 'capability';\n\nexport type WorkflowPreFlightIssueSeverity = 'error' | 'warning';\n\nexport interface WorkflowPreFlightIssue {\n stepId: string;\n type: WorkflowPreFlightIssueType;\n identifier: string;\n severity: WorkflowPreFlightIssueSeverity;\n reason: string;\n}\n\nexport interface WorkflowPreFlightResult {\n canStart: boolean;\n issues: WorkflowPreFlightIssue[];\n}\n\nexport interface GuardContext {\n workflow: WorkflowState;\n step: Step;\n input?: unknown;\n}\n\nexport type GuardEvaluator = (\n guard: GuardCondition,\n context: GuardContext\n) => Promise<boolean> | boolean;\n\nexport interface WorkflowRunnerConfig {\n registry: WorkflowRegistry;\n stateStore: StateStore;\n opExecutor: OperationExecutor;\n guardEvaluator?: GuardEvaluator;\n eventEmitter?: (event: string, payload: Record<string, unknown>) => void;\n appConfigProvider?: (\n state: WorkflowState\n ) => ResolvedAppConfig | undefined | Promise<ResolvedAppConfig | undefined>;\n enforceCapabilities?: (\n operation: OpRef,\n context: OperationExecutorContext\n ) => void | Promise<void>;\n secretProvider?: SecretProvider;\n translationResolver?: TranslationResolver;\n}\n\nexport class WorkflowRunner {\n constructor(private readonly config: WorkflowRunnerConfig) {}\n\n async preFlightCheck(\n workflowName: string,\n version?: number,\n resolvedConfig?: ResolvedAppConfig\n ): Promise<WorkflowPreFlightResult> {\n const spec = this.getSpec(workflowName, version);\n return this.performPreFlight(spec, resolvedConfig);\n }\n\n async start(\n workflowName: string,\n version?: number,\n initialData?: Record<string, unknown>\n ): Promise<string> {\n const spec = this.getSpec(workflowName, version);\n const entryStepId = resolveEntryStepId(spec);\n const now = new Date();\n const workflowId = randomUUID();\n\n const state: WorkflowState = {\n workflowId,\n workflowName: spec.meta.name,\n workflowVersion: spec.meta.version,\n currentStep: entryStepId,\n data: { ...(initialData ?? {}) },\n history: [],\n status: 'running',\n createdAt: now,\n updatedAt: now,\n };\n\n const resolvedAppConfig = this.config.appConfigProvider\n ? await this.config.appConfigProvider(state)\n : undefined;\n\n const preFlightResult = await this.performPreFlight(\n spec,\n resolvedAppConfig\n );\n if (!preFlightResult.canStart) {\n throw new WorkflowPreFlightError(preFlightResult.issues);\n }\n\n await this.config.stateStore.create(state);\n this.emit('workflow.started', {\n workflowId,\n workflowName: spec.meta.name,\n workflowVersion: spec.meta.version,\n currentStep: entryStepId,\n });\n return workflowId;\n }\n\n async executeStep(workflowId: string, input?: unknown): Promise<void> {\n const state = await this.getStateOrThrow(workflowId);\n if (isTerminalStatus(state.status)) {\n throw new Error(\n `Workflow ${workflowId} is in terminal status \"${state.status}\".`\n );\n }\n\n const spec = this.getSpec(state.workflowName, state.workflowVersion);\n const step = getCurrentStep(spec, state.currentStep);\n const guardOk = await this.evaluateGuard(step, state, input);\n if (!guardOk)\n throw new Error(`GuardRejected: ${state.workflowName} -> ${step.id}`);\n\n const execution: StepExecution = {\n stepId: step.id,\n startedAt: new Date(),\n status: 'running',\n input,\n };\n\n const workingState: WorkflowState = {\n ...state,\n data: { ...state.data },\n history: [...state.history],\n };\n\n try {\n const output = await this.runStepAction(step, workingState, input);\n execution.output = output;\n execution.status = 'completed';\n execution.completedAt = new Date();\n workingState.history.push(execution);\n workingState.updatedAt = new Date();\n\n if (isRecord(input)) {\n workingState.data = { ...workingState.data, ...input };\n }\n if (isRecord(output)) {\n workingState.data = { ...workingState.data, ...output };\n }\n\n const nextStepId = this.pickNextStepId(\n spec,\n workingState,\n step,\n input,\n output\n );\n\n if (nextStepId) {\n workingState.currentStep = nextStepId;\n workingState.status = 'running';\n } else if (!hasOutgoing(spec, step.id)) {\n workingState.status = 'completed';\n } else {\n throw new Error(\n `No transition matched after executing step \"${step.id}\".`\n );\n }\n\n await this.config.stateStore.update(workflowId, () => workingState);\n this.emit('workflow.step_completed', {\n workflowId,\n workflowName: state.workflowName,\n stepId: step.id,\n status: workingState.status,\n });\n } catch (error) {\n execution.status = 'failed';\n execution.completedAt = new Date();\n execution.error =\n error instanceof Error ? error.message : String(error);\n workingState.history.push(execution);\n workingState.status = 'failed';\n workingState.updatedAt = new Date();\n await this.config.stateStore.update(workflowId, () => workingState);\n this.emit('workflow.step_failed', {\n workflowId,\n workflowName: state.workflowName,\n stepId: step.id,\n error: execution.error ?? 'unknown',\n });\n throw error;\n }\n }\n\n async getState(workflowId: string): Promise<WorkflowState> {\n return this.getStateOrThrow(workflowId);\n }\n\n async cancel(workflowId: string): Promise<void> {\n const state = await this.getStateOrThrow(workflowId);\n if (state.status === 'cancelled') return;\n\n const nextState: WorkflowState = {\n ...state,\n status: 'cancelled',\n updatedAt: new Date(),\n };\n await this.config.stateStore.update(workflowId, () => nextState);\n this.emit('workflow.cancelled', {\n workflowId,\n workflowName: state.workflowName,\n });\n }\n\n private async performPreFlight(\n spec: WorkflowSpec,\n resolvedConfig?: ResolvedAppConfig\n ): Promise<WorkflowPreFlightResult> {\n if (!resolvedConfig) {\n return { canStart: true, issues: [] };\n }\n\n const issues: WorkflowPreFlightIssue[] = [];\n const integrationBySlot = new Map<string, ResolvedIntegration>();\n for (const integration of resolvedConfig.integrations) {\n integrationBySlot.set(integration.slot.slotId, integration);\n }\n\n for (const step of spec.definition.steps) {\n for (const slotId of step.requiredIntegrations ?? []) {\n const integration = integrationBySlot.get(slotId);\n if (!integration) {\n issues.push({\n stepId: step.id,\n type: 'integration',\n identifier: slotId,\n severity: 'error',\n reason: `Integration slot \"${slotId}\" is not bound in the resolved app config.`,\n });\n continue;\n }\n const status = integration.connection.status;\n if (status === 'disconnected' || status === 'error') {\n issues.push({\n stepId: step.id,\n type: 'integration',\n identifier: slotId,\n severity: 'error',\n reason: `Integration slot \"${slotId}\" is in status \"${status}\".`,\n });\n } else if (status === 'unknown') {\n issues.push({\n stepId: step.id,\n type: 'integration',\n identifier: slotId,\n severity: 'warning',\n reason: `Integration slot \"${slotId}\" reports unknown health status.`,\n });\n }\n }\n }\n\n const enabledCapabilities = new Set(\n resolvedConfig.capabilities.enabled.map(capabilityKey)\n );\n for (const step of spec.definition.steps) {\n for (const required of step.requiredCapabilities ?? []) {\n if (!enabledCapabilities.has(capabilityKey(required))) {\n issues.push({\n stepId: step.id,\n type: 'capability',\n identifier: capabilityKey(required),\n severity: 'error',\n reason: `Capability \"${required.key}@${required.version}\" is not enabled.`,\n });\n }\n }\n }\n\n const canStart = issues.every((issue) => issue.severity !== 'error');\n return { canStart, issues };\n }\n\n private async evaluateGuard(\n step: Step,\n state: WorkflowState,\n input: unknown\n ) {\n if (!step.guard) return true;\n if (this.config.guardEvaluator)\n return this.config.guardEvaluator(step.guard, {\n workflow: state,\n step,\n input,\n });\n if (step.guard.type === 'expression') {\n return evaluateExpression(step.guard.value, {\n data: state.data,\n input,\n });\n }\n return true;\n }\n\n private async runStepAction(\n step: Step,\n state: WorkflowState,\n input: unknown\n ): Promise<unknown> {\n if (step.type === 'automation') {\n const op = step.action?.operation;\n if (!op)\n throw new Error(`Automation step \"${step.id}\" requires an operation.`);\n const resolvedAppConfig = this.config.appConfigProvider\n ? await this.config.appConfigProvider(state)\n : undefined;\n const executorContext: OperationExecutorContext = {\n workflow: state,\n step,\n resolvedAppConfig,\n integrations: resolvedAppConfig?.integrations ?? [],\n knowledge: resolvedAppConfig?.knowledge ?? [],\n branding: resolvedAppConfig?.branding,\n translation: resolvedAppConfig?.translation,\n translationResolver: this.config.translationResolver,\n secretProvider: this.config.secretProvider,\n };\n if (this.config.enforceCapabilities) {\n await this.config.enforceCapabilities(op, executorContext);\n }\n return this.config.opExecutor(op, input, executorContext);\n }\n\n if (step.type === 'human') {\n return input;\n }\n\n // decision step\n return input;\n }\n\n private pickNextStepId(\n spec: WorkflowSpec,\n state: WorkflowState,\n step: Step,\n input: unknown,\n output: unknown\n ): string | null {\n const transitions = spec.definition.transitions.filter(\n (t) => t.from === step.id\n );\n for (const transition of transitions) {\n if (\n evaluateExpression(transition.condition, {\n data: state.data,\n input,\n output,\n })\n ) {\n const target = spec.definition.steps.find((s) => s.id === transition.to);\n if (!target)\n throw new Error(\n `Transition ${transition.from} -> ${transition.to} points to missing step.`\n );\n return target.id;\n }\n }\n return null;\n }\n\n private getSpec(name: string, version?: number): WorkflowSpec {\n const spec = this.config.registry.get(name, version);\n if (!spec)\n throw new Error(\n `Workflow spec not found for ${name}${version ? `.v${version}` : ''}`\n );\n return spec;\n }\n\n private async getStateOrThrow(workflowId: string): Promise<WorkflowState> {\n const state = await this.config.stateStore.get(workflowId);\n if (!state) throw new Error(`Workflow state not found for ${workflowId}`);\n return state;\n }\n\n private emit(event: string, payload: Record<string, unknown>) {\n this.config.eventEmitter?.(event, payload);\n }\n}\n\nfunction resolveEntryStepId(spec: WorkflowSpec): string {\n const entry =\n spec.definition.entryStepId ?? spec.definition.steps[0]?.id ?? null;\n if (!entry)\n throw new Error(\n `Workflow ${spec.meta.name}.v${spec.meta.version} has no entry step.`\n );\n return entry;\n}\n\nfunction getCurrentStep(spec: WorkflowSpec, stepId: string): Step {\n const step = spec.definition.steps.find((s) => s.id === stepId);\n if (!step)\n throw new Error(\n `Step \"${stepId}\" not found in workflow ${spec.meta.name}.v${spec.meta.version}.`\n );\n return step;\n}\n\nfunction hasOutgoing(spec: WorkflowSpec, stepId: string): boolean {\n return spec.definition.transitions.some((t) => t.from === stepId);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return (\n value != null &&\n typeof value === 'object' &&\n !Array.isArray(value)\n );\n}\n\nfunction isTerminalStatus(status: WorkflowState['status']) {\n return status === 'completed' || status === 'failed' || status === 'cancelled';\n}\n\nexport class WorkflowPreFlightError extends Error {\n constructor(public readonly issues: WorkflowPreFlightIssue[]) {\n super(\n `Workflow pre-flight failed: ${issues\n .filter((issue) => issue.severity === 'error')\n .map((issue) => `${issue.type}:${issue.identifier}`)\n .join(', ')}`\n );\n this.name = 'WorkflowPreFlightError';\n }\n}\n\nfunction capabilityKey(ref: CapabilityRef): string {\n return `${ref.key}@${ref.version}`;\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runner.js","names":["config: WorkflowRunnerConfig","state: WorkflowState","execution: StepExecution","workingState: WorkflowState","executorContext: OperationExecutorContext","nextState: WorkflowState","issues: WorkflowPreFlightIssue[]"],"sources":["../../src/workflow/runner.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type {\n GuardCondition,\n Step,\n WorkflowRegistry,\n WorkflowSpec,\n} from './spec';\nimport type { StateStore, WorkflowState, StepExecution } from './state';\nimport { evaluateExpression } from './expression';\nimport type { OpRef } from '../features';\nimport type { CapabilityRef } from '../capabilities';\nimport type {\n ResolvedAppConfig,\n ResolvedIntegration,\n ResolvedKnowledge,\n ResolvedTranslation,\n} from '../app-config/runtime';\nimport type { ResolvedBranding } from '../app-config/branding';\nimport type { TranslationResolver } from '../types';\nimport type { SecretProvider } from '../integrations/secrets/provider';\n\nexport interface OperationExecutorContext {\n workflow: WorkflowState;\n step: Step;\n resolvedAppConfig?: ResolvedAppConfig;\n integrations?: ResolvedIntegration[];\n knowledge?: ResolvedKnowledge[];\n branding?: ResolvedBranding;\n translation?: ResolvedTranslation;\n translationResolver?: TranslationResolver;\n secretProvider?: SecretProvider;\n}\n\nexport type OperationExecutor = (\n op: OpRef,\n input: unknown,\n context: OperationExecutorContext\n) => Promise<unknown>;\n\nexport type WorkflowPreFlightIssueType = 'integration' | 'capability';\n\nexport type WorkflowPreFlightIssueSeverity = 'error' | 'warning';\n\nexport interface WorkflowPreFlightIssue {\n stepId: string;\n type: WorkflowPreFlightIssueType;\n identifier: string;\n severity: WorkflowPreFlightIssueSeverity;\n reason: string;\n}\n\nexport interface WorkflowPreFlightResult {\n canStart: boolean;\n issues: WorkflowPreFlightIssue[];\n}\n\nexport interface GuardContext {\n workflow: WorkflowState;\n step: Step;\n input?: unknown;\n}\n\nexport type GuardEvaluator = (\n guard: GuardCondition,\n context: GuardContext\n) => Promise<boolean> | boolean;\n\nexport interface WorkflowRunnerConfig {\n registry: WorkflowRegistry;\n stateStore: StateStore;\n opExecutor: OperationExecutor;\n guardEvaluator?: GuardEvaluator;\n eventEmitter?: (event: string, payload: Record<string, unknown>) => void;\n appConfigProvider?: (\n state: WorkflowState\n ) => ResolvedAppConfig | undefined | Promise<ResolvedAppConfig | undefined>;\n enforceCapabilities?: (\n operation: OpRef,\n context: OperationExecutorContext\n ) => void | Promise<void>;\n secretProvider?: SecretProvider;\n translationResolver?: TranslationResolver;\n}\n\nexport class WorkflowRunner {\n constructor(private readonly config: WorkflowRunnerConfig) {}\n\n async preFlightCheck(\n workflowName: string,\n version?: number,\n resolvedConfig?: ResolvedAppConfig\n ): Promise<WorkflowPreFlightResult> {\n const spec = this.getSpec(workflowName, version);\n return this.performPreFlight(spec, resolvedConfig);\n }\n\n async start(\n workflowName: string,\n version?: number,\n initialData?: Record<string, unknown>\n ): Promise<string> {\n const spec = this.getSpec(workflowName, version);\n const entryStepId = resolveEntryStepId(spec);\n const now = new Date();\n const workflowId = randomUUID();\n\n const state: WorkflowState = {\n workflowId,\n workflowName: spec.meta.name,\n workflowVersion: spec.meta.version,\n currentStep: entryStepId,\n data: { ...(initialData ?? {}) },\n retryCounts: {},\n history: [],\n status: 'running',\n createdAt: now,\n updatedAt: now,\n };\n\n const resolvedAppConfig = this.config.appConfigProvider\n ? await this.config.appConfigProvider(state)\n : undefined;\n\n const preFlightResult = await this.performPreFlight(\n spec,\n resolvedAppConfig\n );\n if (!preFlightResult.canStart) {\n throw new WorkflowPreFlightError(preFlightResult.issues);\n }\n\n await this.config.stateStore.create(state);\n this.emit('workflow.started', {\n workflowId,\n workflowName: spec.meta.name,\n workflowVersion: spec.meta.version,\n currentStep: entryStepId,\n });\n return workflowId;\n }\n\n async executeStep(workflowId: string, input?: unknown): Promise<void> {\n const state = await this.getStateOrThrow(workflowId);\n if (isTerminalStatus(state.status)) {\n throw new Error(\n `Workflow ${workflowId} is in terminal status \"${state.status}\".`\n );\n }\n\n const spec = this.getSpec(state.workflowName, state.workflowVersion);\n const step = getCurrentStep(spec, state.currentStep);\n const guardOk = await this.evaluateGuard(step, state, input);\n if (!guardOk)\n throw new Error(`GuardRejected: ${state.workflowName} -> ${step.id}`);\n\n const execution: StepExecution = {\n stepId: step.id,\n startedAt: new Date(),\n status: 'running',\n input,\n };\n\n const workingState: WorkflowState = {\n ...state,\n data: { ...state.data },\n history: [...state.history],\n };\n\n try {\n const output = await this.runStepAction(step, workingState, input);\n execution.output = output;\n execution.status = 'completed';\n execution.completedAt = new Date();\n workingState.history.push(execution);\n workingState.updatedAt = new Date();\n\n if (isRecord(input)) {\n workingState.data = { ...workingState.data, ...input };\n }\n if (isRecord(output)) {\n workingState.data = { ...workingState.data, ...output };\n }\n\n const nextStepId = this.pickNextStepId(\n spec,\n workingState,\n step,\n input,\n output\n );\n\n if (nextStepId) {\n workingState.currentStep = nextStepId;\n workingState.status = 'running';\n } else if (!hasOutgoing(spec, step.id)) {\n workingState.status = 'completed';\n } else {\n throw new Error(\n `No transition matched after executing step \"${step.id}\".`\n );\n }\n\n await this.config.stateStore.update(workflowId, () => workingState);\n this.emit('workflow.step_completed', {\n workflowId,\n workflowName: state.workflowName,\n stepId: step.id,\n status: workingState.status,\n });\n } catch (error) {\n execution.status = 'failed';\n execution.completedAt = new Date();\n execution.error = error instanceof Error ? error.message : String(error);\n workingState.history.push(execution);\n workingState.updatedAt = new Date();\n\n if (step.retry) {\n const retries = state.retryCounts?.[step.id] ?? 0;\n if (retries < step.retry.maxAttempts) {\n const backoff = step.retry.backoff ?? 'exponential';\n const baseDelay = step.retry.delayMs ?? 1000;\n const delay =\n backoff === 'exponential'\n ? baseDelay * Math.pow(2, retries)\n : baseDelay;\n const cappedDelay = Math.min(\n delay,\n step.retry.maxDelayMs ?? Infinity\n );\n\n workingState.retryCounts = {\n ...(state.retryCounts ?? {}),\n [step.id]: retries + 1,\n };\n workingState.status = 'running';\n\n await this.config.stateStore.update(workflowId, () => workingState);\n this.emit('workflow.step_retrying', {\n workflowId,\n workflowName: state.workflowName,\n stepId: step.id,\n attempt: retries + 1,\n delay: cappedDelay,\n error: execution.error,\n });\n\n await new Promise((resolve) => setTimeout(resolve, cappedDelay));\n return this.executeStep(workflowId, input);\n }\n }\n\n workingState.status = 'failed';\n await this.config.stateStore.update(workflowId, () => workingState);\n this.emit('workflow.step_failed', {\n workflowId,\n workflowName: state.workflowName,\n stepId: step.id,\n error: execution.error ?? 'unknown',\n });\n\n // Trigger compensation if configured\n if (spec.definition.compensation?.trigger === 'on_failure') {\n await this.rollback(workflowId);\n }\n\n throw error;\n }\n }\n\n async rollback(workflowId: string): Promise<void> {\n const state = await this.getStateOrThrow(workflowId);\n const spec = this.getSpec(state.workflowName, state.workflowVersion);\n\n if (!spec.definition.compensation) {\n return;\n }\n\n this.emit('workflow.rollback_started', { workflowId });\n\n // Filter history for completed automation steps in reverse order\n const completedSteps = state.history\n .filter((h) => h.status === 'completed')\n .reverse();\n\n for (const execution of completedSteps) {\n const compStep = spec.definition.compensation.steps.find(\n (s) => s.stepId === execution.stepId\n );\n if (compStep) {\n const input = {\n stepId: execution.stepId,\n originalInput: execution.input,\n originalOutput: execution.output,\n workflowData: state.data,\n };\n\n try {\n // Create a context for the compensation step\n // We use the same state as it provides access to data/history\n const step = getCurrentStep(spec, execution.stepId);\n const resolvedAppConfig = this.config.appConfigProvider\n ? await this.config.appConfigProvider(state)\n : undefined;\n\n const executorContext: OperationExecutorContext = {\n workflow: state,\n step,\n resolvedAppConfig,\n integrations: resolvedAppConfig?.integrations ?? [],\n knowledge: resolvedAppConfig?.knowledge ?? [],\n branding: resolvedAppConfig?.branding,\n translation: resolvedAppConfig?.translation,\n translationResolver: this.config.translationResolver,\n secretProvider: this.config.secretProvider,\n };\n\n await this.config.opExecutor(\n compStep.operation,\n input,\n executorContext\n );\n\n this.emit('workflow.compensation_step_completed', {\n workflowId,\n stepId: execution.stepId,\n compensationOp: compStep.operation.name,\n });\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n this.emit('workflow.compensation_step_failed', {\n workflowId,\n stepId: execution.stepId,\n compensationOp: compStep.operation.name,\n error: errorMessage,\n });\n // We continue with other compensations even if one fails (best effort)\n }\n }\n }\n\n // We don't change status from 'failed' or 'cancelled' usually,\n // but we might want to mark that rollback was attempted/completed.\n // For now, just emitting events is enough.\n this.emit('workflow.rollback_completed', { workflowId });\n }\n\n async getState(workflowId: string): Promise<WorkflowState> {\n return this.getStateOrThrow(workflowId);\n }\n\n async cancel(workflowId: string): Promise<void> {\n const state = await this.getStateOrThrow(workflowId);\n if (state.status === 'cancelled') return;\n\n const nextState: WorkflowState = {\n ...state,\n status: 'cancelled',\n updatedAt: new Date(),\n };\n await this.config.stateStore.update(workflowId, () => nextState);\n this.emit('workflow.cancelled', {\n workflowId,\n workflowName: state.workflowName,\n });\n }\n\n private async performPreFlight(\n spec: WorkflowSpec,\n resolvedConfig?: ResolvedAppConfig\n ): Promise<WorkflowPreFlightResult> {\n if (!resolvedConfig) {\n return { canStart: true, issues: [] };\n }\n\n const issues: WorkflowPreFlightIssue[] = [];\n const integrationBySlot = new Map<string, ResolvedIntegration>();\n for (const integration of resolvedConfig.integrations) {\n integrationBySlot.set(integration.slot.slotId, integration);\n }\n\n for (const step of spec.definition.steps) {\n for (const slotId of step.requiredIntegrations ?? []) {\n const integration = integrationBySlot.get(slotId);\n if (!integration) {\n issues.push({\n stepId: step.id,\n type: 'integration',\n identifier: slotId,\n severity: 'error',\n reason: `Integration slot \"${slotId}\" is not bound in the resolved app config.`,\n });\n continue;\n }\n const status = integration.connection.status;\n if (status === 'disconnected' || status === 'error') {\n issues.push({\n stepId: step.id,\n type: 'integration',\n identifier: slotId,\n severity: 'error',\n reason: `Integration slot \"${slotId}\" is in status \"${status}\".`,\n });\n } else if (status === 'unknown') {\n issues.push({\n stepId: step.id,\n type: 'integration',\n identifier: slotId,\n severity: 'warning',\n reason: `Integration slot \"${slotId}\" reports unknown health status.`,\n });\n }\n }\n }\n\n const enabledCapabilities = new Set(\n resolvedConfig.capabilities.enabled.map(capabilityKey)\n );\n for (const step of spec.definition.steps) {\n for (const required of step.requiredCapabilities ?? []) {\n if (!enabledCapabilities.has(capabilityKey(required))) {\n issues.push({\n stepId: step.id,\n type: 'capability',\n identifier: capabilityKey(required),\n severity: 'error',\n reason: `Capability \"${required.key}@${required.version}\" is not enabled.`,\n });\n }\n }\n }\n\n const canStart = issues.every((issue) => issue.severity !== 'error');\n return { canStart, issues };\n }\n\n private async evaluateGuard(\n step: Step,\n state: WorkflowState,\n input: unknown\n ) {\n if (!step.guard) return true;\n if (this.config.guardEvaluator)\n return this.config.guardEvaluator(step.guard, {\n workflow: state,\n step,\n input,\n });\n if (step.guard.type === 'expression') {\n return evaluateExpression(step.guard.value, {\n data: state.data,\n input,\n });\n }\n return true;\n }\n\n private async runStepAction(\n step: Step,\n state: WorkflowState,\n input: unknown\n ): Promise<unknown> {\n if (step.type === 'automation') {\n const op = step.action?.operation;\n if (!op)\n throw new Error(`Automation step \"${step.id}\" requires an operation.`);\n const resolvedAppConfig = this.config.appConfigProvider\n ? await this.config.appConfigProvider(state)\n : undefined;\n const executorContext: OperationExecutorContext = {\n workflow: state,\n step,\n resolvedAppConfig,\n integrations: resolvedAppConfig?.integrations ?? [],\n knowledge: resolvedAppConfig?.knowledge ?? [],\n branding: resolvedAppConfig?.branding,\n translation: resolvedAppConfig?.translation,\n translationResolver: this.config.translationResolver,\n secretProvider: this.config.secretProvider,\n };\n if (this.config.enforceCapabilities) {\n await this.config.enforceCapabilities(op, executorContext);\n }\n return this.config.opExecutor(op, input, executorContext);\n }\n\n if (step.type === 'human') {\n return input;\n }\n\n // decision step\n return input;\n }\n\n private pickNextStepId(\n spec: WorkflowSpec,\n state: WorkflowState,\n step: Step,\n input: unknown,\n output: unknown\n ): string | null {\n const transitions = spec.definition.transitions.filter(\n (t) => t.from === step.id\n );\n for (const transition of transitions) {\n if (\n evaluateExpression(transition.condition, {\n data: state.data,\n input,\n output,\n })\n ) {\n const target = spec.definition.steps.find(\n (s) => s.id === transition.to\n );\n if (!target)\n throw new Error(\n `Transition ${transition.from} -> ${transition.to} points to missing step.`\n );\n return target.id;\n }\n }\n return null;\n }\n\n private getSpec(name: string, version?: number): WorkflowSpec {\n const spec = this.config.registry.get(name, version);\n if (!spec)\n throw new Error(\n `Workflow spec not found for ${name}${version ? `.v${version}` : ''}`\n );\n return spec;\n }\n\n private async getStateOrThrow(workflowId: string): Promise<WorkflowState> {\n const state = await this.config.stateStore.get(workflowId);\n if (!state) throw new Error(`Workflow state not found for ${workflowId}`);\n return state;\n }\n\n private emit(event: string, payload: Record<string, unknown>) {\n this.config.eventEmitter?.(event, payload);\n }\n}\n\nfunction resolveEntryStepId(spec: WorkflowSpec): string {\n const entry =\n spec.definition.entryStepId ?? spec.definition.steps[0]?.id ?? null;\n if (!entry)\n throw new Error(\n `Workflow ${spec.meta.name}.v${spec.meta.version} has no entry step.`\n );\n return entry;\n}\n\nfunction getCurrentStep(spec: WorkflowSpec, stepId: string): Step {\n const step = spec.definition.steps.find((s) => s.id === stepId);\n if (!step)\n throw new Error(\n `Step \"${stepId}\" not found in workflow ${spec.meta.name}.v${spec.meta.version}.`\n );\n return step;\n}\n\nfunction hasOutgoing(spec: WorkflowSpec, stepId: string): boolean {\n return spec.definition.transitions.some((t) => t.from === stepId);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isTerminalStatus(status: WorkflowState['status']) {\n return (\n status === 'completed' || status === 'failed' || status === 'cancelled'\n );\n}\n\nexport class WorkflowPreFlightError extends Error {\n constructor(public readonly issues: WorkflowPreFlightIssue[]) {\n super(\n `Workflow pre-flight failed: ${issues\n .filter((issue) => issue.severity === 'error')\n .map((issue) => `${issue.type}:${issue.identifier}`)\n .join(', ')}`\n );\n this.name = 'WorkflowPreFlightError';\n }\n}\n\nfunction capabilityKey(ref: CapabilityRef): string {\n return `${ref.key}@${ref.version}`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WorkflowSpec } from "./spec.js";
|
|
2
|
+
import { WorkflowState } from "./state.js";
|
|
3
|
+
|
|
4
|
+
//#region src/workflow/sla-monitor.d.ts
|
|
5
|
+
interface SLABreachEvent {
|
|
6
|
+
workflowId: string;
|
|
7
|
+
workflowName: string;
|
|
8
|
+
type: 'workflow_duration' | 'step_duration';
|
|
9
|
+
stepId?: string;
|
|
10
|
+
expectedMs: number;
|
|
11
|
+
actualMs: number;
|
|
12
|
+
breachedAt: Date;
|
|
13
|
+
}
|
|
14
|
+
declare class SLAMonitor {
|
|
15
|
+
private readonly eventEmitter;
|
|
16
|
+
constructor(eventEmitter: (event: string, payload: SLABreachEvent) => void);
|
|
17
|
+
check(state: WorkflowState, spec: WorkflowSpec): void;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { SLABreachEvent, SLAMonitor };
|
|
21
|
+
//# sourceMappingURL=sla-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sla-monitor.d.ts","names":[],"sources":["../../src/workflow/sla-monitor.ts"],"sourcesContent":[],"mappings":";;;;UAGiB,cAAA;;EAAA,YAAA,EAAA,MAAc;EAUlB,IAAA,EAAA,mBAAU,GAAA,eAAA;EAIR,MAAA,CAAA,EAAA,MAAA;EAIA,UAAA,EAAA,MAAA;EAAqB,QAAA,EAAA,MAAA;EAAY,UAAA,EAXlC,IAWkC;;cARnC,UAAA;;qDAIE;eAIA,qBAAqB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=class{constructor(e){this.eventEmitter=e}check(e,t){let n=t.definition.sla;if(!n)return;let r=new Date().getTime();if(n.totalDurationMs){let t=r-e.createdAt.getTime();t>n.totalDurationMs&&(e.status===`running`||e.status===`paused`)&&this.eventEmitter(`workflow.sla_breach`,{workflowId:e.workflowId,workflowName:e.workflowName,type:`workflow_duration`,expectedMs:n.totalDurationMs,actualMs:t,breachedAt:new Date})}if(n.stepDurationMs&&e.status===`running`&&e.currentStep){let t=e.history.find(t=>t.stepId===e.currentStep&&t.status===`running`);if(t){let i=n.stepDurationMs[e.currentStep];if(i){let n=r-t.startedAt.getTime();n>i&&this.eventEmitter(`workflow.sla_breach`,{workflowId:e.workflowId,workflowName:e.workflowName,type:`step_duration`,stepId:e.currentStep,expectedMs:i,actualMs:n,breachedAt:new Date})}}}}};export{e as SLAMonitor};
|
|
2
|
+
//# sourceMappingURL=sla-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sla-monitor.js","names":["eventEmitter: (\n event: string,\n payload: SLABreachEvent\n ) => void"],"sources":["../../src/workflow/sla-monitor.ts"],"sourcesContent":["import type { WorkflowState } from './state';\nimport type { WorkflowSpec } from './spec';\n\nexport interface SLABreachEvent {\n workflowId: string;\n workflowName: string;\n type: 'workflow_duration' | 'step_duration';\n stepId?: string;\n expectedMs: number;\n actualMs: number;\n breachedAt: Date;\n}\n\nexport class SLAMonitor {\n constructor(\n private readonly eventEmitter: (\n event: string,\n payload: SLABreachEvent\n ) => void\n ) {}\n\n check(state: WorkflowState, spec: WorkflowSpec): void {\n const sla = spec.definition.sla;\n if (!sla) return;\n\n const now = new Date().getTime();\n\n // Check total workflow duration\n if (sla.totalDurationMs) {\n const duration = now - state.createdAt.getTime();\n if (duration > sla.totalDurationMs) {\n // Only emit if not already completed/failed/cancelled\n if (state.status === 'running' || state.status === 'paused') {\n this.eventEmitter('workflow.sla_breach', {\n workflowId: state.workflowId,\n workflowName: state.workflowName,\n type: 'workflow_duration',\n expectedMs: sla.totalDurationMs,\n actualMs: duration,\n breachedAt: new Date(),\n });\n }\n }\n }\n\n // Check step durations\n if (sla.stepDurationMs) {\n // Check currently running step\n if (state.status === 'running' && state.currentStep) {\n // Find when the current step started\n // It might be the last entry in history if it's running?\n // But history usually stores *completed* steps or *failed* attempts.\n // Runner updates history with status='running' at start of execution?\n // Let's check runner.ts:\n // const execution: StepExecution = { ... status: 'running' ... };\n // workingState.history.push(execution);\n // Yes, it pushes running execution.\n\n const currentExecution = state.history.find(\n (h) => h.stepId === state.currentStep && h.status === 'running'\n );\n\n if (currentExecution) {\n const stepLimit = sla.stepDurationMs[state.currentStep];\n if (stepLimit) {\n const stepDuration = now - currentExecution.startedAt.getTime();\n if (stepDuration > stepLimit) {\n this.eventEmitter('workflow.sla_breach', {\n workflowId: state.workflowId,\n workflowName: state.workflowName,\n type: 'step_duration',\n stepId: state.currentStep,\n expectedMs: stepLimit,\n actualMs: stepDuration,\n breachedAt: new Date(),\n });\n }\n }\n }\n }\n }\n }\n}\n"],"mappings":"AAaA,IAAa,EAAb,KAAwB,CACtB,YACE,EAIA,CAJiB,KAAA,aAAA,EAMnB,MAAM,EAAsB,EAA0B,CACpD,IAAM,EAAM,EAAK,WAAW,IAC5B,GAAI,CAAC,EAAK,OAEV,IAAM,EAAM,IAAI,MAAM,CAAC,SAAS,CAGhC,GAAI,EAAI,gBAAiB,CACvB,IAAM,EAAW,EAAM,EAAM,UAAU,SAAS,CAC5C,EAAW,EAAI,kBAEb,EAAM,SAAW,WAAa,EAAM,SAAW,WACjD,KAAK,aAAa,sBAAuB,CACvC,WAAY,EAAM,WAClB,aAAc,EAAM,aACpB,KAAM,oBACN,WAAY,EAAI,gBAChB,SAAU,EACV,WAAY,IAAI,KACjB,CAAC,CAMR,GAAI,EAAI,gBAEF,EAAM,SAAW,WAAa,EAAM,YAAa,CAUnD,IAAM,EAAmB,EAAM,QAAQ,KACpC,GAAM,EAAE,SAAW,EAAM,aAAe,EAAE,SAAW,UACvD,CAED,GAAI,EAAkB,CACpB,IAAM,EAAY,EAAI,eAAe,EAAM,aAC3C,GAAI,EAAW,CACb,IAAM,EAAe,EAAM,EAAiB,UAAU,SAAS,CAC3D,EAAe,GACjB,KAAK,aAAa,sBAAuB,CACvC,WAAY,EAAM,WAClB,aAAc,EAAM,aACpB,KAAM,gBACN,OAAQ,EAAM,YACd,WAAY,EACZ,SAAU,EACV,WAAY,IAAI,KACjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","names":[],"sources":["../../src/workflow/spec.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAQA;AAKY,UALK,OAAA,CAKG;EAER,GAAA,EAAA,MAAA;EAOA,OAAA,EAAA,MAAA;AAEZ;AAMiB,KAjBL,QAAA,GAiBgB,OAAA,GAAA,YAAA,GAAA,UAAA;AAQX,KAvBL,cAAA,
|
|
1
|
+
{"version":3,"file":"spec.d.ts","names":[],"sources":["../../src/workflow/spec.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAQA;AAKY,UALK,OAAA,CAKG;EAER,GAAA,EAAA,MAAA;EAOA,OAAA,EAAA,MAAA;AAEZ;AAMiB,KAjBL,QAAA,GAiBgB,OAAA,GAAA,YAAA,GAAA,UAAA;AAQX,KAvBL,cAAA,GAuBe,SAIlB,GAAA,QAAO,GAAA,WAAA,GAAA,QAAA,GAAA,WAAA;AAGC,KAvBL,kBAAA,GAuBS,QAAA,GAAA,YAAA;AAEb,UAvBS,cAAA,CAuBT;EAGG,IAAA,EAzBH,kBAyBG;EACD;EAEA,KAAA,EAAA,MAAA;;AAI4B,UA3BrB,WAAA,CA2BqB;EAGrB,WAAA,EAAU,MAAA;EAQV,OAAG,EAAA,QAAA,GAED,aAAM;EAGR,OAAA,EAAA,MAAA;EAMA;EAKA,UAAA,CAAA,EAAA,MAAA;;AAEF,UAhDE,UAAA,CAgDF;EAGP;EACS,SAAA,CAAA,EAlDH,KAkDG;EAAoB;EAGpB,IAAA,CAAA,EAnDR,OAmDQ;AAOjB;AACQ,UAxDS,IAAA,CAwDT;EACM,EAAA,EAAA,MAAA;EAEE,IAAA,EAzDR,QAyDQ;EAAa,KAAA,EAAA,MAAA;EAOhB,WAAA,CAAA,EAAA,MAAgB;EAGZ,MAAA,CAAA,EAhEN,UAgEM;EAOP,KAAA,CAAA,EAtEA,cAsEA;EAI6B,SAAA,CAAA,EAAA,MAAA;EAAY,KAAA,CAAA,EAxEzC,WAwEyC;;;;yBApE1B;;UAGR,UAAA;;;;;;;UAQA,GAAA;;mBAEE;;UAGF,gBAAA;;aAEJ;;;UAII,oBAAA;;SAER;;UAGQ,kBAAA;SACR;eACM;;;QAGP;iBACS;;UAGA,YAAA,SAAqB;;;;;;UAOrB,YAAA;QACT;cACM;;;;gBAEE;;cAOH,gBAAA;;iBAGI;UAOP;uCAI6B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","names":["candidate: WorkflowSpec | undefined"],"sources":["../../src/workflow/spec.ts"],"sourcesContent":["import type { CapabilityRef } from '../capabilities';\nimport type { OwnerShipMeta } from '../ownership';\nimport type { OpRef } from '../features';\nimport type { ExperimentRef } from '../experiments/spec';\n\n/**\n * Reference to a form spec declared in {@link FormRegistry}.\n */\nexport interface FormRef {\n key: string;\n version: number;\n}\n\nexport type StepType = 'human' | 'automation' | 'decision';\n\nexport type WorkflowStatus =\n | 'running'\n | 'paused'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\nexport type GuardConditionKind = 'policy' | 'expression';\n\nexport interface GuardCondition {\n type: GuardConditionKind;\n /** Policy name or expression string depending on the type. */\n value: string;\n}\n\nexport interface RetryPolicy {\n maxAttempts: number;\n backoff: 'linear' | 'exponential';\n delayMs: number;\n /** Optional max delay cap for exponential backoff. */\n maxDelayMs?: number;\n}\n\nexport interface StepAction {\n /** Operation executed for automation steps. */\n operation?: OpRef;\n /** Form rendered for human input steps. */\n form?: FormRef;\n}\n\nexport interface Step {\n id: string;\n type: StepType;\n label: string;\n description?: string;\n action?: StepAction;\n guard?: GuardCondition;\n timeoutMs?: number;\n retry?: RetryPolicy;\n /** Integration slot identifiers required before this step can execute. */\n requiredIntegrations?: string[];\n /** Capabilities that must be enabled for this step to execute. */\n requiredCapabilities?: CapabilityRef[];\n}\n\nexport interface Transition {\n from: string;\n to: string;\n label?: string;\n /** Expression evaluated against workflow data (e.g., `data.approved === true`). */\n condition?: string;\n}\n\nexport interface SLA {\n totalDurationMs?: number;\n stepDurationMs?: Record<string, number>;\n}\n\nexport interface CompensationStep {\n stepId: string;\n operation: OpRef;\n description?: string;\n}\n\nexport interface CompensationStrategy {\n trigger?: 'on_failure' | 'manual';\n steps: CompensationStep[];\n}\n\nexport interface WorkflowDefinition {\n steps: Step[];\n transitions: Transition[];\n /** Optional explicit entry step. Defaults to the first step when omitted. */\n entryStepId?: string;\n sla?: SLA;\n compensation?: CompensationStrategy;\n}\n\nexport interface WorkflowMeta extends OwnerShipMeta {\n /** Fully-qualified workflow name (e.g., `sigil.onboarding.basic`). */\n name: string;\n /** Version of the workflow. Increment on breaking changes. */\n version: number;\n}\n\nexport interface WorkflowSpec {\n meta: WorkflowMeta;\n definition: WorkflowDefinition;\n policy?: { flags?: string[] };\n experiments?: ExperimentRef[];\n}\n\nfunction workflowKey(meta: WorkflowMeta) {\n return `${meta.name}.v${meta.version}`;\n}\n\nexport class WorkflowRegistry {\n private readonly items = new Map<string, WorkflowSpec>();\n\n register(spec: WorkflowSpec): this {\n const key = workflowKey(spec.meta);\n if (this.items.has(key)) throw new Error(`Duplicate workflow ${key}`);\n this.items.set(key, spec);\n return this;\n }\n\n list(): WorkflowSpec[] {\n return [...this.items.values()];\n }\n\n get(name: string, version?: number): WorkflowSpec | undefined {\n if (version != null) return this.items.get(`${name}.v${version}`);\n let candidate: WorkflowSpec | undefined;\n let max = -Infinity;\n for (const spec of this.items.values()) {\n if (spec.meta.name !== name) continue;\n if (spec.meta.version > max) {\n max = spec.meta.version;\n candidate = spec;\n }\n }\n return candidate;\n }\n}\n
|
|
1
|
+
{"version":3,"file":"spec.js","names":["candidate: WorkflowSpec | undefined"],"sources":["../../src/workflow/spec.ts"],"sourcesContent":["import type { CapabilityRef } from '../capabilities';\nimport type { OwnerShipMeta } from '../ownership';\nimport type { OpRef } from '../features';\nimport type { ExperimentRef } from '../experiments/spec';\n\n/**\n * Reference to a form spec declared in {@link FormRegistry}.\n */\nexport interface FormRef {\n key: string;\n version: number;\n}\n\nexport type StepType = 'human' | 'automation' | 'decision';\n\nexport type WorkflowStatus =\n | 'running'\n | 'paused'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\nexport type GuardConditionKind = 'policy' | 'expression';\n\nexport interface GuardCondition {\n type: GuardConditionKind;\n /** Policy name or expression string depending on the type. */\n value: string;\n}\n\nexport interface RetryPolicy {\n maxAttempts: number;\n backoff: 'linear' | 'exponential';\n delayMs: number;\n /** Optional max delay cap for exponential backoff. */\n maxDelayMs?: number;\n}\n\nexport interface StepAction {\n /** Operation executed for automation steps. */\n operation?: OpRef;\n /** Form rendered for human input steps. */\n form?: FormRef;\n}\n\nexport interface Step {\n id: string;\n type: StepType;\n label: string;\n description?: string;\n action?: StepAction;\n guard?: GuardCondition;\n timeoutMs?: number;\n retry?: RetryPolicy;\n /** Integration slot identifiers required before this step can execute. */\n requiredIntegrations?: string[];\n /** Capabilities that must be enabled for this step to execute. */\n requiredCapabilities?: CapabilityRef[];\n}\n\nexport interface Transition {\n from: string;\n to: string;\n label?: string;\n /** Expression evaluated against workflow data (e.g., `data.approved === true`). */\n condition?: string;\n}\n\nexport interface SLA {\n totalDurationMs?: number;\n stepDurationMs?: Record<string, number>;\n}\n\nexport interface CompensationStep {\n stepId: string;\n operation: OpRef;\n description?: string;\n}\n\nexport interface CompensationStrategy {\n trigger?: 'on_failure' | 'manual';\n steps: CompensationStep[];\n}\n\nexport interface WorkflowDefinition {\n steps: Step[];\n transitions: Transition[];\n /** Optional explicit entry step. Defaults to the first step when omitted. */\n entryStepId?: string;\n sla?: SLA;\n compensation?: CompensationStrategy;\n}\n\nexport interface WorkflowMeta extends OwnerShipMeta {\n /** Fully-qualified workflow name (e.g., `sigil.onboarding.basic`). */\n name: string;\n /** Version of the workflow. Increment on breaking changes. */\n version: number;\n}\n\nexport interface WorkflowSpec {\n meta: WorkflowMeta;\n definition: WorkflowDefinition;\n policy?: { flags?: string[] };\n experiments?: ExperimentRef[];\n}\n\nfunction workflowKey(meta: WorkflowMeta) {\n return `${meta.name}.v${meta.version}`;\n}\n\nexport class WorkflowRegistry {\n private readonly items = new Map<string, WorkflowSpec>();\n\n register(spec: WorkflowSpec): this {\n const key = workflowKey(spec.meta);\n if (this.items.has(key)) throw new Error(`Duplicate workflow ${key}`);\n this.items.set(key, spec);\n return this;\n }\n\n list(): WorkflowSpec[] {\n return [...this.items.values()];\n }\n\n get(name: string, version?: number): WorkflowSpec | undefined {\n if (version != null) return this.items.get(`${name}.v${version}`);\n let candidate: WorkflowSpec | undefined;\n let max = -Infinity;\n for (const spec of this.items.values()) {\n if (spec.meta.name !== name) continue;\n if (spec.meta.version > max) {\n max = spec.meta.version;\n candidate = spec;\n }\n }\n return candidate;\n }\n}\n"],"mappings":"AA2GA,SAAS,EAAY,EAAoB,CACvC,MAAO,GAAG,EAAK,KAAK,IAAI,EAAK,UAG/B,IAAa,EAAb,KAA8B,CAC5B,MAAyB,IAAI,IAE7B,SAAS,EAA0B,CACjC,IAAM,EAAM,EAAY,EAAK,KAAK,CAClC,GAAI,KAAK,MAAM,IAAI,EAAI,CAAE,MAAU,MAAM,sBAAsB,IAAM,CAErE,OADA,KAAK,MAAM,IAAI,EAAK,EAAK,CAClB,KAGT,MAAuB,CACrB,MAAO,CAAC,GAAG,KAAK,MAAM,QAAQ,CAAC,CAGjC,IAAI,EAAc,EAA4C,CAC5D,GAAI,GAAW,KAAM,OAAO,KAAK,MAAM,IAAI,GAAG,EAAK,IAAI,IAAU,CACjE,IAAIA,EACA,EAAM,KACV,IAAK,IAAM,KAAQ,KAAK,MAAM,QAAQ,CAChC,EAAK,KAAK,OAAS,GACnB,EAAK,KAAK,QAAU,IACtB,EAAM,EAAK,KAAK,QAChB,EAAY,GAGhB,OAAO"}
|
package/dist/workflow/state.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","names":[],"sources":["../../src/workflow/state.ts"],"sourcesContent":[],"mappings":";;;UAEiB,aAAA;;EAAA,SAAA,EAEJ,IAFI;EAUA,WAAA,CAAA,EAPD,IAOc;EAKtB,MAAA,EAAA,SAAA,GAAA,SAAA,GAAA,WAAA,GAAA,QAAA;
|
|
1
|
+
{"version":3,"file":"state.d.ts","names":[],"sources":["../../src/workflow/state.ts"],"sourcesContent":[],"mappings":";;;UAEiB,aAAA;;EAAA,SAAA,EAEJ,IAFI;EAUA,WAAA,CAAA,EAPD,IAOc;EAKtB,MAAA,EAAA,SAAA,GAAA,SAAA,GAAA,WAAA,GAAA,QAAA;EACQ,KAAA,CAAA,EAAA,OAAA;EACL,MAAA,CAAA,EAAA,OAAA;EACD,KAAA,CAAA,EAAA,MAAA;;AAEG,UAVI,aAAA,CAUJ;EAAI,UAAA,EAAA,MAAA;EAGA,YAAA,EAAA,MAAA;EAIA,eAAU,EAAA,MAAA;EACX,WAAA,EAAA,MAAA;EAAgB,IAAA,EAbxB,MAawB,CAAA,MAAA,EAAA,OAAA,CAAA;EACG,WAAA,CAAA,EAbnB,MAamB,CAAA,MAAA,EAAA,MAAA,CAAA;EAAR,OAAA,EAZhB,aAYgB,EAAA;EAGJ,MAAA,EAdb,cAca;EAAkB,SAAA,EAb5B,IAa4B;EAC5B,SAAA,EAbA,IAaA;;AACI,UAXA,oBAAA,CAWA;EAA+B,MAAA,CAAA,EAVrC,cAUqC;;AAAD,UAP9B,UAAA,CAO8B;gBAN/B,gBAAgB;2BACL,QAAQ;gDAGZ,kBAAkB,gBACpC,QAAQ;iBACI,uBAAuB,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","names":[],"sources":["../../src/workflow/validation.ts"],"sourcesContent":[],"mappings":";;;;;KASY,uBAAA;UAEK,uBAAA;EAFL,KAAA,EAGH,uBAH0B;EAElB,OAAA,EAAA,MAAA;EAMA,OAAA,CAAA,EAHL,MAGK,CAAA,MAAA,EAAA,OAA2B,CAAA;AAK5C;AAG4B,UARX,2BAAA,CAQW;EAAA,UAAA,CAAA,EAPb,YAOa;EAHiB,KAAA,CAAA,EAHnC,YAGmC;;AAe7B,cAfH,uBAAA,SAAgC,KAAA,CAeT;EAC5B,SAAA,MAAA,EAboB,uBAapB,EAAA;EACG,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAdiB,uBAcjB,EAAA;;;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","names":[],"sources":["../../src/workflow/validation.ts"],"sourcesContent":[],"mappings":";;;;;KASY,uBAAA;UAEK,uBAAA;EAFL,KAAA,EAGH,uBAH0B;EAElB,OAAA,EAAA,MAAA;EAMA,OAAA,CAAA,EAHL,MAGK,CAAA,MAAA,EAAA,OAA2B,CAAA;AAK5C;AAG4B,UARX,2BAAA,CAQW;EAAA,UAAA,CAAA,EAPb,YAOa;EAHiB,KAAA,CAAA,EAHnC,YAGmC;;AAe7B,cAfH,uBAAA,SAAgC,KAAA,CAeT;EAC5B,SAAA,MAAA,EAboB,uBAapB,EAAA;EACG,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAdiB,uBAcjB,EAAA;;;AAqCX;;;;iBAvCgB,oBAAA,OACR,wBACG,8BACR;iBAoCa,uBAAA,OACR,wBACG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","names":["issues: WorkflowValidationIssue[]"],"sources":["../../src/workflow/validation.ts"],"sourcesContent":["import type { FormRegistry } from '../forms';\nimport type { SpecRegistry } from '../registry';\nimport type {\n Step,\n Transition,\n WorkflowDefinition,\n WorkflowSpec,\n} from './spec';\n\nexport type WorkflowValidationLevel = 'error' | 'warning';\n\nexport interface WorkflowValidationIssue {\n level: WorkflowValidationLevel;\n message: string;\n context?: Record<string, unknown>;\n}\n\nexport interface ValidateWorkflowSpecOptions {\n operations?: SpecRegistry;\n forms?: FormRegistry;\n}\n\nexport class WorkflowValidationError extends Error {\n constructor(\n message: string,\n public readonly issues: WorkflowValidationIssue[]\n ) {\n super(message);\n this.name = 'WorkflowValidationError';\n }\n}\n\n/**\n * Validate workflow structure, references, and reachability.\n * Returns the collected issues. Consumers may call {@link assertWorkflowSpecValid}\n * to throw on validation errors.\n */\nexport function validateWorkflowSpec(\n spec: WorkflowSpec,\n options: ValidateWorkflowSpecOptions = {}\n): WorkflowValidationIssue[] {\n const issues: WorkflowValidationIssue[] = [];\n const { definition } = spec;\n\n if (!definition.steps.length) {\n issues.push({\n level: 'error',\n message: 'Workflow must declare at least one step.',\n });\n return issues;\n }\n\n const stepsById = indexSteps(definition, issues);\n const entryStepId =\n definition.entryStepId ?? definition.steps[0]?.id ?? null;\n\n if (!entryStepId) {\n issues.push({\n level: 'error',\n message: 'Workflow requires an entry step (definition.entryStepId).',\n });\n } else if (!stepsById.has(entryStepId)) {\n issues.push({\n level: 'error',\n message: `Entry step \"${entryStepId}\" is not defined in steps.`,\n });\n }\n\n const adjacency = buildAdjacency(definition, stepsById, issues);\n\n validateStepActions(definition.steps, options, issues);\n validateReachability(entryStepId, stepsById, adjacency, issues);\n detectCycles(adjacency, issues);\n\n return issues;\n}\n\nexport function assertWorkflowSpecValid(\n spec: WorkflowSpec,\n options: ValidateWorkflowSpecOptions = {}\n): void {\n const issues = validateWorkflowSpec(spec, options);\n const errors = issues.filter((issue) => issue.level === 'error');\n if (errors.length) {\n throw new WorkflowValidationError(\n `Workflow ${spec.meta.name}.v${spec.meta.version} is invalid`,\n issues\n );\n }\n}\n\nfunction indexSteps(\n definition: WorkflowDefinition,\n issues: WorkflowValidationIssue[]\n) {\n const stepsById = new Map<string, Step>();\n for (const step of definition.steps) {\n if (stepsById.has(step.id)) {\n issues.push({\n level: 'error',\n message: `Duplicate step id \"${step.id}\" detected.`,\n });\n continue;\n }\n stepsById.set(step.id, step);\n if (step.type === 'automation' && !step.action?.operation) {\n issues.push({\n level: 'warning',\n message: `Automation step \"${step.id}\" does not declare an operation.`,\n });\n }\n if (step.type === 'human' && !step.action?.form) {\n issues.push({\n level: 'warning',\n message: `Human step \"${step.id}\" does not declare a form.`,\n });\n }\n if (step.guard && !step.guard.value.trim()) {\n issues.push({\n level: 'error',\n message: `Guard for step \"${step.id}\" must have a non-empty value.`,\n });\n }\n }\n return stepsById;\n}\n\nfunction buildAdjacency(\n definition: WorkflowDefinition,\n stepsById: Map<string, Step>,\n issues: WorkflowValidationIssue[]\n) {\n const adjacency = new Map<string, Set<string>>();\n const incoming = new Map<string, number>();\n\n for (const stepId of stepsById.keys()) {\n adjacency.set(stepId, new Set());\n incoming.set(stepId, 0);\n }\n\n for (const transition of definition.transitions) {\n const from = stepsById.get(transition.from);\n const to = stepsById.get(transition.to);\n\n if (!from) {\n issues.push({\n level: 'error',\n message: `Transition refers to unknown \"from\" step \"${transition.from}\".`,\n });\n continue;\n }\n if (!to) {\n issues.push({\n level: 'error',\n message: `Transition refers to unknown \"to\" step \"${transition.to}\".`,\n });\n continue;\n }\n\n adjacency.get(transition.from)?.add(transition.to);\n incoming.set(\n transition.to,\n (incoming.get(transition.to) ?? 0) + 1\n );\n\n validateTransition(transition, issues);\n }\n\n const roots = [...incoming.entries()]\n .filter(([, count]) => count === 0)\n .map(([id]) => id);\n if (roots.length > 1) {\n issues.push({\n level: 'warning',\n message: `Workflow has multiple potential entry steps: ${roots.join(', ')}`,\n });\n }\n\n return adjacency;\n}\n\nfunction validateTransition(\n transition: Transition,\n issues: WorkflowValidationIssue[]\n) {\n if (transition.condition && !transition.condition.trim()) {\n issues.push({\n level: 'error',\n message: `Transition ${transition.from} -> ${transition.to} declares an empty condition.`,\n });\n }\n}\n\nfunction validateStepActions(\n steps: Step[],\n options: ValidateWorkflowSpecOptions,\n issues: WorkflowValidationIssue[]\n) {\n for (const step of steps) {\n const action = step.action;\n if (!action) continue;\n if (action.operation && options.operations) {\n const op = options.operations.getSpec(\n action.operation.name,\n action.operation.version\n );\n if (!op) {\n issues.push({\n level: 'error',\n message: `Step \"${step.id}\" references unknown operation ${action.operation.name}.v${action.operation.version}.`,\n });\n }\n }\n if (action.form && options.forms) {\n const form = options.forms.get(action.form.key, action.form.version);\n if (!form) {\n issues.push({\n level: 'error',\n message: `Step \"${step.id}\" references unknown form ${action.form.key}.v${action.form.version}.`,\n });\n }\n }\n }\n}\n\nfunction validateReachability(\n entryStepId: string | null,\n stepsById: Map<string, Step>,\n adjacency: Map<string, Set<string>>,\n issues: WorkflowValidationIssue[]\n) {\n if (!entryStepId || !stepsById.has(entryStepId)) return;\n const visited = new Set<string>();\n const queue = [entryStepId];\n visited.add(entryStepId);\n\n while (queue.length) {\n const current = queue.shift()!;\n const neighbours = adjacency.get(current);\n if (!neighbours) continue;\n for (const next of neighbours) {\n if (visited.has(next)) continue;\n visited.add(next);\n queue.push(next);\n }\n }\n\n for (const stepId of stepsById.keys()) {\n if (!visited.has(stepId)) {\n issues.push({\n level: 'error',\n message: `Step \"${stepId}\" is unreachable from entry step \"${entryStepId}\".`,\n });\n }\n }\n}\n\nfunction detectCycles(\n adjacency: Map<string, Set<string>>,\n issues: WorkflowValidationIssue[]\n) {\n const visited = new Set<string>();\n const stack = new Set<string>();\n let cycleReported = false;\n\n const dfs = (node: string) => {\n if (stack.has(node)) {\n if (!cycleReported) {\n issues.push({\n level: 'error',\n message: `Workflow contains a cycle involving step \"${node}\".`,\n });\n cycleReported = true;\n }\n return;\n }\n if (visited.has(node)) return;\n\n stack.add(node);\n const neighbours = adjacency.get(node);\n if (neighbours) {\n for (const next of neighbours) dfs(next);\n }\n stack.delete(node);\n visited.add(node);\n };\n\n for (const node of adjacency.keys()) dfs(node);\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validation.js","names":["issues: WorkflowValidationIssue[]"],"sources":["../../src/workflow/validation.ts"],"sourcesContent":["import type { FormRegistry } from '../forms';\nimport type { SpecRegistry } from '../registry';\nimport type {\n Step,\n Transition,\n WorkflowDefinition,\n WorkflowSpec,\n} from './spec';\n\nexport type WorkflowValidationLevel = 'error' | 'warning';\n\nexport interface WorkflowValidationIssue {\n level: WorkflowValidationLevel;\n message: string;\n context?: Record<string, unknown>;\n}\n\nexport interface ValidateWorkflowSpecOptions {\n operations?: SpecRegistry;\n forms?: FormRegistry;\n}\n\nexport class WorkflowValidationError extends Error {\n constructor(\n message: string,\n public readonly issues: WorkflowValidationIssue[]\n ) {\n super(message);\n this.name = 'WorkflowValidationError';\n }\n}\n\n/**\n * Validate workflow structure, references, and reachability.\n * Returns the collected issues. Consumers may call {@link assertWorkflowSpecValid}\n * to throw on validation errors.\n */\nexport function validateWorkflowSpec(\n spec: WorkflowSpec,\n options: ValidateWorkflowSpecOptions = {}\n): WorkflowValidationIssue[] {\n const issues: WorkflowValidationIssue[] = [];\n const { definition } = spec;\n\n if (!definition.steps.length) {\n issues.push({\n level: 'error',\n message: 'Workflow must declare at least one step.',\n });\n return issues;\n }\n\n const stepsById = indexSteps(definition, issues);\n const entryStepId = definition.entryStepId ?? definition.steps[0]?.id ?? null;\n\n if (!entryStepId) {\n issues.push({\n level: 'error',\n message: 'Workflow requires an entry step (definition.entryStepId).',\n });\n } else if (!stepsById.has(entryStepId)) {\n issues.push({\n level: 'error',\n message: `Entry step \"${entryStepId}\" is not defined in steps.`,\n });\n }\n\n const adjacency = buildAdjacency(definition, stepsById, issues);\n\n validateStepActions(definition.steps, options, issues);\n validateReachability(entryStepId, stepsById, adjacency, issues);\n detectCycles(adjacency, issues);\n\n return issues;\n}\n\nexport function assertWorkflowSpecValid(\n spec: WorkflowSpec,\n options: ValidateWorkflowSpecOptions = {}\n): void {\n const issues = validateWorkflowSpec(spec, options);\n const errors = issues.filter((issue) => issue.level === 'error');\n if (errors.length) {\n throw new WorkflowValidationError(\n `Workflow ${spec.meta.name}.v${spec.meta.version} is invalid`,\n issues\n );\n }\n}\n\nfunction indexSteps(\n definition: WorkflowDefinition,\n issues: WorkflowValidationIssue[]\n) {\n const stepsById = new Map<string, Step>();\n for (const step of definition.steps) {\n if (stepsById.has(step.id)) {\n issues.push({\n level: 'error',\n message: `Duplicate step id \"${step.id}\" detected.`,\n });\n continue;\n }\n stepsById.set(step.id, step);\n if (step.type === 'automation' && !step.action?.operation) {\n issues.push({\n level: 'warning',\n message: `Automation step \"${step.id}\" does not declare an operation.`,\n });\n }\n if (step.type === 'human' && !step.action?.form) {\n issues.push({\n level: 'warning',\n message: `Human step \"${step.id}\" does not declare a form.`,\n });\n }\n if (step.guard && !step.guard.value.trim()) {\n issues.push({\n level: 'error',\n message: `Guard for step \"${step.id}\" must have a non-empty value.`,\n });\n }\n }\n return stepsById;\n}\n\nfunction buildAdjacency(\n definition: WorkflowDefinition,\n stepsById: Map<string, Step>,\n issues: WorkflowValidationIssue[]\n) {\n const adjacency = new Map<string, Set<string>>();\n const incoming = new Map<string, number>();\n\n for (const stepId of stepsById.keys()) {\n adjacency.set(stepId, new Set());\n incoming.set(stepId, 0);\n }\n\n for (const transition of definition.transitions) {\n const from = stepsById.get(transition.from);\n const to = stepsById.get(transition.to);\n\n if (!from) {\n issues.push({\n level: 'error',\n message: `Transition refers to unknown \"from\" step \"${transition.from}\".`,\n });\n continue;\n }\n if (!to) {\n issues.push({\n level: 'error',\n message: `Transition refers to unknown \"to\" step \"${transition.to}\".`,\n });\n continue;\n }\n\n adjacency.get(transition.from)?.add(transition.to);\n incoming.set(transition.to, (incoming.get(transition.to) ?? 0) + 1);\n\n validateTransition(transition, issues);\n }\n\n const roots = [...incoming.entries()]\n .filter(([, count]) => count === 0)\n .map(([id]) => id);\n if (roots.length > 1) {\n issues.push({\n level: 'warning',\n message: `Workflow has multiple potential entry steps: ${roots.join(', ')}`,\n });\n }\n\n return adjacency;\n}\n\nfunction validateTransition(\n transition: Transition,\n issues: WorkflowValidationIssue[]\n) {\n if (transition.condition && !transition.condition.trim()) {\n issues.push({\n level: 'error',\n message: `Transition ${transition.from} -> ${transition.to} declares an empty condition.`,\n });\n }\n}\n\nfunction validateStepActions(\n steps: Step[],\n options: ValidateWorkflowSpecOptions,\n issues: WorkflowValidationIssue[]\n) {\n for (const step of steps) {\n const action = step.action;\n if (!action) continue;\n if (action.operation && options.operations) {\n const op = options.operations.getSpec(\n action.operation.name,\n action.operation.version\n );\n if (!op) {\n issues.push({\n level: 'error',\n message: `Step \"${step.id}\" references unknown operation ${action.operation.name}.v${action.operation.version}.`,\n });\n }\n }\n if (action.form && options.forms) {\n const form = options.forms.get(action.form.key, action.form.version);\n if (!form) {\n issues.push({\n level: 'error',\n message: `Step \"${step.id}\" references unknown form ${action.form.key}.v${action.form.version}.`,\n });\n }\n }\n }\n}\n\nfunction validateReachability(\n entryStepId: string | null,\n stepsById: Map<string, Step>,\n adjacency: Map<string, Set<string>>,\n issues: WorkflowValidationIssue[]\n) {\n if (!entryStepId || !stepsById.has(entryStepId)) return;\n const visited = new Set<string>();\n const queue = [entryStepId];\n visited.add(entryStepId);\n\n while (queue.length) {\n const current = queue.shift()!;\n const neighbours = adjacency.get(current);\n if (!neighbours) continue;\n for (const next of neighbours) {\n if (visited.has(next)) continue;\n visited.add(next);\n queue.push(next);\n }\n }\n\n for (const stepId of stepsById.keys()) {\n if (!visited.has(stepId)) {\n issues.push({\n level: 'error',\n message: `Step \"${stepId}\" is unreachable from entry step \"${entryStepId}\".`,\n });\n }\n }\n}\n\nfunction detectCycles(\n adjacency: Map<string, Set<string>>,\n issues: WorkflowValidationIssue[]\n) {\n const visited = new Set<string>();\n const stack = new Set<string>();\n let cycleReported = false;\n\n const dfs = (node: string) => {\n if (stack.has(node)) {\n if (!cycleReported) {\n issues.push({\n level: 'error',\n message: `Workflow contains a cycle involving step \"${node}\".`,\n });\n cycleReported = true;\n }\n return;\n }\n if (visited.has(node)) return;\n\n stack.add(node);\n const neighbours = adjacency.get(node);\n if (neighbours) {\n for (const next of neighbours) dfs(next);\n }\n stack.delete(node);\n visited.add(node);\n };\n\n for (const node of adjacency.keys()) dfs(node);\n}\n"],"mappings":"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"}
|