@plumbus/core 0.7.1 → 0.8.0-beta.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/CHANGELOG.md +39 -0
- package/README.md +2 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/admission/client.d.ts +9 -0
- package/dist/admission/client.d.ts.map +1 -0
- package/dist/admission/client.js +34 -0
- package/dist/admission/client.js.map +1 -0
- package/dist/admission/index.d.ts +5 -0
- package/dist/admission/index.d.ts.map +1 -0
- package/dist/admission/index.js +4 -0
- package/dist/admission/index.js.map +1 -0
- package/dist/admission/request-admission.d.ts +26 -0
- package/dist/admission/request-admission.d.ts.map +1 -0
- package/dist/admission/request-admission.js +85 -0
- package/dist/admission/request-admission.js.map +1 -0
- package/dist/admission/shared.d.ts +31 -0
- package/dist/admission/shared.d.ts.map +1 -0
- package/dist/admission/shared.js +30 -0
- package/dist/admission/shared.js.map +1 -0
- package/dist/ai/ai/provider.d.ts +5 -7
- package/dist/ai/ai-service.d.ts +8 -1
- package/dist/ai/ai-service.d.ts.map +1 -1
- package/dist/ai/ai-service.js +23 -13
- package/dist/ai/ai-service.js.map +1 -1
- package/dist/ai/errors/data-errors.d.ts +6 -0
- package/dist/ai/errors/index.d.ts +4 -1
- package/dist/ai/fill-prompt-template.d.ts +12 -0
- package/dist/ai/fill-prompt-template.d.ts.map +1 -0
- package/dist/ai/fill-prompt-template.js +19 -0
- package/dist/ai/fill-prompt-template.js.map +1 -0
- package/dist/ai/governed-artifacts.d.ts +49 -0
- package/dist/ai/governed-artifacts.d.ts.map +1 -0
- package/dist/ai/governed-artifacts.js +277 -0
- package/dist/ai/governed-artifacts.js.map +1 -0
- package/dist/ai/governed-budget.d.ts +17 -0
- package/dist/ai/governed-budget.d.ts.map +1 -0
- package/dist/ai/governed-budget.js +52 -0
- package/dist/ai/governed-budget.js.map +1 -0
- package/dist/ai/governed-host.d.ts +54 -0
- package/dist/ai/governed-host.d.ts.map +1 -0
- package/dist/ai/governed-host.js +8 -0
- package/dist/ai/governed-host.js.map +1 -0
- package/dist/ai/governed-invoke.d.ts +41 -0
- package/dist/ai/governed-invoke.d.ts.map +1 -0
- package/dist/ai/governed-invoke.js +102 -0
- package/dist/ai/governed-invoke.js.map +1 -0
- package/dist/ai/governed-runtime.d.ts +103 -0
- package/dist/ai/governed-runtime.d.ts.map +1 -0
- package/dist/ai/governed-runtime.js +151 -0
- package/dist/ai/governed-runtime.js.map +1 -0
- package/dist/ai/index.d.ts +12 -2
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +8 -2
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/prompt-registry.d.ts +6 -0
- package/dist/ai/prompt-registry.d.ts.map +1 -1
- package/dist/ai/prompt-registry.js +12 -0
- package/dist/ai/prompt-registry.js.map +1 -1
- package/dist/ai/provider.d.ts +5 -7
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/ai/provider.js +29 -0
- package/dist/ai/provider.js.map +1 -1
- package/dist/ai/types/enums.d.ts +2 -0
- package/dist/ai/types/fields.d.ts +7 -0
- package/dist/ai/types/prompt.d.ts +8 -0
- package/dist/ai/validation.d.ts.map +1 -1
- package/dist/ai/validation.js +10 -1
- package/dist/ai/validation.js.map +1 -1
- package/dist/api/exposure.d.ts +14 -0
- package/dist/api/exposure.d.ts.map +1 -1
- package/dist/api/exposure.js +16 -0
- package/dist/api/exposure.js.map +1 -1
- package/dist/api/idempotency.d.ts +67 -0
- package/dist/api/idempotency.d.ts.map +1 -0
- package/dist/api/idempotency.js +176 -0
- package/dist/api/idempotency.js.map +1 -0
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +4 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/route-generator.d.ts +50 -6
- package/dist/api/route-generator.d.ts.map +1 -1
- package/dist/api/route-generator.js +254 -12
- package/dist/api/route-generator.js.map +1 -1
- package/dist/approvals/action-risk.d.ts +41 -0
- package/dist/approvals/action-risk.d.ts.map +1 -0
- package/dist/approvals/action-risk.js +56 -0
- package/dist/approvals/action-risk.js.map +1 -0
- package/dist/approvals/actors.d.ts +8 -0
- package/dist/approvals/actors.d.ts.map +1 -0
- package/dist/approvals/actors.js +26 -0
- package/dist/approvals/actors.js.map +1 -0
- package/dist/approvals/authorization.d.ts +5 -0
- package/dist/approvals/authorization.d.ts.map +1 -0
- package/dist/approvals/authorization.js +16 -0
- package/dist/approvals/authorization.js.map +1 -0
- package/dist/approvals/digest.d.ts +3 -0
- package/dist/approvals/digest.d.ts.map +1 -0
- package/dist/approvals/digest.js +21 -0
- package/dist/approvals/digest.js.map +1 -0
- package/dist/approvals/gate.d.ts +15 -0
- package/dist/approvals/gate.d.ts.map +1 -0
- package/dist/approvals/gate.js +102 -0
- package/dist/approvals/gate.js.map +1 -0
- package/dist/approvals/host-runtime.d.ts +16 -0
- package/dist/approvals/host-runtime.d.ts.map +1 -0
- package/dist/approvals/host-runtime.js +12 -0
- package/dist/approvals/host-runtime.js.map +1 -0
- package/dist/approvals/index.d.ts +19 -0
- package/dist/approvals/index.d.ts.map +1 -0
- package/dist/approvals/index.js +13 -0
- package/dist/approvals/index.js.map +1 -0
- package/dist/approvals/memory-store.d.ts +3 -0
- package/dist/approvals/memory-store.d.ts.map +1 -0
- package/dist/approvals/memory-store.js +33 -0
- package/dist/approvals/memory-store.js.map +1 -0
- package/dist/approvals/schema.d.ts +484 -0
- package/dist/approvals/schema.d.ts.map +1 -0
- package/dist/approvals/schema.js +55 -0
- package/dist/approvals/schema.js.map +1 -0
- package/dist/approvals/service.d.ts +17 -0
- package/dist/approvals/service.d.ts.map +1 -0
- package/dist/approvals/service.js +240 -0
- package/dist/approvals/service.js.map +1 -0
- package/dist/approvals/sql-store.d.ts +9 -0
- package/dist/approvals/sql-store.d.ts.map +1 -0
- package/dist/approvals/sql-store.js +179 -0
- package/dist/approvals/sql-store.js.map +1 -0
- package/dist/approvals/types.d.ts +156 -0
- package/dist/approvals/types.d.ts.map +1 -0
- package/dist/approvals/types.js +32 -0
- package/dist/approvals/types.js.map +1 -0
- package/dist/approvals/wait.d.ts +10 -0
- package/dist/approvals/wait.d.ts.map +1 -0
- package/dist/approvals/wait.js +11 -0
- package/dist/approvals/wait.js.map +1 -0
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +2 -1
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/commands/api.d.ts +65 -0
- package/dist/cli/commands/api.d.ts.map +1 -1
- package/dist/cli/commands/api.js +79 -4
- package/dist/cli/commands/api.js.map +1 -1
- package/dist/cli/commands/compile-flows.d.ts +9 -0
- package/dist/cli/commands/compile-flows.d.ts.map +1 -0
- package/dist/cli/commands/compile-flows.js +55 -0
- package/dist/cli/commands/compile-flows.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +6 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +22 -5
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/e2e.d.ts +5 -0
- package/dist/cli/commands/e2e.d.ts.map +1 -1
- package/dist/cli/commands/e2e.js +42 -3
- package/dist/cli/commands/e2e.js.map +1 -1
- package/dist/cli/commands/flow.d.ts.map +1 -1
- package/dist/cli/commands/flow.js +12 -3
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/generate-openapi-from-zod.d.ts +26 -0
- package/dist/cli/commands/generate-openapi-from-zod.d.ts.map +1 -0
- package/dist/cli/commands/generate-openapi-from-zod.js +189 -0
- package/dist/cli/commands/generate-openapi-from-zod.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +10 -4
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +27 -70
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +2 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts +5 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +28 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/migrate.d.ts +1 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +145 -34
- package/dist/cli/commands/migrate.js.map +1 -1
- package/dist/cli/commands/openapi-3-1.d.ts +34 -0
- package/dist/cli/commands/openapi-3-1.d.ts.map +1 -0
- package/dist/cli/commands/openapi-3-1.js +333 -0
- package/dist/cli/commands/openapi-3-1.js.map +1 -0
- package/dist/cli/commands/start.d.ts +5 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +20 -2
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/ui.d.ts +11 -0
- package/dist/cli/commands/ui.d.ts.map +1 -1
- package/dist/cli/commands/ui.js +105 -20
- package/dist/cli/commands/ui.js.map +1 -1
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +2 -0
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/commands/worker.d.ts +5 -0
- package/dist/cli/commands/worker.d.ts.map +1 -1
- package/dist/cli/commands/worker.js +18 -2
- package/dist/cli/commands/worker.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/credentials/catalog.d.ts +71 -0
- package/dist/credentials/catalog.d.ts.map +1 -0
- package/dist/credentials/catalog.js +293 -0
- package/dist/credentials/catalog.js.map +1 -0
- package/dist/credentials/index.d.ts +3 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/data/drift-inspector.d.ts +1 -4
- package/dist/data/drift-inspector.d.ts.map +1 -1
- package/dist/data/drift-inspector.js +39 -5
- package/dist/data/drift-inspector.js.map +1 -1
- package/dist/data/field-encryption.d.ts +7 -0
- package/dist/data/field-encryption.d.ts.map +1 -1
- package/dist/data/field-encryption.js +35 -17
- package/dist/data/field-encryption.js.map +1 -1
- package/dist/data/framework-migration-rewriter.js +1 -1
- package/dist/data/framework-migration-rewriter.js.map +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +1 -1
- package/dist/data/index.js.map +1 -1
- package/dist/data/mask-fields.d.ts +2 -0
- package/dist/data/mask-fields.d.ts.map +1 -1
- package/dist/data/mask-fields.js +6 -0
- package/dist/data/mask-fields.js.map +1 -1
- package/dist/data/migration.d.ts.map +1 -1
- package/dist/data/migration.js +25 -1
- package/dist/data/migration.js.map +1 -1
- package/dist/data/repository.d.ts.map +1 -1
- package/dist/data/repository.js +15 -3
- package/dist/data/repository.js.map +1 -1
- package/dist/data/schema-generator.d.ts +95 -3
- package/dist/data/schema-generator.d.ts.map +1 -1
- package/dist/data/schema-generator.js +122 -6
- package/dist/data/schema-generator.js.map +1 -1
- package/dist/define/defineCapability.d.ts +7 -0
- package/dist/define/defineCapability.d.ts.map +1 -1
- package/dist/define/defineCapability.js +15 -0
- package/dist/define/defineCapability.js.map +1 -1
- package/dist/define/defineFlow.d.ts +3 -1
- package/dist/define/defineFlow.d.ts.map +1 -1
- package/dist/define/defineFlow.js.map +1 -1
- package/dist/durable/apply-ddl.d.ts +13 -0
- package/dist/durable/apply-ddl.d.ts.map +1 -0
- package/dist/durable/apply-ddl.js +278 -0
- package/dist/durable/apply-ddl.js.map +1 -0
- package/dist/durable/harness.d.ts +31 -0
- package/dist/durable/harness.d.ts.map +1 -0
- package/dist/durable/harness.js +136 -0
- package/dist/durable/harness.js.map +1 -0
- package/dist/durable/index.d.ts +18 -0
- package/dist/durable/index.d.ts.map +1 -0
- package/dist/durable/index.js +16 -0
- package/dist/durable/index.js.map +1 -0
- package/dist/durable/memory-store.d.ts +48 -0
- package/dist/durable/memory-store.d.ts.map +1 -0
- package/dist/durable/memory-store.js +260 -0
- package/dist/durable/memory-store.js.map +1 -0
- package/dist/durable/migrations-path.d.ts +5 -0
- package/dist/durable/migrations-path.d.ts.map +1 -0
- package/dist/durable/migrations-path.js +8 -0
- package/dist/durable/migrations-path.js.map +1 -0
- package/dist/durable/opaque-dispatch.d.ts +7 -0
- package/dist/durable/opaque-dispatch.d.ts.map +1 -0
- package/dist/durable/opaque-dispatch.js +67 -0
- package/dist/durable/opaque-dispatch.js.map +1 -0
- package/dist/durable/persist-before-ack.d.ts +52 -0
- package/dist/durable/persist-before-ack.d.ts.map +1 -0
- package/dist/durable/persist-before-ack.js +153 -0
- package/dist/durable/persist-before-ack.js.map +1 -0
- package/dist/durable/pg-env.d.ts +9 -0
- package/dist/durable/pg-env.d.ts.map +1 -0
- package/dist/durable/pg-env.js +20 -0
- package/dist/durable/pg-env.js.map +1 -0
- package/dist/durable/postgres-persist.d.ts +33 -0
- package/dist/durable/postgres-persist.d.ts.map +1 -0
- package/dist/durable/postgres-persist.js +239 -0
- package/dist/durable/postgres-persist.js.map +1 -0
- package/dist/durable/reconciliation.d.ts +20 -0
- package/dist/durable/reconciliation.d.ts.map +1 -0
- package/dist/durable/reconciliation.js +91 -0
- package/dist/durable/reconciliation.js.map +1 -0
- package/dist/durable/schema.d.ts +1448 -0
- package/dist/durable/schema.d.ts.map +1 -0
- package/dist/durable/schema.js +138 -0
- package/dist/durable/schema.js.map +1 -0
- package/dist/durable/spine-claim.d.ts +16 -0
- package/dist/durable/spine-claim.d.ts.map +1 -0
- package/dist/durable/spine-claim.js +131 -0
- package/dist/durable/spine-claim.js.map +1 -0
- package/dist/durable/types.d.ts +153 -0
- package/dist/durable/types.d.ts.map +1 -0
- package/dist/durable/types.js +114 -0
- package/dist/durable/types.js.map +1 -0
- package/dist/errors/data-errors.d.ts +6 -0
- package/dist/errors/data-errors.d.ts.map +1 -1
- package/dist/errors/data-errors.js +9 -0
- package/dist/errors/data-errors.js.map +1 -1
- package/dist/errors/index.d.ts +4 -1
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +11 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/errors-entry.d.ts +1 -1
- package/dist/errors-entry.d.ts.map +1 -1
- package/dist/errors-entry.js +1 -1
- package/dist/errors-entry.js.map +1 -1
- package/dist/events/consumer-registry.d.ts +6 -0
- package/dist/events/consumer-registry.d.ts.map +1 -1
- package/dist/events/consumer-registry.js.map +1 -1
- package/dist/events/dispatcher.d.ts +19 -0
- package/dist/events/dispatcher.d.ts.map +1 -1
- package/dist/events/dispatcher.js +161 -114
- package/dist/events/dispatcher.js.map +1 -1
- package/dist/events/idempotency.d.ts +3 -2
- package/dist/events/idempotency.d.ts.map +1 -1
- package/dist/events/idempotency.js +3 -2
- package/dist/events/idempotency.js.map +1 -1
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +1 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/subscription.d.ts +29 -0
- package/dist/events/subscription.d.ts.map +1 -0
- package/dist/events/subscription.js +19 -0
- package/dist/events/subscription.js.map +1 -0
- package/dist/events/worker.d.ts +8 -1
- package/dist/events/worker.d.ts.map +1 -1
- package/dist/events/worker.js +32 -5
- package/dist/events/worker.js.map +1 -1
- package/dist/execution/capability-executor.d.ts +6 -3
- package/dist/execution/capability-executor.d.ts.map +1 -1
- package/dist/execution/capability-executor.js +34 -6
- package/dist/execution/capability-executor.js.map +1 -1
- package/dist/execution/context-deps.d.ts +2 -0
- package/dist/execution/context-deps.d.ts.map +1 -1
- package/dist/execution/context-deps.js +2 -1
- package/dist/execution/context-deps.js.map +1 -1
- package/dist/execution/context-factory.d.ts +38 -1
- package/dist/execution/context-factory.d.ts.map +1 -1
- package/dist/execution/context-factory.js +102 -4
- package/dist/execution/context-factory.js.map +1 -1
- package/dist/execution/index.d.ts +2 -2
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +1 -1
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/transactional-outbox.d.ts +10 -0
- package/dist/execution/transactional-outbox.d.ts.map +1 -1
- package/dist/execution/transactional-outbox.js +41 -2
- package/dist/execution/transactional-outbox.js.map +1 -1
- package/dist/flows/budget.d.ts +44 -0
- package/dist/flows/budget.d.ts.map +1 -0
- package/dist/flows/budget.js +81 -0
- package/dist/flows/budget.js.map +1 -0
- package/dist/flows/compile-flow.d.ts +23 -0
- package/dist/flows/compile-flow.d.ts.map +1 -0
- package/dist/flows/compile-flow.js +176 -0
- package/dist/flows/compile-flow.js.map +1 -0
- package/dist/flows/compiled-registry.d.ts +43 -0
- package/dist/flows/compiled-registry.d.ts.map +1 -0
- package/dist/flows/compiled-registry.js +198 -0
- package/dist/flows/compiled-registry.js.map +1 -0
- package/dist/flows/dead-letter.d.ts +16 -0
- package/dist/flows/dead-letter.d.ts.map +1 -1
- package/dist/flows/dead-letter.js +67 -0
- package/dist/flows/dead-letter.js.map +1 -1
- package/dist/flows/definition-strategy.d.ts +13 -0
- package/dist/flows/definition-strategy.d.ts.map +1 -0
- package/dist/flows/definition-strategy.js +30 -0
- package/dist/flows/definition-strategy.js.map +1 -0
- package/dist/flows/engine.d.ts +38 -1
- package/dist/flows/engine.d.ts.map +1 -1
- package/dist/flows/engine.js +375 -32
- package/dist/flows/engine.js.map +1 -1
- package/dist/flows/index.d.ts +12 -4
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +7 -2
- package/dist/flows/index.js.map +1 -1
- package/dist/flows/scheduler.d.ts +26 -0
- package/dist/flows/scheduler.d.ts.map +1 -1
- package/dist/flows/scheduler.js +157 -37
- package/dist/flows/scheduler.js.map +1 -1
- package/dist/flows/schema.d.ts +34 -0
- package/dist/flows/schema.d.ts.map +1 -1
- package/dist/flows/schema.js +4 -0
- package/dist/flows/schema.js.map +1 -1
- package/dist/flows/step-executor.d.ts +3 -0
- package/dist/flows/step-executor.d.ts.map +1 -1
- package/dist/flows/step-executor.js +33 -0
- package/dist/flows/step-executor.js.map +1 -1
- package/dist/governance/capability-source-scan.d.ts.map +1 -1
- package/dist/governance/capability-source-scan.js +2 -29
- package/dist/governance/capability-source-scan.js.map +1 -1
- package/dist/governance/forbidden-path-scan.d.ts +7 -0
- package/dist/governance/forbidden-path-scan.d.ts.map +1 -0
- package/dist/governance/forbidden-path-scan.js +60 -0
- package/dist/governance/forbidden-path-scan.js.map +1 -0
- package/dist/governance/index.d.ts +2 -0
- package/dist/governance/index.d.ts.map +1 -1
- package/dist/governance/index.js +2 -0
- package/dist/governance/index.js.map +1 -1
- package/dist/governance/source-walk.d.ts +3 -0
- package/dist/governance/source-walk.d.ts.map +1 -0
- package/dist/governance/source-walk.js +33 -0
- package/dist/governance/source-walk.js.map +1 -0
- package/dist/index.d.ts +21 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -9
- package/dist/index.js.map +1 -1
- package/dist/runtime/bootstrap.d.ts +3 -1
- package/dist/runtime/bootstrap.d.ts.map +1 -1
- package/dist/runtime/load-extensions.d.ts.map +1 -1
- package/dist/runtime/load-extensions.js +11 -0
- package/dist/runtime/load-extensions.js.map +1 -1
- package/dist/runtime/register-consumers.d.ts +3 -0
- package/dist/runtime/register-consumers.d.ts.map +1 -1
- package/dist/runtime/register-consumers.js +4 -0
- package/dist/runtime/register-consumers.js.map +1 -1
- package/dist/runtime/start-worker-pool.d.ts.map +1 -1
- package/dist/runtime/start-worker-pool.js +1 -0
- package/dist/runtime/start-worker-pool.js.map +1 -1
- package/dist/runtime-entry.d.ts +4 -0
- package/dist/runtime-entry.d.ts.map +1 -0
- package/dist/runtime-entry.js +30 -0
- package/dist/runtime-entry.js.map +1 -0
- package/dist/server/bootstrap.d.ts +116 -8
- package/dist/server/bootstrap.d.ts.map +1 -1
- package/dist/server/bootstrap.js +139 -62
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/tenancy/data-plane-connection.d.ts +108 -0
- package/dist/tenancy/data-plane-connection.d.ts.map +1 -0
- package/dist/tenancy/data-plane-connection.js +320 -0
- package/dist/tenancy/data-plane-connection.js.map +1 -0
- package/dist/tenancy/data-plane-migrate.d.ts +30 -0
- package/dist/tenancy/data-plane-migrate.d.ts.map +1 -0
- package/dist/tenancy/data-plane-migrate.js +44 -0
- package/dist/tenancy/data-plane-migrate.js.map +1 -0
- package/dist/tenancy/data-plane-provisioning.d.ts +135 -0
- package/dist/tenancy/data-plane-provisioning.d.ts.map +1 -0
- package/dist/tenancy/data-plane-provisioning.js +639 -0
- package/dist/tenancy/data-plane-provisioning.js.map +1 -0
- package/dist/tenancy/data-plane-resolver.d.ts +37 -0
- package/dist/tenancy/data-plane-resolver.d.ts.map +1 -0
- package/dist/tenancy/data-plane-resolver.js +302 -0
- package/dist/tenancy/data-plane-resolver.js.map +1 -0
- package/dist/tenancy/index.d.ts +9 -0
- package/dist/tenancy/index.d.ts.map +1 -0
- package/dist/tenancy/index.js +22 -0
- package/dist/tenancy/index.js.map +1 -0
- package/dist/tenancy/types.d.ts +117 -0
- package/dist/tenancy/types.d.ts.map +1 -0
- package/dist/tenancy/types.js +8 -0
- package/dist/tenancy/types.js.map +1 -0
- package/dist/testing/context.d.ts.map +1 -1
- package/dist/testing/context.js +6 -1
- package/dist/testing/context.js.map +1 -1
- package/dist/testing/crash-matrix-simulation.d.ts +51 -0
- package/dist/testing/crash-matrix-simulation.d.ts.map +1 -0
- package/dist/testing/crash-matrix-simulation.js +350 -0
- package/dist/testing/crash-matrix-simulation.js.map +1 -0
- package/dist/testing/scaffolding.d.ts.map +1 -1
- package/dist/testing/scaffolding.js +4 -1
- package/dist/testing/scaffolding.js.map +1 -1
- package/dist/types/capability.d.ts +16 -0
- package/dist/types/capability.d.ts.map +1 -1
- package/dist/types/capability.js.map +1 -1
- package/dist/types/context.d.ts +62 -0
- package/dist/types/context.d.ts.map +1 -1
- package/dist/types/enums.d.ts +2 -0
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/enums.js +2 -0
- package/dist/types/enums.js.map +1 -1
- package/dist/types/fields.d.ts +7 -0
- package/dist/types/fields.d.ts.map +1 -1
- package/dist/types/flow.d.ts +96 -1
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/flow.js +7 -1
- package/dist/types/flow.js.map +1 -1
- package/dist/types/index.d.ts +9 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +5 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/prompt.d.ts +8 -0
- package/dist/types/prompt.d.ts.map +1 -1
- package/dist/types/prompt.js +7 -0
- package/dist/types/prompt.js.map +1 -1
- package/dist/worker/bootstrap.d.ts +100 -1
- package/dist/worker/bootstrap.d.ts.map +1 -1
- package/dist/worker/bootstrap.js +155 -14
- package/dist/worker/bootstrap.js.map +1 -1
- package/instructions/api.md +21 -0
- package/instructions/cli.md +15 -9
- package/instructions/deployment.md +27 -25
- package/instructions/flows.md +8 -1
- package/instructions/framework.md +2 -1
- package/instructions/mcp.md +1 -1
- package/instructions/peer-dependencies.md +16 -14
- package/instructions/prompts.md +3 -0
- package/instructions/security.md +4 -0
- package/instructions/testing.md +2 -2
- package/migrations/durable-tenant/0000_durable_tenant.sql +92 -0
- package/migrations/durable-tenant/0001_human_task.sql +45 -0
- package/migrations/durable-tenant/meta/_journal.json +20 -0
- package/migrations/spine/0000_opaque_dispatch.sql +26 -0
- package/migrations/spine/meta/_journal.json +13 -0
- package/package.json +26 -8
package/dist/flows/engine.js
CHANGED
|
@@ -3,8 +3,13 @@ import { and, eq, inArray, isNull, lte, or, sql } from 'drizzle-orm';
|
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { hostname } from 'node:os';
|
|
5
5
|
import { parseDurationToMs } from '../config/duration.js';
|
|
6
|
-
import { FlowCancelledError, LeaseLostError } from '../errors/index.js';
|
|
7
|
-
import {
|
|
6
|
+
import { FlowCancelledError, LeaseLostError, PlumbusError } from '../errors/index.js';
|
|
7
|
+
import { BUDGET_EXHAUSTED, consumeExecutionBudget, createExecutionBudgetLedger, writeExecutionBudget, } from './budget.js';
|
|
8
|
+
import { BackoffStrategy, ErrorCode, FlowStepType } from '../types/enums.js';
|
|
9
|
+
import { FRAMEWORK_SCHEMA } from '../data/schema-generator.js';
|
|
10
|
+
import { ackSpineDispatch, casAdvanceExecution, claimSpineDispatch, insertDispatchOutbox, loadExecutionState, persistAcceptanceOnDb, publishOutboxToSpine, } from '../durable/index.js';
|
|
11
|
+
import { flowDefinitionId, hydrateCompiledFlow } from './compile-flow.js';
|
|
12
|
+
import { assertSupportedDefinitionStrategy, DefinitionInFlightStrategy, } from './definition-strategy.js';
|
|
8
13
|
import { flowExecutionsTable } from './schema.js';
|
|
9
14
|
import { assertTransition, FlowStatus, isTerminal, StepStatus, } from './state-machine.js';
|
|
10
15
|
import { buildHistoryEntry, executeStep, } from './step-executor.js';
|
|
@@ -68,13 +73,71 @@ export function generateWorkerId() {
|
|
|
68
73
|
* across multiple workers sharing the same database.
|
|
69
74
|
*/
|
|
70
75
|
export function createFlowEngine(config) {
|
|
71
|
-
const { db, registry,
|
|
76
|
+
const { db, registry, audit, onFlowError, createEventService } = config;
|
|
77
|
+
const compiledRegistry = config.compiledRegistry;
|
|
78
|
+
const approvals = config.approvals;
|
|
79
|
+
const stepDeps = {
|
|
80
|
+
...config.stepDeps,
|
|
81
|
+
findApprovalForExecution: config.stepDeps.findApprovalForExecution ??
|
|
82
|
+
(approvals ? (executionId) => approvals.findByExecutionId(executionId) : undefined),
|
|
83
|
+
};
|
|
72
84
|
const workerId = config.workerId ?? generateWorkerId();
|
|
73
85
|
const leaseDurationMs = config.flowLeaseDurationMs ?? DEFAULT_LEASE_DURATION_MS;
|
|
74
86
|
const heartbeatIntervalMs = config.flowHeartbeatIntervalMs ?? Math.floor(leaseDurationMs / 3);
|
|
75
87
|
const claimBatchSize = config.flowClaimBatchSize ?? DEFAULT_CLAIM_BATCH_SIZE;
|
|
76
88
|
const logger = config.logger;
|
|
77
89
|
const onFlowStepEnqueue = config.onFlowStepEnqueue;
|
|
90
|
+
const spineDispatch = config.spineDispatch;
|
|
91
|
+
const durableSchema = spineDispatch?.coreSchema ?? FRAMEWORK_SCHEMA;
|
|
92
|
+
const executionStores = new Map();
|
|
93
|
+
const claimedHints = new Map();
|
|
94
|
+
const executionPins = new Map();
|
|
95
|
+
function restorePinFromRow(row) {
|
|
96
|
+
if (executionPins.has(row.id))
|
|
97
|
+
return;
|
|
98
|
+
if (!row.definitionVersion)
|
|
99
|
+
return;
|
|
100
|
+
executionPins.set(row.id, {
|
|
101
|
+
flowDefinitionId: flowDefinitionId({ domain: row.domain, name: row.flowName }),
|
|
102
|
+
definitionVersion: row.definitionVersion,
|
|
103
|
+
definitionDigest: row.definitionDigest ?? undefined,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function resolveCompiledForStart(flow) {
|
|
107
|
+
if (!compiledRegistry)
|
|
108
|
+
return undefined;
|
|
109
|
+
const id = flowDefinitionId(flow);
|
|
110
|
+
const compiled = compiledRegistry.getLatest(id);
|
|
111
|
+
if (!compiled) {
|
|
112
|
+
throw new PlumbusError(ErrorCode.NotFound, `compiled definition required for "${id}"`, {
|
|
113
|
+
reason: 'compiled-definition-required',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return compiled;
|
|
117
|
+
}
|
|
118
|
+
function resolveExecutionFlow(executionId, flowName) {
|
|
119
|
+
const authoring = registry.get(flowName);
|
|
120
|
+
if (!authoring) {
|
|
121
|
+
throw new Error(`Flow "${flowName}" is not registered`);
|
|
122
|
+
}
|
|
123
|
+
if (!compiledRegistry)
|
|
124
|
+
return authoring;
|
|
125
|
+
const pin = executionPins.get(executionId);
|
|
126
|
+
if (!pin) {
|
|
127
|
+
throw new PlumbusError(ErrorCode.NotFound, `Flow "${flowName}" has no pinned compiled definition`, { reason: 'compiled-definition-missing', executionId });
|
|
128
|
+
}
|
|
129
|
+
const compiled = compiledRegistry.get(pin.flowDefinitionId, pin.definitionVersion);
|
|
130
|
+
if (!compiled) {
|
|
131
|
+
throw new PlumbusError(ErrorCode.NotFound, `compiled definition "${pin.flowDefinitionId}@${pin.definitionVersion}" is not in the registry`, { reason: 'compiled-definition-missing' });
|
|
132
|
+
}
|
|
133
|
+
if (pin.definitionDigest && compiled.definitionDigest !== pin.definitionDigest) {
|
|
134
|
+
throw new PlumbusError(ErrorCode.Conflict, `compiled definition digest mismatch for "${pin.flowDefinitionId}@${pin.definitionVersion}"`, { reason: 'compiled-definition-digest-mismatch' });
|
|
135
|
+
}
|
|
136
|
+
return hydrateCompiledFlow(compiled, authoring);
|
|
137
|
+
}
|
|
138
|
+
function storeFor(executionId) {
|
|
139
|
+
return executionStores.get(executionId) ?? db;
|
|
140
|
+
}
|
|
78
141
|
const onFlowDelayedSchedule = config.onFlowDelayedSchedule;
|
|
79
142
|
async function maybeEnqueueFlowStep(executionId, correlationId) {
|
|
80
143
|
if (onFlowStepEnqueue) {
|
|
@@ -103,26 +166,56 @@ export function createFlowEngine(config) {
|
|
|
103
166
|
throw new Error(`Flow "${flowName}": invalid input — ${parseResult.error.message}`);
|
|
104
167
|
}
|
|
105
168
|
const executionId = opts?.executionId ?? randomUUID();
|
|
106
|
-
const
|
|
169
|
+
const compiled = resolveCompiledForStart(flow);
|
|
170
|
+
const executionFlow = compiled ? hydrateCompiledFlow(compiled, flow) : flow;
|
|
171
|
+
const definitionVersion = compiled?.definitionVersion ?? '0.0.0';
|
|
172
|
+
if (compiled) {
|
|
173
|
+
executionPins.set(executionId, {
|
|
174
|
+
flowDefinitionId: compiled.flowDefinitionId,
|
|
175
|
+
definitionVersion: compiled.definitionVersion,
|
|
176
|
+
definitionDigest: compiled.definitionDigest,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
let initialState = flow.state
|
|
107
180
|
? (() => {
|
|
108
181
|
const parsed = flow.state.safeParse({});
|
|
109
182
|
return parsed.success ? parsed.data : {};
|
|
110
183
|
})()
|
|
111
184
|
: null;
|
|
112
|
-
|
|
185
|
+
if (flow.budget) {
|
|
186
|
+
initialState = writeExecutionBudget(initialState, createExecutionBudgetLedger({
|
|
187
|
+
executionId,
|
|
188
|
+
profileId: flow.budget.profileId,
|
|
189
|
+
allocated: flow.budget.allocated,
|
|
190
|
+
unitId: flow.budget.unitId,
|
|
191
|
+
dimensionId: flow.budget.dimensionId,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
let writeDb = db;
|
|
195
|
+
if (spineDispatch) {
|
|
196
|
+
if (!auth.tenantId) {
|
|
197
|
+
throw new PlumbusError(ErrorCode.Forbidden, 'spine dispatch requires a tenant reference on flow start', { reason: 'untenanted-flow-start' });
|
|
198
|
+
}
|
|
199
|
+
const handle = await spineDispatch.resolver.resolve(auth.tenantId);
|
|
200
|
+
writeDb = handle.db;
|
|
201
|
+
executionStores.set(executionId, writeDb);
|
|
202
|
+
}
|
|
203
|
+
await writeDb.insert(flowExecutionsTable).values({
|
|
113
204
|
id: executionId,
|
|
114
205
|
flowName,
|
|
115
206
|
domain: flow.domain,
|
|
116
207
|
status: FlowStatus.Created,
|
|
117
208
|
input: parseResult.data,
|
|
118
209
|
state: initialState,
|
|
119
|
-
currentStep:
|
|
210
|
+
currentStep: executionFlow.steps[0]?.name ?? null,
|
|
120
211
|
stepHistory: [],
|
|
121
212
|
actor: auth.userId ?? 'system',
|
|
122
213
|
tenantId: auth.tenantId ?? null,
|
|
123
214
|
authSnapshotJson: flowAuthSchema.parse(auth),
|
|
124
215
|
correlationId: opts?.correlationId ?? null,
|
|
125
216
|
triggerEventId: opts?.triggerEventId ?? null,
|
|
217
|
+
definitionVersion: compiled?.definitionVersion ?? null,
|
|
218
|
+
definitionDigest: compiled?.definitionDigest ?? null,
|
|
126
219
|
});
|
|
127
220
|
if (audit) {
|
|
128
221
|
await audit.record(`flow.started.${flowName}`, {
|
|
@@ -134,6 +227,20 @@ export function createFlowEngine(config) {
|
|
|
134
227
|
});
|
|
135
228
|
}
|
|
136
229
|
await maybeEnqueueFlowStep(executionId, opts?.correlationId);
|
|
230
|
+
if (spineDispatch && auth.tenantId) {
|
|
231
|
+
const nowIso = new Date().toISOString();
|
|
232
|
+
const firstStepId = executionFlow.steps[0]?.name ?? 'terminal';
|
|
233
|
+
const accepted = await persistAcceptanceOnDb(writeDb, {
|
|
234
|
+
executionId,
|
|
235
|
+
tenantRef: auth.tenantId,
|
|
236
|
+
definitionId: flowName,
|
|
237
|
+
definitionVersion,
|
|
238
|
+
firstStepId,
|
|
239
|
+
correlationId: opts?.correlationId ?? executionId,
|
|
240
|
+
nowIso,
|
|
241
|
+
}, durableSchema);
|
|
242
|
+
await publishOutboxToSpine(writeDb, spineDispatch.db, accepted.outbox, `disp:${executionId}:1`, nowIso, durableSchema);
|
|
243
|
+
}
|
|
137
244
|
return {
|
|
138
245
|
id: executionId,
|
|
139
246
|
flowName,
|
|
@@ -145,7 +252,67 @@ export function createFlowEngine(config) {
|
|
|
145
252
|
* Uses FOR UPDATE SKIP LOCKED so concurrent workers each get different rows.
|
|
146
253
|
* Also reclaims rows whose lease has expired (crash recovery).
|
|
147
254
|
*/
|
|
255
|
+
async function claimNextFromSpine(batchSize) {
|
|
256
|
+
if (!spineDispatch)
|
|
257
|
+
return [];
|
|
258
|
+
const hints = await claimSpineDispatch(spineDispatch.db, {
|
|
259
|
+
workerId,
|
|
260
|
+
leaseDurationMs,
|
|
261
|
+
limit: batchSize ?? claimBatchSize,
|
|
262
|
+
});
|
|
263
|
+
const rows = [];
|
|
264
|
+
for (const hint of hints) {
|
|
265
|
+
try {
|
|
266
|
+
const handle = await spineDispatch.resolver.resolve(hint.tenantRouteId);
|
|
267
|
+
const tenantState = await loadExecutionState(handle.db, hint.executionId, durableSchema);
|
|
268
|
+
if (!tenantState ||
|
|
269
|
+
tenantState.terminal ||
|
|
270
|
+
tenantState.revision !== hint.expectedRevision ||
|
|
271
|
+
tenantState.tenantEpoch !== hint.tenantEpoch) {
|
|
272
|
+
await ackSpineDispatch(spineDispatch.db, hint.dispatchId);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const execRows = await handle.db
|
|
276
|
+
.select()
|
|
277
|
+
.from(flowExecutionsTable)
|
|
278
|
+
.where(eq(flowExecutionsTable.id, hint.executionId))
|
|
279
|
+
.limit(1);
|
|
280
|
+
const row = execRows[0];
|
|
281
|
+
if (!row) {
|
|
282
|
+
await ackSpineDispatch(spineDispatch.db, hint.dispatchId);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
executionStores.set(hint.executionId, handle.db);
|
|
286
|
+
claimedHints.set(hint.executionId, hint);
|
|
287
|
+
await handle.db
|
|
288
|
+
.update(flowExecutionsTable)
|
|
289
|
+
.set({
|
|
290
|
+
status: FlowStatus.Running,
|
|
291
|
+
leaseOwner: workerId,
|
|
292
|
+
leaseExpiresAt: new Date(Date.now() + leaseDurationMs),
|
|
293
|
+
updatedAt: new Date(),
|
|
294
|
+
})
|
|
295
|
+
.where(eq(flowExecutionsTable.id, hint.executionId));
|
|
296
|
+
rows.push({
|
|
297
|
+
...row,
|
|
298
|
+
status: FlowStatus.Running,
|
|
299
|
+
leaseOwner: workerId,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
logger?.error('spine claim failed closed for one dispatch', {
|
|
304
|
+
dispatchId: hint.dispatchId,
|
|
305
|
+
executionId: hint.executionId,
|
|
306
|
+
error: error instanceof Error ? error.message : String(error),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return rows;
|
|
311
|
+
}
|
|
148
312
|
async function claimNext(batchSize) {
|
|
313
|
+
if (spineDispatch) {
|
|
314
|
+
return claimNextFromSpine(batchSize);
|
|
315
|
+
}
|
|
149
316
|
const limit = batchSize ?? claimBatchSize;
|
|
150
317
|
const leaseDurationInterval = `${leaseDurationMs} milliseconds`;
|
|
151
318
|
const result = await db.execute(sql `
|
|
@@ -235,7 +402,7 @@ export function createFlowEngine(config) {
|
|
|
235
402
|
*/
|
|
236
403
|
async function extendLease(executionId) {
|
|
237
404
|
const leaseDurationInterval = `${leaseDurationMs} milliseconds`;
|
|
238
|
-
const result = await
|
|
405
|
+
const result = await storeFor(executionId)
|
|
239
406
|
.update(flowExecutionsTable)
|
|
240
407
|
.set({
|
|
241
408
|
leaseExpiresAt: sql `now() + ${leaseDurationInterval}::interval`,
|
|
@@ -251,7 +418,7 @@ export function createFlowEngine(config) {
|
|
|
251
418
|
// tell at a glance which dimension diverged. Best-effort: a failure
|
|
252
419
|
// here must not break the heartbeat.
|
|
253
420
|
try {
|
|
254
|
-
const rows = await
|
|
421
|
+
const rows = await storeFor(executionId)
|
|
255
422
|
.select({
|
|
256
423
|
status: flowExecutionsTable.status,
|
|
257
424
|
leaseOwner: flowExecutionsTable.leaseOwner,
|
|
@@ -294,7 +461,12 @@ export function createFlowEngine(config) {
|
|
|
294
461
|
* The execution must have been claimed by this worker (via claimNext) first.
|
|
295
462
|
*/
|
|
296
463
|
async function runNext(executionId, ctx) {
|
|
297
|
-
const
|
|
464
|
+
const result = await runNextUnsynced(executionId, ctx);
|
|
465
|
+
await syncSpineAfterRun(executionId, result);
|
|
466
|
+
return result;
|
|
467
|
+
}
|
|
468
|
+
async function runNextUnsynced(executionId, ctx) {
|
|
469
|
+
const rows = await storeFor(executionId)
|
|
298
470
|
.select()
|
|
299
471
|
.from(flowExecutionsTable)
|
|
300
472
|
.where(eq(flowExecutionsTable.id, executionId))
|
|
@@ -306,10 +478,8 @@ export function createFlowEngine(config) {
|
|
|
306
478
|
if (isTerminal(row.status)) {
|
|
307
479
|
return { id: row.id, flowName: row.flowName, status: row.status };
|
|
308
480
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
throw new Error(`Flow "${row.flowName}" is not registered`);
|
|
312
|
-
}
|
|
481
|
+
restorePinFromRow(row);
|
|
482
|
+
const flow = resolveExecutionFlow(executionId, row.flowName);
|
|
313
483
|
// Do not auto-run event waits, and do not run delayed waits until due.
|
|
314
484
|
if (row.status === FlowStatus.Waiting && row.waitingForEvent) {
|
|
315
485
|
return { id: row.id, flowName: row.flowName, status: FlowStatus.Waiting };
|
|
@@ -340,6 +510,19 @@ export function createFlowEngine(config) {
|
|
|
340
510
|
await failFlow(executionId, row.flowName, `Step "${currentStepName}" not found in flow definition`, row);
|
|
341
511
|
return { id: executionId, flowName: row.flowName, status: FlowStatus.Failed };
|
|
342
512
|
}
|
|
513
|
+
if (step.type === FlowStepType.Capability) {
|
|
514
|
+
const charged = consumeExecutionBudget(row.state, 1);
|
|
515
|
+
if (charged) {
|
|
516
|
+
row.state = charged.state;
|
|
517
|
+
if (charged.exhausted) {
|
|
518
|
+
const history = Array.isArray(row.stepHistory)
|
|
519
|
+
? [...row.stepHistory]
|
|
520
|
+
: [];
|
|
521
|
+
return handleStepFailure(executionId, row, flow, history, BUDGET_EXHAUSTED);
|
|
522
|
+
}
|
|
523
|
+
await guardedUpdate(executionId, { state: charged.state });
|
|
524
|
+
}
|
|
525
|
+
}
|
|
343
526
|
// Build flow-scoped context from stored auth snapshot (not worker systemAuth roles)
|
|
344
527
|
const flowAuth = resolveFlowStepAuth(row);
|
|
345
528
|
if (!flowAuth) {
|
|
@@ -641,7 +824,7 @@ export function createFlowEngine(config) {
|
|
|
641
824
|
* Resume a waiting flow (e.g., after an event arrives or approval granted).
|
|
642
825
|
*/
|
|
643
826
|
async function resume(executionId, signal) {
|
|
644
|
-
const rows = await
|
|
827
|
+
const rows = await storeFor(executionId)
|
|
645
828
|
.select()
|
|
646
829
|
.from(flowExecutionsTable)
|
|
647
830
|
.where(eq(flowExecutionsTable.id, executionId))
|
|
@@ -652,9 +835,8 @@ export function createFlowEngine(config) {
|
|
|
652
835
|
if (row.status !== FlowStatus.Waiting) {
|
|
653
836
|
throw new Error(`Cannot resume flow "${executionId}" — current status is "${row.status}"`);
|
|
654
837
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
throw new Error(`Flow "${row.flowName}" not registered`);
|
|
838
|
+
restorePinFromRow(row);
|
|
839
|
+
const flow = resolveExecutionFlow(executionId, row.flowName);
|
|
658
840
|
// Advance past the wait/delay step — set to created so claimNext picks it up
|
|
659
841
|
const nextStep = getNextStepName(flow.steps, row.currentStep ?? '');
|
|
660
842
|
await updateExecution(executionId, {
|
|
@@ -716,10 +898,11 @@ export function createFlowEngine(config) {
|
|
|
716
898
|
return rows.map((row) => row.id);
|
|
717
899
|
}
|
|
718
900
|
/**
|
|
719
|
-
* Cancel a running or waiting flow.
|
|
901
|
+
* Cancel a running or waiting flow. Completed steps with `compensate`
|
|
902
|
+
* run their compensation capability first (recovery CompensationState v1).
|
|
720
903
|
*/
|
|
721
|
-
async function cancel(executionId) {
|
|
722
|
-
const rows = await
|
|
904
|
+
async function cancel(executionId, opts) {
|
|
905
|
+
const rows = await storeFor(executionId)
|
|
723
906
|
.select()
|
|
724
907
|
.from(flowExecutionsTable)
|
|
725
908
|
.where(eq(flowExecutionsTable.id, executionId))
|
|
@@ -730,30 +913,124 @@ export function createFlowEngine(config) {
|
|
|
730
913
|
if (isTerminal(row.status)) {
|
|
731
914
|
throw new Error(`Cannot cancel flow "${executionId}" — already in terminal state "${row.status}"`);
|
|
732
915
|
}
|
|
916
|
+
restorePinFromRow(row);
|
|
917
|
+
const flow = resolveExecutionFlow(executionId, row.flowName);
|
|
918
|
+
const history = Array.isArray(row.stepHistory)
|
|
919
|
+
? [...row.stepHistory]
|
|
920
|
+
: [];
|
|
921
|
+
// Abort the in-flight step before compensation so it cannot commit.
|
|
922
|
+
const activeAc = activeStepAborts.get(executionId);
|
|
923
|
+
if (activeAc && !activeAc.signal.aborted) {
|
|
924
|
+
activeAc.abort(new FlowCancelledError(executionId));
|
|
925
|
+
}
|
|
926
|
+
if (!opts?.skipCompensation) {
|
|
927
|
+
await runCompensations(executionId, row, flow, history);
|
|
928
|
+
}
|
|
733
929
|
assertTransition(row.status, FlowStatus.Cancelled);
|
|
734
930
|
await updateExecution(executionId, {
|
|
735
931
|
status: FlowStatus.Cancelled,
|
|
932
|
+
stepHistory: history,
|
|
736
933
|
completedAt: new Date(),
|
|
737
934
|
});
|
|
738
|
-
// Synchronously abort the step's AbortController if it is running in THIS
|
|
739
|
-
// engine instance. Cross-process cancellations still converge via the next
|
|
740
|
-
// heartbeat (which fails because status is no longer 'running').
|
|
741
|
-
const activeAc = activeStepAborts.get(executionId);
|
|
742
|
-
if (activeAc && !activeAc.signal.aborted) {
|
|
743
|
-
activeAc.abort(new FlowCancelledError(executionId));
|
|
744
|
-
}
|
|
745
935
|
if (audit) {
|
|
746
936
|
await audit.record(`flow.cancelled.${row.flowName}`, {
|
|
747
937
|
executionId,
|
|
748
938
|
flowName: row.flowName,
|
|
939
|
+
actor: opts?.actor ?? row.actor,
|
|
940
|
+
compensated: history.some((entry) => entry.step.startsWith('compensate:')),
|
|
749
941
|
});
|
|
750
942
|
}
|
|
751
943
|
}
|
|
944
|
+
async function terminate(executionId, opts) {
|
|
945
|
+
return cancel(executionId, { actor: opts?.actor, skipCompensation: true });
|
|
946
|
+
}
|
|
947
|
+
async function runCompensations(executionId, row, flow, history) {
|
|
948
|
+
const completed = new Set(history.filter((entry) => entry.status === StepStatus.Completed).map((entry) => entry.step));
|
|
949
|
+
const compensable = [...flow.steps]
|
|
950
|
+
.reverse()
|
|
951
|
+
.filter((step) => {
|
|
952
|
+
return (step.type === FlowStepType.Capability &&
|
|
953
|
+
typeof step.compensate === 'string' &&
|
|
954
|
+
step.compensate.length > 0 &&
|
|
955
|
+
completed.has(step.name));
|
|
956
|
+
});
|
|
957
|
+
if (compensable.length === 0)
|
|
958
|
+
return;
|
|
959
|
+
// Compensations run as the verified initiating identity, never as the
|
|
960
|
+
// worker. A missing or invalid snapshot is recorded and left for operator
|
|
961
|
+
// review, matching the step path above.
|
|
962
|
+
const flowAuth = resolveFlowStepAuth(row);
|
|
963
|
+
if (!flowAuth) {
|
|
964
|
+
const at = new Date();
|
|
965
|
+
history.push(buildHistoryEntry('compensate', {
|
|
966
|
+
status: StepStatus.Failed,
|
|
967
|
+
error: 'Missing or invalid flow auth snapshot; compensations require a verified caller context',
|
|
968
|
+
}, at, at));
|
|
969
|
+
if (audit) {
|
|
970
|
+
await audit.record('flow.compensation_skipped', {
|
|
971
|
+
executionId,
|
|
972
|
+
flowName: row.flowName,
|
|
973
|
+
reason: 'invalid-auth-snapshot',
|
|
974
|
+
steps: compensable.map((step) => step.name),
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
const ctx = {
|
|
980
|
+
auth: flowAuth,
|
|
981
|
+
data: config.createDataService ? config.createDataService(flowAuth) : {},
|
|
982
|
+
events: createEventService
|
|
983
|
+
? createEventService(flowAuth)
|
|
984
|
+
: { emit: async () => undefined, emitMany: async () => undefined },
|
|
985
|
+
flows: {
|
|
986
|
+
start: async () => ({
|
|
987
|
+
id: executionId,
|
|
988
|
+
flowName: row.flowName,
|
|
989
|
+
status: FlowStatus.Cancelled,
|
|
990
|
+
}),
|
|
991
|
+
resume: async () => undefined,
|
|
992
|
+
cancel: async () => undefined,
|
|
993
|
+
status: async () => ({ id: executionId, flowName: row.flowName, status: row.status }),
|
|
994
|
+
},
|
|
995
|
+
ai: {},
|
|
996
|
+
audit: audit ?? { record: async () => undefined },
|
|
997
|
+
errors: {},
|
|
998
|
+
logger: logger ?? { debug() { }, info() { }, warn() { }, error() { } },
|
|
999
|
+
time: { now: () => new Date() },
|
|
1000
|
+
config: {},
|
|
1001
|
+
security: {},
|
|
1002
|
+
translations: { locale: 'en', t: (key) => key },
|
|
1003
|
+
state: row.state,
|
|
1004
|
+
flowId: executionId,
|
|
1005
|
+
};
|
|
1006
|
+
for (const step of compensable) {
|
|
1007
|
+
const startedAt = new Date();
|
|
1008
|
+
const result = await stepDeps.executeCapability(step.compensate, ctx, row.input);
|
|
1009
|
+
const completedAt = new Date();
|
|
1010
|
+
history.push(buildHistoryEntry(`compensate:${step.name}`, {
|
|
1011
|
+
status: result.success ? StepStatus.Completed : StepStatus.Failed,
|
|
1012
|
+
error: result.success
|
|
1013
|
+
? undefined
|
|
1014
|
+
: typeof result.error === 'object' && result.error !== null
|
|
1015
|
+
? JSON.stringify(result.error)
|
|
1016
|
+
: String(result.error),
|
|
1017
|
+
}, startedAt, completedAt));
|
|
1018
|
+
if (audit) {
|
|
1019
|
+
await audit.record(`flow.compensated.${step.name}`, {
|
|
1020
|
+
executionId,
|
|
1021
|
+
flowName: row.flowName,
|
|
1022
|
+
sourceStep: step.name,
|
|
1023
|
+
compensation: step.compensate,
|
|
1024
|
+
outcome: result.success ? 'succeeded' : 'failed',
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
752
1029
|
/**
|
|
753
1030
|
* Get the current status of a flow execution.
|
|
754
1031
|
*/
|
|
755
1032
|
async function status(executionId) {
|
|
756
|
-
const rows = await
|
|
1033
|
+
const rows = await storeFor(executionId)
|
|
757
1034
|
.select()
|
|
758
1035
|
.from(flowExecutionsTable)
|
|
759
1036
|
.where(eq(flowExecutionsTable.id, executionId))
|
|
@@ -820,7 +1097,7 @@ export function createFlowEngine(config) {
|
|
|
820
1097
|
error: error ?? 'Unknown error',
|
|
821
1098
|
tenantId: row?.tenantId,
|
|
822
1099
|
actor: row?.actor,
|
|
823
|
-
db,
|
|
1100
|
+
db: storeFor(executionId),
|
|
824
1101
|
});
|
|
825
1102
|
}
|
|
826
1103
|
catch {
|
|
@@ -829,7 +1106,7 @@ export function createFlowEngine(config) {
|
|
|
829
1106
|
}
|
|
830
1107
|
}
|
|
831
1108
|
async function updateExecution(id, updates) {
|
|
832
|
-
await
|
|
1109
|
+
await storeFor(id)
|
|
833
1110
|
.update(flowExecutionsTable)
|
|
834
1111
|
.set({ ...updates, updatedAt: new Date() })
|
|
835
1112
|
.where(eq(flowExecutionsTable.id, id));
|
|
@@ -853,7 +1130,7 @@ export function createFlowEngine(config) {
|
|
|
853
1130
|
*/
|
|
854
1131
|
async function markFailedFromRunner(executionId, error) {
|
|
855
1132
|
const message = error instanceof Error ? error.message : typeof error === 'string' ? error : 'Unknown error';
|
|
856
|
-
const result = await
|
|
1133
|
+
const result = await storeFor(executionId)
|
|
857
1134
|
.update(flowExecutionsTable)
|
|
858
1135
|
.set({
|
|
859
1136
|
status: FlowStatus.Failed,
|
|
@@ -884,13 +1161,77 @@ export function createFlowEngine(config) {
|
|
|
884
1161
|
* false if the lease was lost (0 rows affected).
|
|
885
1162
|
*/
|
|
886
1163
|
async function guardedUpdate(id, updates) {
|
|
887
|
-
const result = await
|
|
1164
|
+
const result = await storeFor(id)
|
|
888
1165
|
.update(flowExecutionsTable)
|
|
889
1166
|
.set({ ...updates, updatedAt: new Date() })
|
|
890
1167
|
.where(and(eq(flowExecutionsTable.id, id), eq(flowExecutionsTable.leaseOwner, workerId)));
|
|
891
1168
|
const rowsAffected = getRowsAffected(result);
|
|
892
1169
|
return rowsAffected > 0;
|
|
893
1170
|
}
|
|
1171
|
+
async function syncSpineAfterRun(executionId, result) {
|
|
1172
|
+
if (!spineDispatch)
|
|
1173
|
+
return;
|
|
1174
|
+
const hint = claimedHints.get(executionId);
|
|
1175
|
+
const tenantDb = executionStores.get(executionId);
|
|
1176
|
+
if (!hint || !tenantDb)
|
|
1177
|
+
return;
|
|
1178
|
+
const nowIso = new Date().toISOString();
|
|
1179
|
+
const flowRow = (await tenantDb
|
|
1180
|
+
.select({ currentStep: flowExecutionsTable.currentStep })
|
|
1181
|
+
.from(flowExecutionsTable)
|
|
1182
|
+
.where(eq(flowExecutionsTable.id, executionId))
|
|
1183
|
+
.limit(1))[0];
|
|
1184
|
+
const nextStepId = flowRow?.currentStep ?? hint.stepId;
|
|
1185
|
+
const terminal = result.status === FlowStatus.Completed ||
|
|
1186
|
+
result.status === FlowStatus.Failed ||
|
|
1187
|
+
result.status === FlowStatus.Cancelled;
|
|
1188
|
+
const cas = await casAdvanceExecution(tenantDb, {
|
|
1189
|
+
executionId,
|
|
1190
|
+
expectedRevision: hint.expectedRevision,
|
|
1191
|
+
nextStatus: terminal
|
|
1192
|
+
? result.status === FlowStatus.Completed
|
|
1193
|
+
? 'succeeded'
|
|
1194
|
+
: result.status === FlowStatus.Cancelled
|
|
1195
|
+
? 'cancelled'
|
|
1196
|
+
: 'failed'
|
|
1197
|
+
: 'running',
|
|
1198
|
+
nextStepId,
|
|
1199
|
+
terminal,
|
|
1200
|
+
nowIso,
|
|
1201
|
+
sideEffectKey: `${executionId}:${hint.stepId}:${hint.expectedRevision}`,
|
|
1202
|
+
sideEffectLabel: `${executionId}:${hint.stepId}`,
|
|
1203
|
+
}, durableSchema);
|
|
1204
|
+
await ackSpineDispatch(spineDispatch.db, hint.dispatchId);
|
|
1205
|
+
claimedHints.delete(executionId);
|
|
1206
|
+
if (cas !== 'ok' || terminal)
|
|
1207
|
+
return;
|
|
1208
|
+
const advanced = await loadExecutionState(tenantDb, executionId, durableSchema);
|
|
1209
|
+
if (!advanced || advanced.terminal || !flowRow?.currentStep)
|
|
1210
|
+
return;
|
|
1211
|
+
const nextStep = flowRow.currentStep;
|
|
1212
|
+
const outbox = await insertDispatchOutbox(tenantDb, advanced, nextStep, nowIso, durableSchema);
|
|
1213
|
+
await publishOutboxToSpine(tenantDb, spineDispatch.db, outbox, `disp:${executionId}:${advanced.revision}`, nowIso, durableSchema);
|
|
1214
|
+
}
|
|
1215
|
+
async function applyDefinitionStrategy(executionId, strategy) {
|
|
1216
|
+
assertSupportedDefinitionStrategy(strategy);
|
|
1217
|
+
const rows = await storeFor(executionId)
|
|
1218
|
+
.select()
|
|
1219
|
+
.from(flowExecutionsTable)
|
|
1220
|
+
.where(eq(flowExecutionsTable.id, executionId))
|
|
1221
|
+
.limit(1);
|
|
1222
|
+
const row = rows[0];
|
|
1223
|
+
if (!row)
|
|
1224
|
+
throw new Error(`Flow execution "${executionId}" not found`);
|
|
1225
|
+
if (strategy === DefinitionInFlightStrategy.CompleteOnOriginal) {
|
|
1226
|
+
restorePinFromRow(row);
|
|
1227
|
+
return { strategy, applied: true };
|
|
1228
|
+
}
|
|
1229
|
+
if (!isTerminal(row.status)) {
|
|
1230
|
+
await cancel(executionId);
|
|
1231
|
+
}
|
|
1232
|
+
await updateExecution(executionId, { lastError: DefinitionInFlightStrategy.StopAndRecover });
|
|
1233
|
+
return { strategy: DefinitionInFlightStrategy.StopAndRecover, applied: true };
|
|
1234
|
+
}
|
|
894
1235
|
return {
|
|
895
1236
|
start,
|
|
896
1237
|
runNext,
|
|
@@ -900,8 +1241,10 @@ export function createFlowEngine(config) {
|
|
|
900
1241
|
claimNext,
|
|
901
1242
|
claimExecution,
|
|
902
1243
|
cancel,
|
|
1244
|
+
terminate,
|
|
903
1245
|
status,
|
|
904
1246
|
markFailedFromRunner,
|
|
1247
|
+
applyDefinitionStrategy,
|
|
905
1248
|
get workerId() {
|
|
906
1249
|
return workerId;
|
|
907
1250
|
},
|