@lostgradient/weft 0.23.1 → 0.24.1
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 +72 -4
- package/dist/cli/codegen-emit-dedup.d.ts +81 -0
- package/dist/cli/codegen-emit-dedup.js +45 -0
- package/dist/cli/codegen-emit-registry.d.ts +90 -0
- package/dist/cli/codegen-emit-registry.js +50 -0
- package/dist/cli/codegen-emit.d.ts +26 -39
- package/dist/cli/codegen-emit.js +4 -27
- package/dist/cli/codegen-validate.d.ts +49 -0
- package/dist/cli/codegen-validate.js +186 -0
- package/dist/cli/codegen.js +6 -87
- package/dist/cli/conformance.js +5 -2
- package/dist/cli/generated/operation-catalog.snapshot.json +381 -3
- package/dist/cli/generated/operation-client.generated.d.ts +350 -10
- package/dist/cli/generated/operation-client.generated.js +14 -0
- package/dist/cli/output.js +1 -1
- package/dist/cli/parse-schedule-arguments.js +15 -3
- package/dist/cli/schedule.js +2 -1
- package/dist/cli/storage-factory.js +2 -0
- package/dist/cli/types.d.ts +2 -1
- package/dist/cli/workflow-commands.js +2 -0
- package/dist/cli-main.js +1 -1
- package/dist/client/http-client-requests.js +6 -9
- package/dist/client/start-body.js +1 -0
- package/dist/core/application-payload-digest.d.ts +42 -0
- package/dist/core/application-payload-digest.js +76 -0
- package/dist/core/application-primitive-abort.d.ts +50 -0
- package/dist/core/application-primitive-abort.js +40 -0
- package/dist/core/application-primitive-attempt-registry.d.ts +74 -0
- package/dist/core/application-primitive-attempt-registry.js +73 -0
- package/dist/core/application-primitive-codec.d.ts +36 -0
- package/dist/core/application-primitive-codec.js +56 -0
- package/dist/core/application-primitive-commit.d.ts +67 -0
- package/dist/core/application-primitive-commit.js +66 -0
- package/dist/core/application-primitive-guards.d.ts +62 -0
- package/dist/core/application-primitive-guards.js +89 -0
- package/dist/core/application-primitive-payload.d.ts +29 -0
- package/dist/core/application-primitive-payload.js +65 -0
- package/dist/core/application-primitive-timing.d.ts +18 -0
- package/dist/core/application-primitive-timing.js +22 -0
- package/dist/core/atomic-state.js +2 -0
- package/dist/core/catalog/codec.d.ts +40 -0
- package/dist/core/catalog/codec.js +45 -0
- package/dist/core/catalog/errors.d.ts +104 -0
- package/dist/core/catalog/errors.js +41 -0
- package/dist/core/catalog/index.d.ts +25 -0
- package/dist/core/catalog/index.js +22 -0
- package/dist/core/catalog/reference-counts.d.ts +120 -0
- package/dist/core/catalog/reference-counts.js +28 -0
- package/dist/core/catalog/removal.d.ts +105 -0
- package/dist/core/catalog/removal.js +30 -0
- package/dist/core/catalog/storage-io.d.ts +101 -0
- package/dist/core/catalog/storage-io.js +106 -0
- package/dist/core/catalog/types.d.ts +108 -0
- package/dist/core/catalog/types.js +0 -0
- package/dist/core/catalog/workflow-catalog.d.ts +165 -0
- package/dist/core/catalog/workflow-catalog.js +198 -0
- package/dist/core/compare-codepoint.d.ts +13 -0
- package/dist/core/compare-codepoint.js +7 -0
- package/dist/core/compression.js +2 -0
- package/dist/core/context/attributes.d.ts +1 -1
- package/dist/core/context/durable-operations.d.ts +2 -2
- package/dist/core/context/index.js +5 -3
- package/dist/core/context/state-namespace.d.ts +1 -1
- package/dist/core/contract/build.d.ts +64 -0
- package/dist/core/contract/build.js +99 -0
- package/dist/core/contract/compatibility.d.ts +187 -0
- package/dist/core/contract/compatibility.js +37 -0
- package/dist/core/contract/failure.d.ts +64 -0
- package/dist/core/contract/failure.js +4 -0
- package/dist/core/contract/hash.d.ts +92 -0
- package/dist/core/contract/hash.js +34 -0
- package/dist/core/contract/index.d.ts +21 -0
- package/dist/core/contract/index.js +22 -0
- package/dist/core/contract/limits.d.ts +74 -0
- package/dist/core/contract/limits.js +1 -0
- package/dist/core/contract/manifest-parse-schema.d.ts +37 -0
- package/dist/core/contract/manifest-parse-schema.js +106 -0
- package/dist/core/contract/manifest-parse.d.ts +76 -0
- package/dist/core/contract/manifest-parse.js +189 -0
- package/dist/core/contract/manifest.d.ts +56 -0
- package/dist/core/contract/manifest.js +31 -0
- package/dist/core/contract/normalize.d.ts +97 -0
- package/dist/core/contract/normalize.js +127 -0
- package/dist/core/contract/revision.d.ts +29 -0
- package/dist/core/contract/revision.js +5 -0
- package/dist/core/contract/types.d.ts +274 -0
- package/dist/core/contract/types.js +1 -0
- package/dist/core/engine/activity-resolution.js +17 -17
- package/dist/core/engine/bulk-operations-purge.js +14 -20
- package/dist/core/engine/bulk-operations-retry.d.ts +9 -0
- package/dist/core/engine/bulk-operations-retry.js +177 -0
- package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
- package/dist/core/engine/bulk-operations-shared.js +14 -0
- package/dist/core/engine/bulk-operations.js +8 -167
- package/dist/core/engine/callback-creators-bundles.js +4 -2
- package/dist/core/engine/callback-creators-core.js +9 -1
- package/dist/core/engine/callback-creators-schedule.js +2 -2
- package/dist/core/engine/catalog-activation.d.ts +40 -0
- package/dist/core/engine/catalog-activation.js +17 -0
- package/dist/core/engine/catalog-events.d.ts +36 -0
- package/dist/core/engine/catalog-events.js +15 -0
- package/dist/core/engine/catalog-readiness.d.ts +49 -0
- package/dist/core/engine/catalog-readiness.js +61 -0
- package/dist/core/engine/catalog-removal.d.ts +236 -0
- package/dist/core/engine/catalog-removal.js +123 -0
- package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
- package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
- package/dist/core/engine/constraints.js +5 -1
- package/dist/core/engine/construction.d.ts +2 -2
- package/dist/core/engine/construction.js +4 -2
- package/dist/core/engine/decode-revision.d.ts +32 -0
- package/dist/core/engine/decode-revision.js +9 -0
- package/dist/core/engine/disposal.d.ts +6 -2
- package/dist/core/engine/disposal.js +26 -3
- package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
- package/dist/core/engine/dynamic-source-errors.js +25 -0
- package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
- package/dist/core/engine/dynamic-source-execution.js +108 -0
- package/dist/core/engine/engine-internal-types.d.ts +16 -0
- package/dist/core/engine/engine-workflows-namespace.d.ts +140 -0
- package/dist/core/engine/engine-workflows-namespace.js +51 -0
- package/dist/core/engine/finalizer-metadata.d.ts +22 -0
- package/dist/core/engine/finalizer-metadata.js +12 -0
- package/dist/core/engine/handle-result.js +2 -0
- package/dist/core/engine/index.d.ts +91 -0
- package/dist/core/engine/index.js +78 -6
- package/dist/core/engine/inline-launch-queue.js +1 -1
- package/dist/core/engine/internals.d.ts +54 -15
- package/dist/core/engine/internals.js +6 -0
- package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
- package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
- package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
- package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
- package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
- package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
- package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
- package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
- package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
- package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
- package/dist/core/engine/lifecycle/resume.js +18 -9
- package/dist/core/engine/lifecycle/shared.d.ts +43 -0
- package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +12 -0
- package/dist/core/engine/lifecycle/standalone-claim-acquire.js +6 -0
- package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
- package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
- package/dist/core/engine/lifecycle/start-commit.d.ts +22 -7
- package/dist/core/engine/lifecycle/start-commit.js +49 -15
- package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
- package/dist/core/engine/lifecycle/start-exec.js +7 -5
- package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
- package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
- package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +49 -0
- package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
- package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
- package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
- package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
- package/dist/core/engine/lifecycle/start-state.js +60 -0
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +66 -3
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +13 -3
- package/dist/core/engine/lifecycle/start.d.ts +16 -6
- package/dist/core/engine/lifecycle/start.js +39 -66
- package/dist/core/engine/lifecycle/transition.d.ts +3 -4
- package/dist/core/engine/lifecycle/transition.js +30 -80
- package/dist/core/engine/lifecycle.d.ts +4 -2
- package/dist/core/engine/lifecycle.js +6 -6
- package/dist/core/engine/listing.js +15 -1
- package/dist/core/engine/memo-durable-activity.js +4 -1
- package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
- package/dist/core/engine/nonterminal-revision-count.js +16 -0
- package/dist/core/engine/operations-time.d.ts +5 -23
- package/dist/core/engine/operations-time.js +13 -11
- package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
- package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
- package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
- package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
- package/dist/core/engine/pinned-schedule-revision.js +53 -0
- package/dist/core/engine/registration.d.ts +106 -0
- package/dist/core/engine/registration.js +28 -7
- package/dist/core/engine/retention.js +9 -2
- package/dist/core/engine/revision-errors.d.ts +71 -0
- package/dist/core/engine/revision-errors.js +13 -0
- package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
- package/dist/core/engine/schedule-revision-fire.js +3 -0
- package/dist/core/engine/schedule-run.js +2 -1
- package/dist/core/engine/schedules.d.ts +2 -1
- package/dist/core/engine/schedules.js +28 -9
- package/dist/core/engine/source-diagnostics.d.ts +76 -0
- package/dist/core/engine/source-diagnostics.js +105 -0
- package/dist/core/engine/source-registration.d.ts +42 -0
- package/dist/core/engine/source-registration.js +38 -0
- package/dist/core/engine/source-resolution.d.ts +101 -0
- package/dist/core/engine/source-resolution.js +154 -0
- package/dist/core/engine/source-runtime-state.d.ts +92 -0
- package/dist/core/engine/source-runtime-state.js +36 -0
- package/dist/core/engine/storage-io.d.ts +19 -2
- package/dist/core/engine/storage-io.js +21 -2
- package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
- package/dist/core/engine/termination/finalizer-registration.js +21 -0
- package/dist/core/engine/termination/finalizer.d.ts +16 -19
- package/dist/core/engine/termination/finalizer.js +3 -3
- package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
- package/dist/core/engine/time-operation-callbacks.js +0 -0
- package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
- package/dist/core/engine/validation/schedule-cadence.js +20 -0
- package/dist/core/engine/validation/schedule-options.d.ts +4 -1
- package/dist/core/engine/validation/schedule-options.js +14 -0
- package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
- package/dist/core/engine/validation/schedule-revision.js +21 -0
- package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
- package/dist/core/engine/validation/schedule-warnings.js +5 -0
- package/dist/core/engine/validation/schedule.d.ts +4 -3
- package/dist/core/engine/validation/schedule.js +15 -26
- package/dist/core/engine/validation.js +5 -2
- package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
- package/dist/core/engine/workflow-claim-reclaim-target.js +16 -2
- package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
- package/dist/core/engine/workflow-retention-deadline.js +33 -0
- package/dist/core/events/catalog-events.d.ts +117 -0
- package/dist/core/events/catalog-events.js +62 -0
- package/dist/core/events/event-map.d.ts +11 -0
- package/dist/core/events/index.d.ts +2 -0
- package/dist/core/events/index.js +2 -0
- package/dist/core/events/workflow-source-events.d.ts +102 -0
- package/dist/core/events/workflow-source-events.js +57 -0
- package/dist/core/execution-strategy.d.ts +7 -0
- package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
- package/dist/core/inline-execution-strategy.js +1 -1
- package/dist/core/mailbox-admission.d.ts +26 -0
- package/dist/core/mailbox-admission.js +130 -0
- package/dist/core/mailbox-claims.d.ts +251 -0
- package/dist/core/mailbox-claims.js +0 -0
- package/dist/core/mailbox-codec.d.ts +32 -0
- package/dist/core/mailbox-codec.js +221 -0
- package/dist/core/mailbox-contract.d.ts +290 -0
- package/dist/core/mailbox-contract.js +0 -0
- package/dist/core/mailbox-delivery.d.ts +37 -0
- package/dist/core/mailbox-delivery.js +193 -0
- package/dist/core/mailbox-guards.d.ts +78 -0
- package/dist/core/mailbox-guards.js +58 -0
- package/dist/core/mailbox-index-codec.d.ts +41 -0
- package/dist/core/mailbox-index-codec.js +71 -0
- package/dist/core/mailbox-internals.d.ts +156 -0
- package/dist/core/mailbox-internals.js +154 -0
- package/dist/core/mailbox-maintenance.d.ts +29 -0
- package/dist/core/mailbox-maintenance.js +196 -0
- package/dist/core/mailbox-settlement.d.ts +69 -0
- package/dist/core/mailbox-settlement.js +206 -0
- package/dist/core/mailbox-storage.d.ts +117 -0
- package/dist/core/mailbox-storage.js +115 -0
- package/dist/core/mailbox-transition-helpers.d.ts +70 -0
- package/dist/core/mailbox-transition-helpers.js +43 -0
- package/dist/core/mailbox-transitions-recovery.d.ts +28 -0
- package/dist/core/mailbox-transitions-recovery.js +64 -0
- package/dist/core/mailbox-transitions.d.ts +138 -0
- package/dist/core/mailbox-transitions.js +180 -0
- package/dist/core/mailbox-types.d.ts +406 -0
- package/dist/core/mailbox-types.js +16 -0
- package/dist/core/mailbox-validation.d.ts +65 -0
- package/dist/core/mailbox-validation.js +73 -0
- package/dist/core/mailbox-waits.d.ts +50 -0
- package/dist/core/mailbox-waits.js +97 -0
- package/dist/core/mailbox.d.ts +163 -0
- package/dist/core/mailbox.js +211 -0
- package/dist/core/outbox-claims.d.ts +307 -0
- package/dist/core/outbox-claims.js +0 -0
- package/dist/core/outbox-codec.d.ts +24 -0
- package/dist/core/outbox-codec.js +257 -0
- package/dist/core/outbox-contract.d.ts +346 -0
- package/dist/core/outbox-contract.js +0 -0
- package/dist/core/outbox-delivery.d.ts +34 -0
- package/dist/core/outbox-delivery.js +149 -0
- package/dist/core/outbox-drain.d.ts +29 -0
- package/dist/core/outbox-drain.js +158 -0
- package/dist/core/outbox-enqueue.d.ts +24 -0
- package/dist/core/outbox-enqueue.js +115 -0
- package/dist/core/outbox-guards.d.ts +76 -0
- package/dist/core/outbox-guards.js +60 -0
- package/dist/core/outbox-index-codec.d.ts +33 -0
- package/dist/core/outbox-index-codec.js +71 -0
- package/dist/core/outbox-internals.d.ts +99 -0
- package/dist/core/outbox-internals.js +159 -0
- package/dist/core/outbox-listing.d.ts +12 -0
- package/dist/core/outbox-listing.js +38 -0
- package/dist/core/outbox-maintenance.d.ts +28 -0
- package/dist/core/outbox-maintenance.js +191 -0
- package/dist/core/outbox-operations.d.ts +18 -0
- package/dist/core/outbox-operations.js +46 -0
- package/dist/core/outbox-runner.d.ts +30 -0
- package/dist/core/outbox-runner.js +217 -0
- package/dist/core/outbox-settlement.d.ts +57 -0
- package/dist/core/outbox-settlement.js +183 -0
- package/dist/core/outbox-storage.d.ts +107 -0
- package/dist/core/outbox-storage.js +127 -0
- package/dist/core/outbox-transition-helpers.d.ts +83 -0
- package/dist/core/outbox-transition-helpers.js +63 -0
- package/dist/core/outbox-transitions-recovery.d.ts +30 -0
- package/dist/core/outbox-transitions-recovery.js +42 -0
- package/dist/core/outbox-transitions.d.ts +145 -0
- package/dist/core/outbox-transitions.js +236 -0
- package/dist/core/outbox-types.d.ts +400 -0
- package/dist/core/outbox-types.js +20 -0
- package/dist/core/outbox-validation.d.ts +101 -0
- package/dist/core/outbox-validation.js +127 -0
- package/dist/core/outbox-waits.d.ts +39 -0
- package/dist/core/outbox-waits.js +88 -0
- package/dist/core/outbox.d.ts +156 -0
- package/dist/core/outbox.js +234 -0
- package/dist/core/registry-limits.d.ts +49 -0
- package/dist/core/registry-limits.js +10 -0
- package/dist/core/registry-schema-conversion.d.ts +20 -0
- package/dist/core/registry-schema-conversion.js +22 -0
- package/dist/core/registry-snapshot.d.ts +91 -42
- package/dist/core/registry-snapshot.js +39 -77
- package/dist/core/registry-workflow-contract-draft.d.ts +32 -0
- package/dist/core/registry-workflow-contract-draft.js +28 -0
- package/dist/core/registry-workflow-manifest.d.ts +122 -0
- package/dist/core/registry-workflow-manifest.js +92 -0
- package/dist/core/source/errors.d.ts +55 -0
- package/dist/core/source/errors.js +13 -0
- package/dist/core/source/index.d.ts +19 -0
- package/dist/core/source/index.js +4 -0
- package/dist/core/source/resolvers.d.ts +45 -0
- package/dist/core/source/resolvers.js +9 -0
- package/dist/core/source/types.d.ts +211 -0
- package/dist/core/source/types.js +0 -0
- package/dist/core/source/validate.d.ts +91 -0
- package/dist/core/source/validate.js +62 -0
- package/dist/core/source/workflow-source.d.ts +43 -0
- package/dist/core/source/workflow-source.js +16 -0
- package/dist/core/types/checkpoint.d.ts +14 -0
- package/dist/core/types/schedules.d.ts +52 -1
- package/dist/core/types/state.d.ts +16 -0
- package/dist/core/types/workflow-registries.d.ts +7 -0
- package/dist/core/types/workflow-registry.d.ts +12 -0
- package/dist/core/versioning.js +2 -0
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +12 -1
- package/dist/core/worker-execution-strategy.d.ts +1 -0
- package/dist/core/worker-execution-strategy.js +13 -1
- package/dist/core/worker-fault-handling.d.ts +10 -0
- package/dist/core/worker-fault-handling.js +1 -0
- package/dist/core/worker-inbound-message.d.ts +1 -0
- package/dist/core/worker-inbound-message.js +1 -0
- package/dist/core/worker-protocol-guard.js +4 -0
- package/dist/core/worker-protocol.d.ts +7 -0
- package/dist/core/worker-protocol.js +2 -1
- package/dist/core/worker-turn-watchdog.d.ts +8 -1
- package/dist/core/worker-turn-watchdog.js +3 -2
- package/dist/diagnostics/format.js +5 -0
- package/dist/diagnostics/types.d.ts +24 -0
- package/dist/diagnostics/version-check.js +8 -2
- package/dist/http.js +2 -2
- package/dist/index.d.ts +25 -4
- package/dist/index.js +57 -0
- package/dist/indexeddb.js +1 -1
- package/dist/json-schema.js +3 -3
- package/dist/mcp/resources.js +2 -0
- package/dist/runtime/portable.d.ts +9 -1
- package/dist/server/fault-to-json-rpc.js +4 -1
- package/dist/server/handler/auth-context-principal.js +4 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/json-rpc-http.js +2 -0
- package/dist/server/json-rpc-websocket.js +6 -4
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/pipeline-helpers.js +2 -0
- package/dist/server/operation-catalog/types.d.ts +17 -0
- package/dist/server/operation-fault.d.ts +5 -0
- package/dist/server/operation-fault.js +4 -1
- package/dist/server/operations/activate-workflow-revision.d.ts +30 -0
- package/dist/server/operations/activate-workflow-revision.js +69 -0
- package/dist/server/operations/create-schedule.d.ts +2 -0
- package/dist/server/operations/create-schedule.js +10 -6
- package/dist/server/operations/fleet-events-subscription.js +1 -1
- package/dist/server/operations/fork-workflow.js +1 -1
- package/dist/server/operations/get-active-workflow-revision.d.ts +32 -0
- package/dist/server/operations/get-active-workflow-revision.js +46 -0
- package/dist/server/operations/get-catalog-diagnostics.d.ts +113 -0
- package/dist/server/operations/get-catalog-diagnostics.js +65 -0
- package/dist/server/operations/get-registry.js +17 -4
- package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
- package/dist/server/operations/get-task-detail-schema.js +1 -0
- package/dist/server/operations/get-task-detail.d.ts +8 -0
- package/dist/server/operations/get-task-detail.js +1 -0
- package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
- package/dist/server/operations/get-workflow-revision.d.ts +25 -0
- package/dist/server/operations/get-workflow-revision.js +50 -0
- package/dist/server/operations/install-workflow-revision.d.ts +27 -0
- package/dist/server/operations/install-workflow-revision.js +46 -0
- package/dist/server/operations/list-workflow-revisions.d.ts +20 -0
- package/dist/server/operations/list-workflow-revisions.js +40 -0
- package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
- package/dist/server/operations/preload-workflow-revision.js +60 -0
- package/dist/server/operations/schedule-faults.d.ts +1 -0
- package/dist/server/operations/schedule-faults.js +32 -4
- package/dist/server/operations/schedule-rest-body.d.ts +1 -0
- package/dist/server/operations/schedule-rest-body.js +2 -1
- package/dist/server/operations/start-or-signal-workflow.js +1 -1
- package/dist/server/operations/start-workflow.js +1 -1
- package/dist/server/operations/static-registrations.js +42 -0
- package/dist/server/operations/storage.js +2 -2
- package/dist/server/operations/submit-review-decision.js +1 -1
- package/dist/server/operations/update-schedule.d.ts +2 -0
- package/dist/server/operations/update-schedule.js +4 -2
- package/dist/server/operations/workflow-catalog-operation-helpers.d.ts +59 -0
- package/dist/server/operations/workflow-catalog-operation-helpers.js +162 -0
- package/dist/server/runtime/task-dispatch-envelope.d.ts +14 -0
- package/dist/server/runtime/task-dispatch-envelope.js +32 -0
- package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
- package/dist/server/runtime/task-dispatch-revision.js +13 -0
- package/dist/server/runtime/task-dispatch.js +12 -37
- package/dist/server/runtime/task-ledger-recovery.js +1 -1
- package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
- package/dist/server/runtime/task-ledger-runtime.js +5 -3
- package/dist/server/runtime/task-polling.js +9 -3
- package/dist/server/runtime/task-reconciliation.js +2 -1
- package/dist/server/runtime/websocket-upgrade.js +2 -0
- package/dist/server/runtime/websocket-worker.js +9 -0
- package/dist/server/task-ledger-codec.d.ts +9 -0
- package/dist/server/task-ledger-codec.js +4 -1
- package/dist/server/task-ledger-transition-helpers.js +1 -0
- package/dist/server/task-ledger-types.d.ts +9 -0
- package/dist/server/task-ledger.d.ts +1 -1
- package/dist/server/task-ledger.js +2 -1
- package/dist/server/task-queue-types.d.ts +2 -0
- package/dist/storage/bun-sql.js +51 -6
- package/dist/storage/catalog-keys.d.ts +64 -0
- package/dist/storage/catalog-keys.js +8 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/derived-operations.js +1 -1
- package/dist/storage/index.d.ts +28 -1
- package/dist/storage/interface.d.ts +28 -1
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-encoding.d.ts +15 -0
- package/dist/storage/key-encoding.js +3 -0
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +16 -0
- package/dist/storage/lmdb.d.ts +54 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/mailbox-keys.d.ts +80 -0
- package/dist/storage/mailbox-keys.js +14 -0
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +2 -2
- package/dist/storage/node-sqlite-loader.d.ts +1 -1
- package/dist/storage/node-sqlite.js +51 -6
- package/dist/storage/outbox-keys.d.ts +77 -0
- package/dist/storage/outbox-keys.js +14 -0
- package/dist/storage/postgres.js +2 -2
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/storage-configuration.d.ts +6 -0
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
- package/dist/worker/manifest/registry-contract-builder.js +40 -31
- package/dist/worker/protocol-messages.d.ts +17 -0
- package/dist/worker/protocol-schemas.d.ts +32 -0
- package/dist/worker/protocol-schemas.js +7 -3
- package/dist/worker/protocol-task-result.js +35 -3
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/registry/types.d.ts +2 -0
- package/dist/worker/registry.d.ts +1 -1
- package/dist/worker/registry.js +3 -1
- package/dist/workers/workflow-runner.d.ts +9 -0
- package/dist/workers/workflow-runner.js +9 -2
- package/dist/workers/workflow-worker-entry.js +9 -4
- package/package.json +2 -2
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TimerEntry } from '../../types.ts';
|
|
2
|
+
import type { ExecutableRegistration } from '../dynamic-source-execution.ts';
|
|
3
|
+
import type { EngineInternals } from '../internals.ts';
|
|
4
|
+
import type { TimeOperationCallbacks } from '../operations-time.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Resolve `type`'s registration for a delayed-start fire, failing the
|
|
7
|
+
* workflow (via `callbacks.failWorkflow`) and returning `null` on any
|
|
8
|
+
* resolution error instead of throwing. ADR 0002: acquires this workflow's
|
|
9
|
+
* claim standalone + hydrates cleanup tracking BEFORE failing — the
|
|
10
|
+
* happy-path pending→running fold later in `startDelayedWorkflow` would
|
|
11
|
+
* otherwise establish both.
|
|
12
|
+
*
|
|
13
|
+
* Resolved against `revision` — the pending run's own persisted
|
|
14
|
+
* `WorkflowState.revision` (WFT-17), `undefined` for a legacy record —
|
|
15
|
+
* never the catalog's active pointer, so a delayed-start fire honors the
|
|
16
|
+
* exact revision this run was created against, matching
|
|
17
|
+
* `resumeWorkflowFromStorage()`'s use of the same resolver.
|
|
18
|
+
*
|
|
19
|
+
* Returns the FULL `{ entry, revision }` pair, not just `entry` — mirroring
|
|
20
|
+
* `resolveExecutableRegistrationOrRenamedNotFound()`'s shape used by
|
|
21
|
+
* `resume.ts`/`transition.ts`. For a legacy, pre-revision-pinning pending
|
|
22
|
+
* record with exactly one registered `registerSource()` candidate, the
|
|
23
|
+
* resolver can unambiguously resolve that candidate even though the input
|
|
24
|
+
* `revision` was `undefined` — the caller MUST thread this returned
|
|
25
|
+
* `revision` (not the input `revision` or the persisted state's own,
|
|
26
|
+
* still-`undefined` `revision`) through the pending→running transition and
|
|
27
|
+
* into `beginWorkflowExecution`, or the per-instance identity cache ends up
|
|
28
|
+
* stamped with the wrong (missing) revision (WFT-19 review round 7).
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveDelayedStartRegistrationOrFail(internals: EngineInternals, entry: TimerEntry, type: string, revision: string | undefined, callbacks: Pick<TimeOperationCallbacks, 'failWorkflow' | 'resolveExecutableRegistrationForRevision'>): Promise<ExecutableRegistration | null>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ensureDelayedStartClaimAndCleanupBeforeFailure } from "./standalone-claim-acquire.js";
|
|
2
|
+
export async function resolveDelayedStartRegistrationOrFail(internals, entry, type, revision, callbacks) {
|
|
3
|
+
try {
|
|
4
|
+
return await callbacks.resolveExecutableRegistrationForRevision(type, revision);
|
|
5
|
+
} catch (error) {
|
|
6
|
+
await ensureDelayedStartClaimAndCleanupBeforeFailure(internals, entry.workflowId);
|
|
7
|
+
const asError = error instanceof Error ? error : Error(String(error));
|
|
8
|
+
await callbacks.failWorkflow(entry.workflowId, asError);
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -5,5 +5,37 @@ import type { EngineInternals } from '../internals.ts';
|
|
|
5
5
|
import { type LifecycleCallbacks } from './shared.ts';
|
|
6
6
|
export declare function createForkLineage(_internals: EngineInternals, sourceWorkflowId: string, checkpoint: Checkpoint, _callbacks: LifecycleCallbacks): ForkLineage;
|
|
7
7
|
export declare function buildForkSearchAttributes(_internals: EngineInternals, checkpoint: Checkpoint, lineage: ForkLineage, _callbacks: LifecycleCallbacks): Record<string, SearchAttributeValue>;
|
|
8
|
-
export declare function createForkedWorkflowState(_internals: EngineInternals, workflowId: string, sourceState: WorkflowState, versionTuple: WorkflowVersionTuple, lineage: ForkLineage, forkedAt: number, _callbacks: LifecycleCallbacks
|
|
8
|
+
export declare function createForkedWorkflowState(_internals: EngineInternals, workflowId: string, sourceState: WorkflowState, versionTuple: WorkflowVersionTuple, lineage: ForkLineage, forkedAt: number, _callbacks: LifecycleCallbacks,
|
|
9
|
+
/**
|
|
10
|
+
* `fork()`'s own resolver-returned revision — used to fill in the fork's
|
|
11
|
+
* persisted `revision` ONLY when `sourceState.revision` is itself
|
|
12
|
+
* `undefined` (WFT-19 review round 6, Codex, P1). Never overrides an
|
|
13
|
+
* already-defined `sourceState.revision`: `resolveExecutableRegistrationForRevision()`
|
|
14
|
+
* ALWAYS returns `revision: undefined` for an eager registration (eager
|
|
15
|
+
* has no ambiguity to resolve against — see `canResolveRevisionLocally`'s
|
|
16
|
+
* doc), even though the eager source run's own `sourceState.revision` is
|
|
17
|
+
* a real, independently-meaningful value (`resolveCachedStartRevision()`'s
|
|
18
|
+
* `registeredCatalogRevisions` fallback stamps it at ordinary start time,
|
|
19
|
+
* for every registration kind). Blindly preferring `resolvedRevision`
|
|
20
|
+
* here would have dropped that real value for every eager-type fork —
|
|
21
|
+
* caught by `tests/replay-fixtures/fork-from-checkpoint.json`'s golden
|
|
22
|
+
* byte comparison. For a legacy (pre-revision-pinning) source run on a
|
|
23
|
+
* dynamic-source type with exactly one registered candidate,
|
|
24
|
+
* `sourceState.revision` genuinely IS `undefined` even though the
|
|
25
|
+
* resolver resolved — and the fork launches against — that sole
|
|
26
|
+
* candidate's code; `sourceState.revision ?? resolvedRevision` falls
|
|
27
|
+
* through to the resolver's answer only in that case. Stamping the fork's
|
|
28
|
+
* persisted `revision` with the raw `undefined` legacy pin (as this
|
|
29
|
+
* function did before this fix existed) left the fork durably unpinned:
|
|
30
|
+
* it would run correctly until the next restart, but a fresh-process
|
|
31
|
+
* `recoverAll()` after a second candidate is later registered would
|
|
32
|
+
* classify the fork `legacy-ambiguous` and refuse to resume it, even
|
|
33
|
+
* though the fork's own resolver already knew exactly which revision it
|
|
34
|
+
* belonged to at creation time. Mirrors the identical fix already applied
|
|
35
|
+
* to the process-local identity cache in `checkpoint-launch.ts`'s
|
|
36
|
+
* `launchWorkflowFromCheckpoint()` (WFT-19 review round 5) — that fix
|
|
37
|
+
* closed the in-memory gap; this one closes the matching durable-state
|
|
38
|
+
* gap the same bug left behind, for the one case it actually applies to.
|
|
39
|
+
*/
|
|
40
|
+
resolvedRevision: string | undefined): WorkflowState;
|
|
9
41
|
export declare function buildForkBatchOperations(_internals: EngineInternals, workflowId: string, state: WorkflowState, checkpoint: Checkpoint, serializedCheckpoint: Uint8Array, workflowStartHeaders: Map<string, string> | undefined, _callbacks: LifecycleCallbacks): BatchOperation[];
|
|
@@ -16,7 +16,8 @@ export function buildForkSearchAttributes(_internals, checkpoint, lineage, _call
|
|
|
16
16
|
[FORK_LINEAGE_ATTRIBUTE]: lineage.workflowId
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
export function createForkedWorkflowState(_internals, workflowId, sourceState, versionTuple, lineage, forkedAt, _callbacks) {
|
|
19
|
+
export function createForkedWorkflowState(_internals, workflowId, sourceState, versionTuple, lineage, forkedAt, _callbacks, resolvedRevision) {
|
|
20
|
+
const forkRevision = sourceState.revision ?? resolvedRevision;
|
|
20
21
|
return {
|
|
21
22
|
id: workflowId,
|
|
22
23
|
type: sourceState.type,
|
|
@@ -24,6 +25,7 @@ export function createForkedWorkflowState(_internals, workflowId, sourceState, v
|
|
|
24
25
|
input: sourceState.input,
|
|
25
26
|
workflowExecutionToken: crypto.randomUUID(),
|
|
26
27
|
versionTuple,
|
|
28
|
+
...forkRevision !== void 0 && { revision: forkRevision },
|
|
27
29
|
executionStateOwnerId: workflowId,
|
|
28
30
|
createdAt: forkedAt,
|
|
29
31
|
startedAt: forkedAt,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `recoverAll()`'s per-`(type, revision)` preload barrier (WFT-17/WFT-18),
|
|
3
|
+
* replacing the per-`type`-only barrier `recovery-dynamic-sources.ts` used
|
|
4
|
+
* to own. Split out of `transition.ts`, which has no headroom under the
|
|
5
|
+
* repository's 500-line implementation-file ceiling for this logic inline
|
|
6
|
+
* — the same reason `recovery-dynamic-sources.ts` was split out for
|
|
7
|
+
* WFT-15/16.
|
|
8
|
+
*
|
|
9
|
+
* Recovery scans non-terminal workflow states, groups them by their exact
|
|
10
|
+
* `(type, revision)` pin (a legacy record with no persisted `revision`
|
|
11
|
+
* groups under `undefined` for its type), and preloads/classifies every
|
|
12
|
+
* group BEFORE any group's runs advance — ready, or unavailable with the
|
|
13
|
+
* error every run in that group fails with. Grouping and classification use
|
|
14
|
+
* nested `Map<type, Map<revision, …>>` structures rather than a
|
|
15
|
+
* delimiter-joined composite key, so an arbitrary workflow `type` or
|
|
16
|
+
* `revision` string can never collide with a delimiter.
|
|
17
|
+
*
|
|
18
|
+
* @module core/engine/lifecycle/recovery-revision-groups
|
|
19
|
+
*/
|
|
20
|
+
import { DynamicWorkflowSourceUnavailableError } from '../dynamic-source-errors.ts';
|
|
21
|
+
import type { EngineInternals } from '../internals.ts';
|
|
22
|
+
import { WorkflowRevisionUnavailableError } from '../revision-errors.ts';
|
|
23
|
+
import type { LifecycleCallbacks } from './shared.ts';
|
|
24
|
+
/** One preflight-recoverable entry's identity, as `transition.ts`'s preflight scan produces it. */
|
|
25
|
+
export type RecoverableRevisionEntry = {
|
|
26
|
+
readonly workflowId: string;
|
|
27
|
+
readonly type: string;
|
|
28
|
+
readonly revision: string | undefined;
|
|
29
|
+
};
|
|
30
|
+
/** One `(type, revision)` group: every non-terminal run pinned to that exact revision. */
|
|
31
|
+
export type RecoveryRevisionGroup = {
|
|
32
|
+
readonly type: string;
|
|
33
|
+
readonly revision: string | undefined;
|
|
34
|
+
readonly workflowIds: readonly string[];
|
|
35
|
+
};
|
|
36
|
+
/** `type -> revision -> group`. A legacy entry (no persisted `revision`) groups under the `undefined` key. */
|
|
37
|
+
export type RecoveryRevisionGroups = ReadonlyMap<string, ReadonlyMap<string | undefined, RecoveryRevisionGroup>>;
|
|
38
|
+
/**
|
|
39
|
+
* Group preflight-recoverable entries by their exact `(type, revision)` pin.
|
|
40
|
+
* Every non-terminal run pinned to the same revision of the same type lands
|
|
41
|
+
* in one group, regardless of scan order.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildRecoveryRevisionGroups(entries: readonly RecoverableRevisionEntry[]): RecoveryRevisionGroups;
|
|
44
|
+
/** Outcome of classifying one `(type, revision)` group. */
|
|
45
|
+
export type RevisionGroupClassification = {
|
|
46
|
+
readonly status: 'ready';
|
|
47
|
+
} | {
|
|
48
|
+
readonly status: 'unavailable';
|
|
49
|
+
readonly error: WorkflowRevisionUnavailableError | DynamicWorkflowSourceUnavailableError;
|
|
50
|
+
};
|
|
51
|
+
/** `type -> revision -> classification`, mirroring {@link RecoveryRevisionGroups}'s shape. */
|
|
52
|
+
export type RevisionGroupClassifications = ReadonlyMap<string, ReadonlyMap<string | undefined, RevisionGroupClassification>>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve every `(type, revision)` group to `'ready'` or `'unavailable'`,
|
|
55
|
+
* concurrently, one `resolveExecutableRegistrationForRevision()` call per
|
|
56
|
+
* group — even when many non-terminal runs share the same pin. An eager
|
|
57
|
+
* type's groups are omitted from the result entirely (eager is always
|
|
58
|
+
* ready and needs no preload call); only dynamic-source groups are
|
|
59
|
+
* classified. A disposal mid-preload aborts the whole barrier by
|
|
60
|
+
* rethrowing, matching `recoverEntryOrIsolateFailure`'s own un-isolated
|
|
61
|
+
* treatment of {@link EngineDisposedError}.
|
|
62
|
+
*/
|
|
63
|
+
export declare function classifyRevisionGroups(internals: EngineInternals, callbacks: LifecycleCallbacks, groups: RecoveryRevisionGroups): Promise<RevisionGroupClassifications>;
|
|
64
|
+
/**
|
|
65
|
+
* Wrap `callbacks` so `recoverAll()`'s own per-entry `resume()` calls below
|
|
66
|
+
* see a batch's cached `classifyRevisionGroups()` failure for the entry's
|
|
67
|
+
* `(type, revision)` group, WITHOUT touching any state shared with other
|
|
68
|
+
* callers. `classifications` is a plain, closure-local `Map` structure —
|
|
69
|
+
* nothing outside `recoverAll()` ever sees it, so a concurrent, unrelated
|
|
70
|
+
* `engine.start()`, `engine.resume()`, or a second concurrent `recoverAll()`
|
|
71
|
+
* batch for the SAME `(type, revision)` keeps using the real, un-wrapped
|
|
72
|
+
* `callbacks.resolveExecutableRegistrationForRevision` and can never observe
|
|
73
|
+
* (or race the reset of) this batch's classification.
|
|
74
|
+
*/
|
|
75
|
+
export declare function createRecoveryScopedRevisionCallbacks(callbacks: LifecycleCallbacks, classifications: RevisionGroupClassifications): LifecycleCallbacks;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { DynamicWorkflowSourceUnavailableError } from "../dynamic-source-errors.js";
|
|
2
|
+
import { EngineDisposedError } from "../errors.js";
|
|
3
|
+
import { WorkflowRevisionUnavailableError } from "../revision-errors.js";
|
|
4
|
+
export function buildRecoveryRevisionGroups(entries) {
|
|
5
|
+
const groups = new Map;
|
|
6
|
+
for (const entry of entries) {
|
|
7
|
+
let byRevision = groups.get(entry.type);
|
|
8
|
+
if (byRevision === void 0) {
|
|
9
|
+
byRevision = new Map;
|
|
10
|
+
groups.set(entry.type, byRevision);
|
|
11
|
+
}
|
|
12
|
+
const existing = byRevision.get(entry.revision);
|
|
13
|
+
if (existing === void 0)
|
|
14
|
+
byRevision.set(entry.revision, {
|
|
15
|
+
type: entry.type,
|
|
16
|
+
revision: entry.revision,
|
|
17
|
+
workflowIds: [entry.workflowId]
|
|
18
|
+
});
|
|
19
|
+
else
|
|
20
|
+
existing.workflowIds.push(entry.workflowId);
|
|
21
|
+
}
|
|
22
|
+
return groups;
|
|
23
|
+
}
|
|
24
|
+
export async function classifyRevisionGroups(internals, callbacks, groups) {
|
|
25
|
+
const dynamicGroups = [];
|
|
26
|
+
for (const [type, byRevision] of groups) {
|
|
27
|
+
if (internals.registrations.has(type))
|
|
28
|
+
continue;
|
|
29
|
+
dynamicGroups.push(...byRevision.values());
|
|
30
|
+
}
|
|
31
|
+
const results = new Map;
|
|
32
|
+
if (dynamicGroups.length === 0)
|
|
33
|
+
return results;
|
|
34
|
+
const settled = await Promise.allSettled(dynamicGroups.map((group) => callbacks.resolveExecutableRegistrationForRevision(group.type, group.revision)));
|
|
35
|
+
for (const [index, outcome] of settled.entries()) {
|
|
36
|
+
const group = dynamicGroups[index];
|
|
37
|
+
let byRevision = results.get(group.type);
|
|
38
|
+
if (byRevision === void 0) {
|
|
39
|
+
byRevision = new Map;
|
|
40
|
+
results.set(group.type, byRevision);
|
|
41
|
+
}
|
|
42
|
+
if (outcome.status === "fulfilled") {
|
|
43
|
+
byRevision.set(group.revision, { status: "ready" });
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const reason = outcome.reason;
|
|
47
|
+
if (reason instanceof EngineDisposedError)
|
|
48
|
+
throw reason;
|
|
49
|
+
const error = reason instanceof WorkflowRevisionUnavailableError || reason instanceof DynamicWorkflowSourceUnavailableError ? reason : new DynamicWorkflowSourceUnavailableError(group.type, group.revision, "load-failed", reason);
|
|
50
|
+
byRevision.set(group.revision, { status: "unavailable", error });
|
|
51
|
+
}
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
export function createRecoveryScopedRevisionCallbacks(callbacks, classifications) {
|
|
55
|
+
return {
|
|
56
|
+
...callbacks,
|
|
57
|
+
resolveExecutableRegistrationForRevision: (type, revision) => {
|
|
58
|
+
const classification = classifications.get(type)?.get(revision);
|
|
59
|
+
if (classification?.status === "unavailable")
|
|
60
|
+
return Promise.reject(classification.error);
|
|
61
|
+
return callbacks.resolveExecutableRegistrationForRevision(type, revision);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `resumeWorkflowFromStorage()`'s generation-identity re-check (WFT-19
|
|
3
|
+
* review round 7, chatgpt-codex-connector + stevekinney) — split out of
|
|
4
|
+
* `resume.ts`, which has no headroom under the repository's 500-line
|
|
5
|
+
* implementation-file ceiling for this doc-heavy addition.
|
|
6
|
+
*
|
|
7
|
+
* @module core/engine/lifecycle/resume-generation-guard
|
|
8
|
+
*/
|
|
9
|
+
import type { WorkflowState } from '../../types.ts';
|
|
10
|
+
/**
|
|
11
|
+
* The generation a resume's `registration`/`resumeCheckpoint`/`resolvedRevision`
|
|
12
|
+
* were all resolved against — captured from the SAME `WorkflowState` decoded
|
|
13
|
+
* at the very top of `resumeWorkflowFromStorage()`, before
|
|
14
|
+
* `acquireStandaloneClaimBeforeResume`, the checkpoint load, and registration
|
|
15
|
+
* resolution all ran.
|
|
16
|
+
*
|
|
17
|
+
* `performSerializedResume()` re-reads workflow state fresh inside its
|
|
18
|
+
* serialized section but (before this guard existed) only re-checked
|
|
19
|
+
* `status` — never identity. An `onTerminalConflict: 'start-new'`
|
|
20
|
+
* replacement landing on this SAME `workflowId` between the top-of-function
|
|
21
|
+
* read and the serialized section's fresh read (e.g. a concurrent
|
|
22
|
+
* cancel/timeout terminalizes this run, then a fresh `start()` call replaces
|
|
23
|
+
* it) purges the old record and writes a brand-new one — new
|
|
24
|
+
* `type`/`revision` possibly, and ALWAYS a fresh `workflowExecutionToken`
|
|
25
|
+
* (`crypto.randomUUID()`, minted by every `start()` — see
|
|
26
|
+
* `start-state.ts`'s `buildInitialIdentitySlice`). Without
|
|
27
|
+
* {@link assertSameGeneration}, the stale `registration`/
|
|
28
|
+
* `resumeCheckpoint` a resume closure already built would replay against the
|
|
29
|
+
* replacement's fresh state: `commitSerializedResumeState` populates
|
|
30
|
+
* `internals.checkpoints` from the OLD checkpoint, and
|
|
31
|
+
* `relaunchInlineWorkflowAfterResume` drives the OLD handler — silently
|
|
32
|
+
* corrupting the replacement's run.
|
|
33
|
+
*
|
|
34
|
+
* A DIFFERENT engine's replacement is additionally caught earlier, by
|
|
35
|
+
* `acquireStandaloneClaimBeforeResume`'s durable `wakeOwnershipCheck`
|
|
36
|
+
* (workflow-lease mode only) — but that check compares only holder
|
|
37
|
+
* identity/epoch, never workflow identity, so a SAME-engine replacement
|
|
38
|
+
* (whose fold-acquire updates this engine's own already-held claim in
|
|
39
|
+
* place, leaving the epoch check trivially satisfied) is not caught there.
|
|
40
|
+
* This guard closes that gap for every ownership mode, not just
|
|
41
|
+
* workflow-lease.
|
|
42
|
+
*/
|
|
43
|
+
export type ResumeGeneration = {
|
|
44
|
+
type: string;
|
|
45
|
+
revision: string | undefined;
|
|
46
|
+
workflowExecutionToken: string | undefined;
|
|
47
|
+
};
|
|
48
|
+
/** Captures {@link ResumeGeneration} off the `WorkflowState` a resume decoded at its top, before any `await`. */
|
|
49
|
+
export declare function deriveResumeGeneration(state: WorkflowState): ResumeGeneration;
|
|
50
|
+
/**
|
|
51
|
+
* Throws when `latestState` — freshly re-read inside `performSerializedResume()`'s
|
|
52
|
+
* serialized section — no longer belongs to the same generation `expected`
|
|
53
|
+
* names. See {@link ResumeGeneration}'s doc for the exact race this
|
|
54
|
+
* closes. All three fields are compared — `workflowExecutionToken` alone
|
|
55
|
+
* would miss a legacy record that carries `undefined` on both sides of the
|
|
56
|
+
* race.
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertSameGeneration(workflowId: string, latestState: WorkflowState, expected: ResumeGeneration): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function deriveResumeGeneration(state) {
|
|
2
|
+
return {
|
|
3
|
+
type: state.type,
|
|
4
|
+
revision: state.revision,
|
|
5
|
+
workflowExecutionToken: state.workflowExecutionToken
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function assertSameGeneration(workflowId, latestState, expected) {
|
|
9
|
+
if (latestState.workflowExecutionToken !== expected.workflowExecutionToken || latestState.type !== expected.type || latestState.revision !== expected.revision)
|
|
10
|
+
throw Error(`Cannot resume workflow "${workflowId}": its persisted state changed generation (a replacement run landed at this same id) between resume's registration lookup ` + "and its serialized commit \u2014 retry against the new generation instead of replaying " + "stale state.");
|
|
11
|
+
}
|
|
@@ -8,6 +8,7 @@ import { buildTimerBatchOperations } from "../../scheduler.js";
|
|
|
8
8
|
import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
|
|
9
9
|
import { rememberCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
|
|
10
10
|
import { rehydrateChildCancellationHandlers } from "../child-workflow-cancellation.js";
|
|
11
|
+
import { resolveExecutableRegistrationOrRenamedNotFound } from "../dynamic-source-execution.js";
|
|
11
12
|
import { commitFencedEngineWrite } from "../fenced-write.js";
|
|
12
13
|
import { getWorkflowExecutionStartedAt } from "../handles.js";
|
|
13
14
|
import { loadWorkflowState } from "../storage-io.js";
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
reprovideRecoveredServices,
|
|
20
21
|
workflowServicesResolverInfoFromState
|
|
21
22
|
} from "./recovered-services.js";
|
|
23
|
+
import { assertSameGeneration, deriveResumeGeneration } from "./resume-generation-guard.js";
|
|
22
24
|
import {
|
|
23
25
|
enforceHistoryPolicyBeforeReplay,
|
|
24
26
|
loadTerminalCleanupTrackedState,
|
|
@@ -79,7 +81,11 @@ function commitSerializedResumeState(internals, args) {
|
|
|
79
81
|
internals.parkedInlineWorkflows.delete(workflowId);
|
|
80
82
|
}
|
|
81
83
|
async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
82
|
-
const { workflowId, resumeCheckpoint, registration, callbacks } = args, accumulatedResults = new Map(resumeCheckpoint.accumulatedResults), workflowAbort = new AbortController;
|
|
84
|
+
const { workflowId, resumeCheckpoint, registration, resolvedRevision, callbacks } = args, accumulatedResults = new Map(resumeCheckpoint.accumulatedResults), workflowAbort = new AbortController;
|
|
85
|
+
internals.workflowTypeByWorkflowId.set(workflowId, {
|
|
86
|
+
type: latestState.type,
|
|
87
|
+
revision: resolvedRevision
|
|
88
|
+
});
|
|
83
89
|
resetCancelHandlers(internals, workflowId);
|
|
84
90
|
await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
|
|
85
91
|
const context = new Context({
|
|
@@ -115,7 +121,11 @@ async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
|
115
121
|
inlineStrategy.continueWorkflow(workflowId, void 0);
|
|
116
122
|
}
|
|
117
123
|
async function relaunchWorkerWorkflowAfterResume(internals, latestState, args) {
|
|
118
|
-
const { workflowId, resumeCheckpoint, workflowStartHeaders, callbacks } = args;
|
|
124
|
+
const { workflowId, resumeCheckpoint, workflowStartHeaders, resolvedRevision, callbacks } = args;
|
|
125
|
+
internals.workflowTypeByWorkflowId.set(workflowId, {
|
|
126
|
+
type: latestState.type,
|
|
127
|
+
revision: resolvedRevision
|
|
128
|
+
});
|
|
119
129
|
resetCancelHandlers(internals, workflowId);
|
|
120
130
|
await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
|
|
121
131
|
const serialized = serializeCheckpoint(resumeCheckpoint);
|
|
@@ -146,6 +156,7 @@ async function performSerializedResume(internals, args) {
|
|
|
146
156
|
throw Error(`Workflow "${workflowId}" not found in storage`);
|
|
147
157
|
if (latestState.status !== "running" && latestState.status !== "suspended")
|
|
148
158
|
throw Error(`Cannot resume workflow "${workflowId}": status is "${latestState.status}", expected "running" or "suspended"`);
|
|
159
|
+
assertSameGeneration(workflowId, latestState, args.expectedGeneration);
|
|
149
160
|
await reactivateSuspendedWorkflowState(internals, latestState);
|
|
150
161
|
commitSerializedResumeState(internals, args);
|
|
151
162
|
if (internals.inlineStrategy) {
|
|
@@ -179,18 +190,14 @@ export async function resumeWorkflowFromStorage(internals, workflowId, dispatchR
|
|
|
179
190
|
if (state.status !== "running" && state.status !== "suspended")
|
|
180
191
|
throw Error(`Cannot resume workflow "${workflowId}": status is "${state.status}", expected "running" or "suspended"`);
|
|
181
192
|
await acquireStandaloneClaimBeforeResume(internals, workflowId);
|
|
193
|
+
await loadTerminalCleanupTrackedState(internals, workflowId, callbacks);
|
|
182
194
|
const checkpointBytes = await internals.storage.get(KEYS.checkpoint(workflowId));
|
|
183
195
|
if (!checkpointBytes)
|
|
184
196
|
throw Error(`Checkpoint not found for workflow "${workflowId}"`);
|
|
185
|
-
const checkpoint = deserializeCheckpoint(checkpointBytes), registration =
|
|
186
|
-
if (!registration)
|
|
187
|
-
throw Error(`No workflow registered with name "${state.type}" (needed to resume "${workflowId}")`);
|
|
188
|
-
const preparedResumeState = await prepareResumeState(internals, workflowId, state, checkpoint, checkpointBytes, registration, callbacks), resumeCheckpoint = preparedResumeState.checkpoint, registeredVersionTuple = preparedResumeState.versionTuple, restoredHead = await new EventLog(internals.storage, workflowId).loadHead();
|
|
197
|
+
const checkpoint = deserializeCheckpoint(checkpointBytes), { entry: registration, revision: resolvedRevision } = await resolveExecutableRegistrationOrRenamedNotFound((type) => callbacks.resolveExecutableRegistrationForRevision(type, state.revision), state.type, () => Error(`No workflow registered with name "${state.type}" (needed to resume "${workflowId}")`)), preparedResumeState = await prepareResumeState(internals, workflowId, state, checkpoint, checkpointBytes, registration, callbacks), resumeCheckpoint = preparedResumeState.checkpoint, registeredVersionTuple = preparedResumeState.versionTuple, restoredHead = await new EventLog(internals.storage, workflowId).loadHead();
|
|
189
198
|
if (await enforceHistoryPolicyBeforeReplay(internals, workflowId, restoredHead, callbacks))
|
|
190
199
|
return callbacks.getHandle(workflowId);
|
|
191
|
-
const workflowStartHeaders = await loadWorkflowStartHeaders(internals, workflowId, callbacks);
|
|
192
|
-
await loadTerminalCleanupTrackedState(internals, workflowId, callbacks);
|
|
193
|
-
const { handle, shouldStop } = await prepareRecoveredWorkflowOrFail(internals, state, callbacks, onRecoveredWorkflow);
|
|
200
|
+
const workflowStartHeaders = await loadWorkflowStartHeaders(internals, workflowId, callbacks), { handle, shouldStop } = await prepareRecoveredWorkflowOrFail(internals, state, callbacks, onRecoveredWorkflow);
|
|
194
201
|
if (shouldStop)
|
|
195
202
|
return handle;
|
|
196
203
|
await callbacks.runSerializedWorkflowStateWrite(workflowId, () => performSerializedResume(internals, {
|
|
@@ -201,6 +208,8 @@ export async function resumeWorkflowFromStorage(internals, workflowId, dispatchR
|
|
|
201
208
|
restoredHead,
|
|
202
209
|
workflowStartHeaders,
|
|
203
210
|
registration,
|
|
211
|
+
resolvedRevision,
|
|
212
|
+
expectedGeneration: deriveResumeGeneration(state),
|
|
204
213
|
callbacks
|
|
205
214
|
}));
|
|
206
215
|
if (dispatchResumedEvent)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComposedWorkflowInterceptor } from '../../interceptor.ts';
|
|
2
2
|
import type { WorkflowServicesResolverLaunchOptions, WorkflowServicesResolverScheduleInfo } from '../../types.ts';
|
|
3
|
+
import type { ExecutableRegistration } from '../dynamic-source-execution.ts';
|
|
3
4
|
import type { QueuedInlineWorkflowExecutionStart } from '../engine-internal-types.ts';
|
|
4
5
|
import { type WorkflowHandle } from '../handles.ts';
|
|
5
6
|
import type { EngineInternals } from '../internals.ts';
|
|
@@ -125,6 +126,48 @@ export type LifecycleCallbacks = {
|
|
|
125
126
|
* {@link RecoverAllOptions.versionMismatchPolicy}.
|
|
126
127
|
*/
|
|
127
128
|
failWorkflowForVersionMismatch: (workflowId: string, error: Error) => Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Turn a workflow `type` into an executable registration, awaiting
|
|
131
|
+
* dynamic-source resolution when `type` is not eagerly registered
|
|
132
|
+
* (WFT-15/16). See `dynamic-source-execution.ts`'s own doc for the full
|
|
133
|
+
* contract.
|
|
134
|
+
*
|
|
135
|
+
* `onRevisionChosen`, when given, fires synchronously the moment a lazy
|
|
136
|
+
* `type`'s target revision is picked — BEFORE the (potentially slow)
|
|
137
|
+
* loader is awaited — so a caller like `startWorkflow` can reserve an
|
|
138
|
+
* `inFlightStarts` slot for that exact revision immediately, closing the
|
|
139
|
+
* window where a concurrent `removeWorkflowRevision()` could observe zero
|
|
140
|
+
* references against a revision this call's own source load is about to
|
|
141
|
+
* durably (re)install. Never fires for an eager type (no revision to
|
|
142
|
+
* choose) or when resolution fails before a revision is picked (the
|
|
143
|
+
* ambiguous-revision case).
|
|
144
|
+
*/
|
|
145
|
+
resolveExecutableRegistration: (type: string, onRevisionChosen?: (revision: string) => void) => Promise<ExecutableRegistration>;
|
|
146
|
+
/**
|
|
147
|
+
* Force a recovered workflow to a terminal `failed` state because its
|
|
148
|
+
* dynamic workflow source could not be resolved during the recovery
|
|
149
|
+
* preload barrier — only this run fails; `recoverAll()` continues
|
|
150
|
+
* recovering sibling types.
|
|
151
|
+
*/
|
|
152
|
+
failWorkflowForUnavailableDynamicSource: (workflowId: string, error: Error) => Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Resolve workflow `type` against its EXACT pinned revision (WFT-17's
|
|
155
|
+
* `WorkflowState.revision`, `undefined` for a legacy pre-pinning record)
|
|
156
|
+
* instead of whichever revision the catalog currently considers active.
|
|
157
|
+
* Used by every resume path (`resumeWorkflowFromStorage`) so a pinned run
|
|
158
|
+
* never falls back to the active pointer. See
|
|
159
|
+
* `dynamic-source-execution.ts`'s `resolveExecutableRegistrationForRevision()`
|
|
160
|
+
* for the full classification contract.
|
|
161
|
+
*/
|
|
162
|
+
resolveExecutableRegistrationForRevision: (type: string, revision: string | undefined) => Promise<ExecutableRegistration>;
|
|
163
|
+
/**
|
|
164
|
+
* Force a recovered workflow to a terminal `failed` state because its
|
|
165
|
+
* pinned revision could not be resolved during the recovery preload
|
|
166
|
+
* barrier (WFT-18) — a {@link import('../revision-errors.ts').WorkflowRevisionUnavailableError}.
|
|
167
|
+
* Only this run fails; `recoverAll()` continues recovering sibling
|
|
168
|
+
* `(type, revision)` groups, including other revisions of the same type.
|
|
169
|
+
*/
|
|
170
|
+
failWorkflowForRevisionUnavailable: (workflowId: string, error: Error) => Promise<void>;
|
|
128
171
|
};
|
|
129
172
|
/**
|
|
130
173
|
* Pre-replay history circuit breaker. Called at every restore-from-checkpoint
|
|
@@ -31,3 +31,15 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import type { EngineInternals } from '../internals.ts';
|
|
33
33
|
export declare function acquireStandaloneClaimBeforeResume(internals: EngineInternals, workflowId: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Standalone-acquire `workflowId`'s claim (see {@link acquireStandaloneClaimBeforeResume},
|
|
36
|
+
* a no-op once already held) and hydrate its terminal-cleanup tracking from
|
|
37
|
+
* the durable marker — the two preconditions a `'self'`-fenced `failWorkflow()`
|
|
38
|
+
* write needs. Used by `operations-time.ts`'s `startDelayedWorkflow` on every
|
|
39
|
+
* failure exit (dynamic-source resolve, invalid execution-timeout) BEFORE
|
|
40
|
+
* failing: a delayed-start's pending→running write is the only other place
|
|
41
|
+
* this claim would otherwise get acquired (folded atomically, per ADR 0002),
|
|
42
|
+
* so a failure committed ahead of that write needs this standalone path
|
|
43
|
+
* instead, exactly like a recovered `running`/`suspended` workflow does.
|
|
44
|
+
*/
|
|
45
|
+
export declare function ensureDelayedStartClaimAndCleanupBeforeFailure(internals: EngineInternals, workflowId: string): Promise<void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { KEYS, storageHas } from "../../../storage/interface.js";
|
|
1
2
|
import { WorkflowClaimUnavailableError } from "../lease-errors.js";
|
|
2
3
|
import { wakeOwnershipCheck } from "../wake-ownership-check.js";
|
|
3
4
|
export async function acquireStandaloneClaimBeforeResume(internals, workflowId) {
|
|
@@ -23,3 +24,8 @@ export async function acquireStandaloneClaimBeforeResume(internals, workflowId)
|
|
|
23
24
|
if (result.status === "lost-race")
|
|
24
25
|
throw new WorkflowClaimUnavailableError(workflowId, result.heldBy);
|
|
25
26
|
}
|
|
27
|
+
export async function ensureDelayedStartClaimAndCleanupBeforeFailure(internals, workflowId) {
|
|
28
|
+
await acquireStandaloneClaimBeforeResume(internals, workflowId);
|
|
29
|
+
if (await storageHas(internals.storage, KEYS.terminalCleanupNeeded(workflowId)))
|
|
30
|
+
internals.workflowsNeedingTerminalCleanup.add(workflowId);
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal sentinel: the idempotent create batch lost its compare-and-swap to a
|
|
3
|
+
* concurrent caller holding the same idempotency key. Never surfaced to users —
|
|
4
|
+
* `start` / `startOrSignal` catch it and resolve to the winning run's handle.
|
|
5
|
+
*
|
|
6
|
+
* Lives in its own module so both `start-commit.ts` and the attribution helper it
|
|
7
|
+
* delegates to (`start-precondition-attribution.ts`) can raise it without an import
|
|
8
|
+
* cycle between them.
|
|
9
|
+
*/
|
|
10
|
+
export declare class StartIdempotencyRaceLostError extends Error {
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BatchOperation, type ConditionalBatchCondition } from '../../../storage/interface.ts';
|
|
2
2
|
import type { Checkpoint, StartOptions, TimerEntry, WorkflowState } from '../../types.ts';
|
|
3
3
|
import type { EngineInternals } from '../internals.ts';
|
|
4
4
|
import type { WorkflowConcurrencyStartOperations } from '../workflow-concurrency.ts';
|
|
@@ -17,13 +17,19 @@ export type BuildIdempotentStartOperations = (workflowId: string) => {
|
|
|
17
17
|
conditions: ConditionalBatchCondition[];
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* The `conditionalBatch` precondition half of {@link buildCatalogEntryStartPrecondition}
|
|
21
|
+
* — a bare `type`/`revision` pair rather than a full `WorkflowState`, so it
|
|
22
|
+
* is also reusable by a checkpoint-backed failed-run retry's reactivation
|
|
23
|
+
* commit (`bulk-operations-retry.ts`, WFT-17/18 Codex review on PR #958),
|
|
24
|
+
* which has no `WorkflowState & { revision: string }` narrowing of its own
|
|
25
|
+
* and — unlike a fresh start — carries no `inFlightStartsByRevision`
|
|
26
|
+
* reservation to close the SAME-process half of this race, so it needs this
|
|
27
|
+
* fence unconditionally rather than only under `ownershipMode !== 'none'`.
|
|
28
|
+
* Exported (rather than kept local to this module) specifically for that
|
|
29
|
+
* reuse; returns the bare {@link ConditionalBatchCondition} so callers never
|
|
30
|
+
* need this module's own non-exported {@link TaggedStartCondition} shape.
|
|
23
31
|
*/
|
|
24
|
-
export declare
|
|
25
|
-
constructor();
|
|
26
|
-
}
|
|
32
|
+
export declare function buildCatalogEntryRevisionCondition(internals: EngineInternals, type: string, revision: string): Promise<ConditionalBatchCondition>;
|
|
27
33
|
/** Everything {@link buildAndCommitStartBatch} needs to assemble the start batch. */
|
|
28
34
|
export type StartBatchContext = {
|
|
29
35
|
internals: EngineInternals;
|
|
@@ -44,6 +50,15 @@ export type StartBatchContext = {
|
|
|
44
50
|
* {@link buildStartBatchOperations}). Undefined for an ordinary start.
|
|
45
51
|
*/
|
|
46
52
|
purgeDeleteOperations: BatchOperation[] | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Compare-and-swap precondition making the caller-supplied-id duplicate check
|
|
55
|
+
* atomic with this commit (WFT-152). Built by `resolveTerminalConflictForRestart`
|
|
56
|
+
* from the exact bytes its duplicate-id read observed, and carried here as the
|
|
57
|
+
* `duplicateIdCondition` of the `StartDuplicateIdDecision` it returns. Undefined
|
|
58
|
+
* for a generated id, which cannot collide and so keeps the unconditioned hot
|
|
59
|
+
* path.
|
|
60
|
+
*/
|
|
61
|
+
duplicateIdCondition: ConditionalBatchCondition | undefined;
|
|
47
62
|
};
|
|
48
63
|
/**
|
|
49
64
|
* Assemble the start batch — folding in the id-dependent idempotency mapping and
|