@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,28 @@
|
|
|
1
|
+
export function totalWorkflowRevisionReferences(counts) {
|
|
2
|
+
return counts.registeredDefinitions + counts.inFlightStarts + counts.nonTerminalRuns + counts.pinnedSchedules + counts.pendingDispatches + counts.activeExecutionRealms + counts.retainedRecoveryRecords;
|
|
3
|
+
}
|
|
4
|
+
export function incrementNestedRevisionCount(counts, name, revision) {
|
|
5
|
+
let byRevision = counts.get(name);
|
|
6
|
+
if (byRevision === void 0) {
|
|
7
|
+
byRevision = new Map;
|
|
8
|
+
counts.set(name, byRevision);
|
|
9
|
+
}
|
|
10
|
+
byRevision.set(revision, (byRevision.get(revision) ?? 0) + 1);
|
|
11
|
+
}
|
|
12
|
+
export function decrementNestedRevisionCount(counts, name, revision) {
|
|
13
|
+
const byRevision = counts.get(name);
|
|
14
|
+
if (byRevision === void 0)
|
|
15
|
+
return;
|
|
16
|
+
const current = byRevision.get(revision);
|
|
17
|
+
if (current === void 0)
|
|
18
|
+
return;
|
|
19
|
+
if (current <= 1) {
|
|
20
|
+
byRevision.delete(revision);
|
|
21
|
+
if (byRevision.size === 0)
|
|
22
|
+
counts.delete(name);
|
|
23
|
+
} else
|
|
24
|
+
byRevision.set(revision, current - 1);
|
|
25
|
+
}
|
|
26
|
+
export function readNestedRevisionCount(counts, name, revision) {
|
|
27
|
+
return counts.get(name)?.get(revision) ?? 0;
|
|
28
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mechanical CAS-delete primitive `WorkflowCatalog.remove()` delegates
|
|
3
|
+
* to, plus the tombstone primitives that make its own resolution
|
|
4
|
+
* (restore-or-finalize) atomic too. Split into its own module to protect
|
|
5
|
+
* `workflow-catalog.ts`'s size against the repository's 500-line
|
|
6
|
+
* implementation-file ceiling — mirrors how `storage-io.ts`/`codec.ts`
|
|
7
|
+
* already sit alongside `workflow-catalog.ts` rather than inline in it.
|
|
8
|
+
*
|
|
9
|
+
* Fences the delete on BOTH the exact entry bytes read AND the exact active
|
|
10
|
+
* pointer bytes read, in one `conditionalBatch` — not entry bytes alone.
|
|
11
|
+
* Between an in-memory "is this the active revision" check and the delete,
|
|
12
|
+
* a concurrent `activateCandidate`/`activateRegistered` call (this process
|
|
13
|
+
* or another sharing the same durable store) could make the target revision
|
|
14
|
+
* active; fencing the active-pointer key too means that race loses the CAS
|
|
15
|
+
* and surfaces as `'conflict'` (the caller re-decides) instead of silently
|
|
16
|
+
* deleting a revision that became active a moment before the delete landed.
|
|
17
|
+
*
|
|
18
|
+
* Single-shot — no retry loop, matching `activateCandidate`'s own
|
|
19
|
+
* no-retry-caller-decides precedent, since a removal decision (unlike
|
|
20
|
+
* `activateRegistered`'s unconditional retry) already depends on reference
|
|
21
|
+
* counts computed by the caller and should not blindly re-attempt against
|
|
22
|
+
* possibly-stale counts.
|
|
23
|
+
*
|
|
24
|
+
* WFT-17/18 (Codex review, PR #958): a bare delete of the entry key, with
|
|
25
|
+
* `removeWorkflowRevision`'s own reference re-check and possible restore as
|
|
26
|
+
* a SEPARATE, later commit, left a crash window between the two commits
|
|
27
|
+
* where the entry was durably gone but a run still referenced it, with NO
|
|
28
|
+
* durable record of what was deleted for ANY process — including the one
|
|
29
|
+
* that crashed — to recover from. {@link removeCatalogEntry} now writes a
|
|
30
|
+
* `catalog-tombstone:<name>:<revision>` record (the exact deleted entry
|
|
31
|
+
* bytes) in the SAME `conditionalBatch` as the delete, so "the entry is
|
|
32
|
+
* gone" and "a durable record of what it was" land atomically together.
|
|
33
|
+
* {@link finalizeCatalogTombstone} and {@link restoreCatalogEntryFromTombstone}
|
|
34
|
+
* are the two possible resolutions, each its own single-CAS atomic
|
|
35
|
+
* operation conditioned on the tombstone's exact bytes — so a concurrent
|
|
36
|
+
* second attempt at resolving the SAME tombstone (this process retrying, or
|
|
37
|
+
* `catalog-readiness.ts`'s boot-time sweep racing a live caller) loses its
|
|
38
|
+
* CAS harmlessly rather than double-processing. Orphan resolution (a
|
|
39
|
+
* tombstone left behind by a process that crashed between the delete and
|
|
40
|
+
* its own resolution) is `resolveOrphanedCatalogTombstones` in
|
|
41
|
+
* `core/engine/catalog-tombstone-recovery.ts` — deliberately OUTSIDE
|
|
42
|
+
* `core/catalog/**`, not alongside these primitives, because it needs
|
|
43
|
+
* `core/engine/nonterminal-revision-count.ts`'s durable non-terminal-run
|
|
44
|
+
* scan and `core/catalog/**` never imports from `core/engine/**` (a
|
|
45
|
+
* directional boundary `check-import-cycles.ts` enforces); see that
|
|
46
|
+
* module's doc for why it lives there.
|
|
47
|
+
*
|
|
48
|
+
* @module core/catalog/removal
|
|
49
|
+
*/
|
|
50
|
+
import { type Storage } from '../../storage/interface.ts';
|
|
51
|
+
/** Outcome of {@link removeCatalogEntry}. */
|
|
52
|
+
export type WorkflowCatalogRemovalOutcome = Readonly<{
|
|
53
|
+
outcome: 'removed';
|
|
54
|
+
tombstoneBytes: Uint8Array;
|
|
55
|
+
}> | Readonly<{
|
|
56
|
+
outcome: 'not-found';
|
|
57
|
+
}> | Readonly<{
|
|
58
|
+
outcome: 'active';
|
|
59
|
+
activeRevision: string;
|
|
60
|
+
}> | Readonly<{
|
|
61
|
+
outcome: 'conflict';
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Durably delete the installed-revision record for `(name, revision)`,
|
|
65
|
+
* atomically replacing it with a tombstone carrying the deleted bytes (see
|
|
66
|
+
* this module's doc for why).
|
|
67
|
+
*
|
|
68
|
+
* Reads the current `catalog-entry:<name>:<revision>` bytes; `null` is
|
|
69
|
+
* `'not-found'` (a no-op — the caller may already believe the revision is
|
|
70
|
+
* gone). Reads the current `catalog-active:<name>` bytes and refuses with
|
|
71
|
+
* `'active'` when they decode to exactly this revision — a structural
|
|
72
|
+
* invariant independent of reference counts, since every future or
|
|
73
|
+
* resuming run resolves the active pointer, not a specific installed
|
|
74
|
+
* entry. Otherwise deletes the entry key and puts the tombstone key (CAS'd
|
|
75
|
+
* on the tombstone being absent — a stale leftover from a previous,
|
|
76
|
+
* unresolved removal of this exact `(name, revision)` is a durable-store
|
|
77
|
+
* inconsistency this fails closed on rather than silently overwriting) via
|
|
78
|
+
* ONE `conditionalBatch`, also CAS'd on the exact entry bytes AND the exact
|
|
79
|
+
* active-pointer bytes read above (present as a no-op `put`-free
|
|
80
|
+
* precondition when active-pointer bytes are `null` — never activated). A
|
|
81
|
+
* CAS loss (any of the three keys changed concurrently) surfaces as
|
|
82
|
+
* `'conflict'`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function removeCatalogEntry(storage: Storage, name: string, revision: string): Promise<WorkflowCatalogRemovalOutcome>;
|
|
85
|
+
/**
|
|
86
|
+
* Resolve an outstanding tombstone by completing the removal: CAS-delete
|
|
87
|
+
* the `catalog-tombstone:<name>:<revision>` key, conditioned on its exact
|
|
88
|
+
* bytes still being `tombstoneBytes`. Returns `false` (a harmless no-op for
|
|
89
|
+
* the caller, not an error) when the tombstone was already resolved by
|
|
90
|
+
* someone else — this same process re-driving after a transient failure,
|
|
91
|
+
* or a concurrent boot-time sweep on another process.
|
|
92
|
+
*/
|
|
93
|
+
export declare function finalizeCatalogTombstone(storage: Storage, name: string, revision: string, tombstoneBytes: Uint8Array): Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Resolve an outstanding tombstone by restoring the entry: ONE
|
|
96
|
+
* `conditionalBatch` that both re-`put`s the `catalog-entry:<name>:<revision>`
|
|
97
|
+
* key (byte-identical to what {@link removeCatalogEntry} deleted — the
|
|
98
|
+
* tombstone bytes ARE the entry bytes) and deletes the tombstone key,
|
|
99
|
+
* conditioned on the tombstone's exact bytes still being `tombstoneBytes`.
|
|
100
|
+
* Atomic by construction — there is no intermediate durable state where the
|
|
101
|
+
* entry is back but the tombstone still claims a removal is in flight, or
|
|
102
|
+
* vice versa. Returns `false` (harmless no-op) when the tombstone was
|
|
103
|
+
* already resolved by someone else.
|
|
104
|
+
*/
|
|
105
|
+
export declare function restoreCatalogEntryFromTombstone(storage: Storage, name: string, revision: string, tombstoneBytes: Uint8Array): Promise<boolean>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { KEYS, storageConditionalBatch } from "../../storage/interface.js";
|
|
2
|
+
import { decodeActivePointer } from "./codec.js";
|
|
3
|
+
export async function removeCatalogEntry(storage, name, revision) {
|
|
4
|
+
const entryKey = KEYS.catalogEntry(name, revision), entryBytes = await storage.get(entryKey);
|
|
5
|
+
if (entryBytes === null)
|
|
6
|
+
return { outcome: "not-found" };
|
|
7
|
+
const activeKey = KEYS.catalogActive(name), activeBytes = await storage.get(activeKey), activePointer = activeBytes === null ? null : decodeActivePointer(activeBytes);
|
|
8
|
+
if (activePointer !== null && activePointer.revision === revision)
|
|
9
|
+
return { outcome: "active", activeRevision: activePointer.revision };
|
|
10
|
+
const tombstoneKey = KEYS.catalogTombstone(name, revision);
|
|
11
|
+
return await storageConditionalBatch(storage, [
|
|
12
|
+
{ key: entryKey, expectedValue: entryBytes },
|
|
13
|
+
{ key: activeKey, expectedValue: activeBytes },
|
|
14
|
+
{ key: tombstoneKey, expectedValue: null }
|
|
15
|
+
], [
|
|
16
|
+
{ type: "delete", key: entryKey },
|
|
17
|
+
{ type: "put", key: tombstoneKey, value: entryBytes }
|
|
18
|
+
]) ? { outcome: "removed", tombstoneBytes: entryBytes } : { outcome: "conflict" };
|
|
19
|
+
}
|
|
20
|
+
export async function finalizeCatalogTombstone(storage, name, revision, tombstoneBytes) {
|
|
21
|
+
const tombstoneKey = KEYS.catalogTombstone(name, revision);
|
|
22
|
+
return storageConditionalBatch(storage, [{ key: tombstoneKey, expectedValue: tombstoneBytes }], [{ type: "delete", key: tombstoneKey }]);
|
|
23
|
+
}
|
|
24
|
+
export async function restoreCatalogEntryFromTombstone(storage, name, revision, tombstoneBytes) {
|
|
25
|
+
const entryKey = KEYS.catalogEntry(name, revision), tombstoneKey = KEYS.catalogTombstone(name, revision);
|
|
26
|
+
return storageConditionalBatch(storage, [{ key: tombstoneKey, expectedValue: tombstoneBytes }], [
|
|
27
|
+
{ type: "put", key: entryKey, value: tombstoneBytes },
|
|
28
|
+
{ type: "delete", key: tombstoneKey }
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable I/O for the workflow catalog: restoring catalog state at boot and
|
|
3
|
+
* writing individual installed-revision entries.
|
|
4
|
+
*
|
|
5
|
+
* `restoreWorkflowCatalog` fails closed on any corrupt or unparseable
|
|
6
|
+
* durable record — a corrupted catalog entry or active pointer is data
|
|
7
|
+
* corruption in Weft's own durable store, not hostile external input, and
|
|
8
|
+
* every other fail-closed precedent in this codebase (a corrupt lease epoch,
|
|
9
|
+
* a corrupt ownership-mode marker) treats that the same way. Silently
|
|
10
|
+
* dropping it could later resurrect a stale or wrong active revision.
|
|
11
|
+
*
|
|
12
|
+
* @module core/catalog/storage-io
|
|
13
|
+
*/
|
|
14
|
+
import { type Storage } from '../../storage/interface.ts';
|
|
15
|
+
import type { WorkflowRevisionManifest } from '../contract/types.ts';
|
|
16
|
+
import type { WorkflowCatalogActivePointer, WorkflowCatalogEntry } from './types.ts';
|
|
17
|
+
/** In-memory catalog state hydrated from durable storage. */
|
|
18
|
+
export type RestoredWorkflowCatalogState = {
|
|
19
|
+
entries: Map<string, Map<string, WorkflowCatalogEntry>>;
|
|
20
|
+
active: Map<string, WorkflowCatalogActivePointer>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Restore the durable workflow catalog: every installed `(name, revision)`
|
|
24
|
+
* entry and every name's active pointer. Every entry record is validated via
|
|
25
|
+
* {@link parseWorkflowRevisionManifest}; every active-pointer record is
|
|
26
|
+
* validated via {@link decodeActivePointer}. A corrupt or unparseable record
|
|
27
|
+
* throws rather than being silently skipped. Restoring an empty store
|
|
28
|
+
* returns empty maps.
|
|
29
|
+
*/
|
|
30
|
+
export declare function restoreWorkflowCatalog(storage: Storage): Promise<RestoredWorkflowCatalogState>;
|
|
31
|
+
/**
|
|
32
|
+
* Decode and validate one durable catalog-entry record: parse as JSON,
|
|
33
|
+
* validate as a manifest via {@link parseWorkflowRevisionManifest}, and check
|
|
34
|
+
* that the decoded `(name, revision)` agrees with the caller-supplied
|
|
35
|
+
* expectation (normally read from the storage key itself). Fails closed on
|
|
36
|
+
* any disagreement — shared by {@link restoreWorkflowCatalog}'s per-entry
|
|
37
|
+
* restore, {@link readCatalogEntry}'s single-key read, and the by-name scan
|
|
38
|
+
* `WorkflowCatalog.listInstalledRevisions` uses, so the three consumers of
|
|
39
|
+
* one durable record shape can never validate it three different ways.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* Decode and validate a raw catalog-entry-record byte string against an
|
|
43
|
+
* expected `(name, revision)` — exported for {@link import('./removal.ts').restoreCatalogEntryFromTombstone}'s
|
|
44
|
+
* caller (`WorkflowCatalog.restoreFromTombstone`) and the boot-time orphan
|
|
45
|
+
* sweep (`orphaned-tombstones.ts`) to re-populate the in-memory cache from
|
|
46
|
+
* a tombstone's bytes, which are byte-identical to the entry bytes this
|
|
47
|
+
* function already validates for {@link restoreWorkflowCatalog} and
|
|
48
|
+
* {@link readCatalogEntry}.
|
|
49
|
+
*/
|
|
50
|
+
export declare function decodeCatalogEntryRecord(key: string, bytes: Uint8Array, expectedName: string, expectedRevision: string): Promise<{
|
|
51
|
+
manifest: WorkflowRevisionManifest;
|
|
52
|
+
installedAt: number;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Read one durable installed-revision record for `(name, revision)`, or
|
|
56
|
+
* `null` when absent. Fails closed on corruption, exactly matching
|
|
57
|
+
* {@link restoreWorkflowCatalog}'s per-entry validation — used by
|
|
58
|
+
* `WorkflowCatalog.install()` to read through the local in-memory cache to
|
|
59
|
+
* durable storage, which may already hold this `(name, revision)` key
|
|
60
|
+
* courtesy of a different `WorkflowCatalog` instance/process.
|
|
61
|
+
*/
|
|
62
|
+
export declare function readCatalogEntry(storage: Storage, name: string, revision: string): Promise<{
|
|
63
|
+
manifest: WorkflowRevisionManifest;
|
|
64
|
+
installedAt: number;
|
|
65
|
+
} | null>;
|
|
66
|
+
/**
|
|
67
|
+
* Durably scan every installed revision of `name` — the
|
|
68
|
+
* `catalog-entry:<name>:` prefix `WORKFLOW_CATALOG_KEYS.catalogEntryPrefix`
|
|
69
|
+
* builds. Each record is validated exactly like
|
|
70
|
+
* {@link restoreWorkflowCatalog}'s per-entry restore (via
|
|
71
|
+
* {@link decodeCatalogEntryRecord}, shared rather than duplicated); a
|
|
72
|
+
* corrupt or unparseable entry fails closed rather than being silently
|
|
73
|
+
* skipped. Returns entries in no particular order — callers that need a
|
|
74
|
+
* deterministic order (`WorkflowCatalog.listInstalledRevisions`) sort the
|
|
75
|
+
* result themselves.
|
|
76
|
+
*/
|
|
77
|
+
export declare function scanCatalogEntriesForName(storage: Storage, name: string): Promise<Array<{
|
|
78
|
+
manifest: WorkflowRevisionManifest;
|
|
79
|
+
installedAt: number;
|
|
80
|
+
}>>;
|
|
81
|
+
/** Read one name's durable active pointer, or `null` when absent. */
|
|
82
|
+
export declare function readActivePointer(storage: Storage, name: string): Promise<WorkflowCatalogActivePointer | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Durably write one installed-revision entry, CAS-guarded on the key being
|
|
85
|
+
* absent (`expectedValue: null`). Returns `true` when this write won the
|
|
86
|
+
* race, `false` when another writer had already durably installed this
|
|
87
|
+
* exact `(name, revision)` key first — `WorkflowCatalog.install()` re-reads
|
|
88
|
+
* via {@link readCatalogEntry} on `false` to decide whether that concurrent
|
|
89
|
+
* write was byte-identical (idempotent) or a genuine conflict.
|
|
90
|
+
*
|
|
91
|
+
* CAS-protected rather than a plain `put`: "content-addressed by
|
|
92
|
+
* `(name, revision)`, so racing writers always agree" only holds when
|
|
93
|
+
* `revision` is content-derived. `buildWorkflowRevisionManifest`'s public
|
|
94
|
+
* `options.revision` escape hatch lets a caller supply a non-content-derived
|
|
95
|
+
* revision (e.g. a deploy tag), so two different `WorkflowCatalog`
|
|
96
|
+
* instances/processes — each with their own, independently-seeded
|
|
97
|
+
* in-memory cache — could otherwise race a differing-content write to the
|
|
98
|
+
* same key past each other's in-memory-only conflict check with a plain
|
|
99
|
+
* `put` (last write wins, silently).
|
|
100
|
+
*/
|
|
101
|
+
export declare function writeCatalogEntry(storage: Storage, manifest: WorkflowRevisionManifest, installedAt: number): Promise<boolean>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { KEYS, storageConditionalBatch } from "../../storage/interface.js";
|
|
2
|
+
import { tryDecodeStorageKeyComponent } from "../../storage/key-encoding.js";
|
|
3
|
+
import { parseWorkflowRevisionManifest } from "../contract/manifest-parse.js";
|
|
4
|
+
import { decodeActivePointer } from "./codec.js";
|
|
5
|
+
function splitCatalogEntryKey(key) {
|
|
6
|
+
const parts = key.split(":");
|
|
7
|
+
if (parts.length !== 3)
|
|
8
|
+
return null;
|
|
9
|
+
const name = tryDecodeStorageKeyComponent(parts[1] ?? ""), revision = tryDecodeStorageKeyComponent(parts[2] ?? "");
|
|
10
|
+
if (name === null || revision === null)
|
|
11
|
+
return null;
|
|
12
|
+
return { name, revision };
|
|
13
|
+
}
|
|
14
|
+
function splitCatalogActiveKey(key) {
|
|
15
|
+
const parts = key.split(":");
|
|
16
|
+
if (parts.length !== 2)
|
|
17
|
+
return null;
|
|
18
|
+
return tryDecodeStorageKeyComponent(parts[1] ?? "");
|
|
19
|
+
}
|
|
20
|
+
function parseCatalogEntryRecord(bytes) {
|
|
21
|
+
let parsed;
|
|
22
|
+
try {
|
|
23
|
+
parsed = JSON.parse(new TextDecoder().decode(bytes));
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
28
|
+
return null;
|
|
29
|
+
const record = parsed;
|
|
30
|
+
if (typeof record.installedAt !== "number")
|
|
31
|
+
return null;
|
|
32
|
+
return { manifest: record.manifest, installedAt: record.installedAt };
|
|
33
|
+
}
|
|
34
|
+
function failClosed(kind, key, reason) {
|
|
35
|
+
throw Error(`The store's ${kind} ("${key}") exists but ${reason}. Treating it as absent would risk resurrecting a stale or wrong active workflow revision, so the workflow catalog fails closed instead. Resolve by operator repair: inspect the stored bytes and, only if certain no other engine relies on them, delete the key so it can be re-established.`);
|
|
36
|
+
}
|
|
37
|
+
export async function restoreWorkflowCatalog(storage) {
|
|
38
|
+
const entries = new Map, active = new Map;
|
|
39
|
+
for await (const [key, bytes] of storage.scan("catalog-entry:"))
|
|
40
|
+
await restoreOneCatalogEntry(entries, key, bytes);
|
|
41
|
+
for await (const [key, bytes] of storage.scan("catalog-active:"))
|
|
42
|
+
restoreOneActivePointer(active, key, bytes);
|
|
43
|
+
return { entries, active };
|
|
44
|
+
}
|
|
45
|
+
export async function decodeCatalogEntryRecord(key, bytes, expectedName, expectedRevision) {
|
|
46
|
+
const parsedRecord = parseCatalogEntryRecord(bytes);
|
|
47
|
+
if (parsedRecord === null)
|
|
48
|
+
failClosed("workflow catalog entry", key, "could not be parsed as JSON");
|
|
49
|
+
const parsed = await parseWorkflowRevisionManifest(parsedRecord.manifest);
|
|
50
|
+
if (!parsed.ok)
|
|
51
|
+
failClosed("workflow catalog entry", key, "does not decode as a valid installed-revision record");
|
|
52
|
+
const manifest = parsed.manifest;
|
|
53
|
+
if (manifest.name !== expectedName || manifest.revision !== expectedRevision)
|
|
54
|
+
failClosed("workflow catalog entry", key, "contains a manifest whose (name, revision) disagrees with its storage key");
|
|
55
|
+
return { manifest, installedAt: parsedRecord.installedAt };
|
|
56
|
+
}
|
|
57
|
+
async function restoreOneCatalogEntry(entries, key, bytes) {
|
|
58
|
+
const split = splitCatalogEntryKey(key);
|
|
59
|
+
if (split === null)
|
|
60
|
+
failClosed("workflow catalog entry key", key, "does not match the expected catalog-entry:<name>:<revision> shape");
|
|
61
|
+
const { manifest, installedAt } = await decodeCatalogEntryRecord(key, bytes, split.name, split.revision);
|
|
62
|
+
let byName = entries.get(split.name);
|
|
63
|
+
if (byName === void 0) {
|
|
64
|
+
byName = new Map;
|
|
65
|
+
entries.set(split.name, byName);
|
|
66
|
+
}
|
|
67
|
+
byName.set(split.revision, { manifest, installedAt });
|
|
68
|
+
}
|
|
69
|
+
function restoreOneActivePointer(active, key, bytes) {
|
|
70
|
+
const name = splitCatalogActiveKey(key);
|
|
71
|
+
if (name === null)
|
|
72
|
+
failClosed("workflow catalog active pointer key", key, "does not match the expected catalog-active:<name> shape");
|
|
73
|
+
const pointer = decodeActivePointer(bytes);
|
|
74
|
+
if (pointer === null)
|
|
75
|
+
failClosed("workflow catalog active pointer", key, "does not decode as a valid { revision, generation, activatedAt } record");
|
|
76
|
+
active.set(name, pointer);
|
|
77
|
+
}
|
|
78
|
+
export async function readCatalogEntry(storage, name, revision) {
|
|
79
|
+
const key = KEYS.catalogEntry(name, revision), bytes = await storage.get(key);
|
|
80
|
+
if (bytes === null)
|
|
81
|
+
return null;
|
|
82
|
+
return decodeCatalogEntryRecord(key, bytes, name, revision);
|
|
83
|
+
}
|
|
84
|
+
export async function scanCatalogEntriesForName(storage, name) {
|
|
85
|
+
const results = [];
|
|
86
|
+
for await (const [key, bytes] of storage.scan(KEYS.catalogEntryPrefix(name))) {
|
|
87
|
+
const split = splitCatalogEntryKey(key);
|
|
88
|
+
if (split === null)
|
|
89
|
+
failClosed("workflow catalog entry key", key, "does not match the expected catalog-entry:<name>:<revision> shape");
|
|
90
|
+
results.push(await decodeCatalogEntryRecord(key, bytes, split.name, split.revision));
|
|
91
|
+
}
|
|
92
|
+
return results;
|
|
93
|
+
}
|
|
94
|
+
export async function readActivePointer(storage, name) {
|
|
95
|
+
const bytes = await storage.get(KEYS.catalogActive(name));
|
|
96
|
+
if (bytes === null)
|
|
97
|
+
return null;
|
|
98
|
+
const pointer = decodeActivePointer(bytes);
|
|
99
|
+
if (pointer === null)
|
|
100
|
+
failClosed("workflow catalog active pointer", KEYS.catalogActive(name), "does not decode as a valid { revision, generation, activatedAt } record");
|
|
101
|
+
return pointer;
|
|
102
|
+
}
|
|
103
|
+
export async function writeCatalogEntry(storage, manifest, installedAt) {
|
|
104
|
+
const bytes = new TextEncoder().encode(JSON.stringify({ manifest, installedAt })), key = KEYS.catalogEntry(manifest.name, manifest.revision);
|
|
105
|
+
return storageConditionalBatch(storage, [{ key, expectedValue: null }], [{ type: "put", key, value: bytes }]);
|
|
106
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory and wire types for the durable workflow catalog (WFT-9/WFT-10).
|
|
3
|
+
*
|
|
4
|
+
* `WorkflowCatalog` keys entries with nested `Map<string, Map<string, ...>>`
|
|
5
|
+
* structures — never delimiter-joined strings — so a workflow `name` or
|
|
6
|
+
* `revision` equal to `'__proto__'`, `'toString'`, or containing a colon is
|
|
7
|
+
* always safe to store and look up.
|
|
8
|
+
*
|
|
9
|
+
* @module core/catalog/types
|
|
10
|
+
*/
|
|
11
|
+
import type { WorkflowCompatibilityVerdict } from '../contract/compatibility.ts';
|
|
12
|
+
import type { WorkflowRevisionManifest } from '../contract/types.ts';
|
|
13
|
+
import type { RegisteredWorkflowDefinition } from '../types/workflow-registry.ts';
|
|
14
|
+
/**
|
|
15
|
+
* One installed `(name, revision)` catalog entry. `definition` is populated
|
|
16
|
+
* only when this process itself installed the entry (via
|
|
17
|
+
* `engine.register()`'s drain path) — an entry hydrated from durable storage
|
|
18
|
+
* at boot, for a revision this process has not (yet) registered, carries no
|
|
19
|
+
* live `definition` because a `RegisteredWorkflowDefinition` cannot be
|
|
20
|
+
* persisted (it holds function references). Consumers that only need
|
|
21
|
+
* identity (`resolveActive`, registry-snapshot's `activeRevisions`) never
|
|
22
|
+
* touch `definition`.
|
|
23
|
+
*/
|
|
24
|
+
export type WorkflowCatalogEntry = Readonly<{
|
|
25
|
+
manifest: WorkflowRevisionManifest;
|
|
26
|
+
definition?: RegisteredWorkflowDefinition;
|
|
27
|
+
installedAt: number;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* The durable `{ revision, generation, activatedAt }` pointer for one
|
|
31
|
+
* workflow name — what `engine.workflows.getActive()` returns.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { Engine } from '@lostgradient/weft';
|
|
36
|
+
* import type { WorkflowCatalogActivePointer } from '@lostgradient/weft';
|
|
37
|
+
*
|
|
38
|
+
* const engine = new Engine();
|
|
39
|
+
* const pointer: WorkflowCatalogActivePointer | null = await engine.workflows.getActive('checkout');
|
|
40
|
+
* console.log(pointer?.generation ?? null);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export type WorkflowCatalogActivePointer = Readonly<{
|
|
44
|
+
revision: string;
|
|
45
|
+
generation: number;
|
|
46
|
+
activatedAt: number;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Public-facing view of one installed `(name, revision)` catalog entry —
|
|
50
|
+
* {@link WorkflowCatalogEntry} minus `definition`, which can carry a live
|
|
51
|
+
* function reference and must never reach a public return value.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Engine } from '@lostgradient/weft';
|
|
56
|
+
* import type { WorkflowRevisionRecord } from '@lostgradient/weft';
|
|
57
|
+
*
|
|
58
|
+
* const engine = new Engine();
|
|
59
|
+
* const record: WorkflowRevisionRecord | null = await engine.workflows.getRevision(
|
|
60
|
+
* 'checkout',
|
|
61
|
+
* 'some-revision',
|
|
62
|
+
* );
|
|
63
|
+
* console.log(record?.manifest.revision ?? null);
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export type WorkflowRevisionRecord = Readonly<{
|
|
67
|
+
manifest: WorkflowRevisionManifest;
|
|
68
|
+
installedAt: number;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Result of {@link import('./workflow-catalog.ts').WorkflowCatalog.activateCandidate}.
|
|
72
|
+
* A candidate either applies (bumping the durable generation) or is refused
|
|
73
|
+
* with a specific, machine-readable reason — never silently ignored.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* import { Engine } from '@lostgradient/weft';
|
|
78
|
+
* import type { WorkflowCatalogActivationResult } from '@lostgradient/weft';
|
|
79
|
+
*
|
|
80
|
+
* const engine = new Engine();
|
|
81
|
+
* const active = await engine.workflows.getActive('checkout');
|
|
82
|
+
* const result: WorkflowCatalogActivationResult = await engine.workflows.activate(
|
|
83
|
+
* 'checkout',
|
|
84
|
+
* active?.revision ?? '',
|
|
85
|
+
* active === null ? {} : { expectedGeneration: active.generation },
|
|
86
|
+
* );
|
|
87
|
+
* console.log(result.applied);
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export type WorkflowCatalogActivationResult = Readonly<{
|
|
91
|
+
applied: true;
|
|
92
|
+
pointer: WorkflowCatalogActivePointer;
|
|
93
|
+
}> | Readonly<{
|
|
94
|
+
applied: false;
|
|
95
|
+
reason: 'incompatible';
|
|
96
|
+
verdict: WorkflowCompatibilityVerdict;
|
|
97
|
+
}> | Readonly<{
|
|
98
|
+
applied: false;
|
|
99
|
+
reason: 'stale-generation';
|
|
100
|
+
currentGeneration: number;
|
|
101
|
+
}> | Readonly<{
|
|
102
|
+
applied: false;
|
|
103
|
+
reason: 'conflict';
|
|
104
|
+
}> | Readonly<{
|
|
105
|
+
applied: false;
|
|
106
|
+
reason: 'expected-generation-required';
|
|
107
|
+
currentGeneration: number;
|
|
108
|
+
}>;
|
|
File without changes
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `WorkflowCatalog` — the immutable-entry, durable workflow catalog
|
|
3
|
+
* (WFT-9/WFT-10).
|
|
4
|
+
*
|
|
5
|
+
* In-memory state is `Map<string, Map<string, WorkflowCatalogEntry>>` for
|
|
6
|
+
* installed entries and `Map<string, WorkflowCatalogActivePointer>` for each
|
|
7
|
+
* name's active pointer — nested maps, never delimiter-joined keys, so a
|
|
8
|
+
* workflow `name` or `revision` equal to `'__proto__'`/`'toString'` or
|
|
9
|
+
* containing a colon is always handled correctly.
|
|
10
|
+
*
|
|
11
|
+
* Two activation entry points exist, matching WFT-9/WFT-10's distinct
|
|
12
|
+
* producers:
|
|
13
|
+
*
|
|
14
|
+
* - {@link WorkflowCatalog.activateRegistered} — unconditional, used
|
|
15
|
+
* exclusively by `engine.register()`'s drain path
|
|
16
|
+
* (`core/engine/catalog-readiness.ts`). Never consults
|
|
17
|
+
* `checkWorkflowCompatibility`; always wins via a bounded 5-attempt CAS
|
|
18
|
+
* retry loop. Registering a different version of an already-registered
|
|
19
|
+
* workflow must never hard-fail construction or registration (the
|
|
20
|
+
* `version-mismatch-recovery.test.ts` precedent), which is why this path
|
|
21
|
+
* is unconditional. "Unconditional" is about bypassing
|
|
22
|
+
* `checkWorkflowCompatibility`, not immunity to failure in general: under
|
|
23
|
+
* sustained contention the bounded 5-attempt CAS retry can still exhaust
|
|
24
|
+
* and throw {@link WorkflowCatalogActivationConflictError}, which
|
|
25
|
+
* propagates out of `ensureWorkflowCatalogReady` and fails
|
|
26
|
+
* `Engine.create()` itself (safely — `Engine.create()`'s `try`/`catch`
|
|
27
|
+
* disposes the half-booted engine before rethrowing).
|
|
28
|
+
* - {@link WorkflowCatalog.activateCandidate} — the guarded primitive:
|
|
29
|
+
* `checkWorkflowCompatibility`-gated, single-shot CAS (no retry — the
|
|
30
|
+
* caller decides whether to re-read and retry), refuses on incompatibility
|
|
31
|
+
* or a stale expected generation. As of WFT-11, reachable by external
|
|
32
|
+
* callers via `engine.workflows.activate()` — the first production
|
|
33
|
+
* caller. Because a multi-writer caller can activate a revision this
|
|
34
|
+
* process's `#entries` cache never observed, the compatibility check
|
|
35
|
+
* reads through to durable storage rather than trusting the cache.
|
|
36
|
+
* Reused as-is by later dynamic-loading work (WFT-13+).
|
|
37
|
+
*
|
|
38
|
+
* @module core/catalog/workflow-catalog
|
|
39
|
+
*/
|
|
40
|
+
import { type Storage } from '../../storage/interface.ts';
|
|
41
|
+
import { type WorkflowCompatibilityPolicy } from '../contract/compatibility.ts';
|
|
42
|
+
import type { WorkflowRevisionManifest } from '../contract/types.ts';
|
|
43
|
+
import type { RegisteredWorkflowDefinition } from '../types/workflow-registry.ts';
|
|
44
|
+
import { type WorkflowCatalogRemovalOutcome } from './removal.ts';
|
|
45
|
+
import { type RestoredWorkflowCatalogState } from './storage-io.ts';
|
|
46
|
+
import type { WorkflowCatalogActivationResult, WorkflowCatalogActivePointer, WorkflowCatalogEntry, WorkflowRevisionRecord } from './types.ts';
|
|
47
|
+
/** Options accepted by {@link WorkflowCatalog.activateCandidate}. */
|
|
48
|
+
export type ActivateCandidateOptions = {
|
|
49
|
+
/** The generation this caller last observed; refused with `stale-generation` if it disagrees with the durable pointer. */
|
|
50
|
+
expectedGeneration?: number;
|
|
51
|
+
/** Compatibility policy; defaults to {@link DEFAULT_WORKFLOW_COMPATIBILITY_POLICY}. */
|
|
52
|
+
policy?: WorkflowCompatibilityPolicy;
|
|
53
|
+
};
|
|
54
|
+
export declare class WorkflowCatalog {
|
|
55
|
+
#private;
|
|
56
|
+
constructor(storage: Storage, seed?: RestoredWorkflowCatalogState);
|
|
57
|
+
/** Look up one installed `(name, revision)` entry, or `undefined` when not installed. */
|
|
58
|
+
getEntry(name: string, revision: string): WorkflowCatalogEntry | undefined;
|
|
59
|
+
/** Every installed revision of `name`, in no particular order. */
|
|
60
|
+
listRevisions(name: string): readonly WorkflowCatalogEntry[];
|
|
61
|
+
/** The current active pointer for `name`, or `undefined` when never activated. */
|
|
62
|
+
resolveActive(name: string): WorkflowCatalogActivePointer | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve one installed `(name, revision)` entry as a public
|
|
65
|
+
* {@link WorkflowRevisionRecord} — cache hit first, else a durable
|
|
66
|
+
* read-through via {@link readCatalogEntry} (adopted into the local cache
|
|
67
|
+
* on hit, exactly like `install()`'s own read-through), else `undefined`
|
|
68
|
+
* when truly absent. No TOCTOU gap against a concurrent `install()` on
|
|
69
|
+
* this same instance: JS is single-threaded and neither this method nor
|
|
70
|
+
* `install()`'s fast (already-cached) path yields between the cache read
|
|
71
|
+
* and its use.
|
|
72
|
+
*/
|
|
73
|
+
resolveEntry(name: string, revision: string): Promise<WorkflowRevisionRecord | undefined>;
|
|
74
|
+
/**
|
|
75
|
+
* Every durably installed revision of `name`, sorted by {@link compareCodepoint}
|
|
76
|
+
* on `revision` for a deterministic order — never `localeCompare`, per
|
|
77
|
+
* this codebase's determinism rule. Durable scan via
|
|
78
|
+
* {@link scanCatalogEntriesForName}, validated the same fail-closed way
|
|
79
|
+
* {@link restoreWorkflowCatalog} validates every entry it restores.
|
|
80
|
+
* Returns an empty array for an unknown name rather than throwing.
|
|
81
|
+
*/
|
|
82
|
+
listInstalledRevisions(name: string): Promise<readonly WorkflowRevisionRecord[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Whether `(name, revision)` is already durably installed — checked
|
|
85
|
+
* against this process's in-memory cache first, then, on a cache miss,
|
|
86
|
+
* durable storage itself (a different process may have installed it).
|
|
87
|
+
* Used by `catalog-events.ts`'s installed/activated/draining dispatch
|
|
88
|
+
* helper to decide whether an activation call is installing genuinely
|
|
89
|
+
* new content, since `install()`'s own cache-hit branch does not
|
|
90
|
+
* distinguish "already known to this process" from "just installed a
|
|
91
|
+
* moment ago by this same call."
|
|
92
|
+
*/
|
|
93
|
+
hasInstalled(name: string, revision: string): Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Durably resolve `name`'s active pointer — always reads through to
|
|
96
|
+
* durable storage rather than trusting the in-memory `#active` cache.
|
|
97
|
+
* Deliberately NOT cache-first like {@link hasInstalled}: `hasInstalled`'s
|
|
98
|
+
* cache-hit short-circuit can only go stale in the SAFE direction (a
|
|
99
|
+
* different process's `remove()` durably deleting an entry this
|
|
100
|
+
* process's `#entries` still holds still lets `catalog.remove()`'s own
|
|
101
|
+
* durable re-read refuse with `'not-found'` rather than double-deleting),
|
|
102
|
+
* whereas a name's active pointer has no such one-directional guarantee —
|
|
103
|
+
* a second engine/process can durably move it (e.g. via
|
|
104
|
+
* `activateCandidate`, or a second engine holding the ADR 0002
|
|
105
|
+
* workflow-lease) to a revision this process never installed at all, so a
|
|
106
|
+
* stale cache HIT here can misreport a durably-active revision as
|
|
107
|
+
* inactive. Used by removal and diagnostics
|
|
108
|
+
* (`core/engine/catalog-removal.ts`) so a durably-active revision is
|
|
109
|
+
* never misreported as inactive/removable; `resolveActive` stays the
|
|
110
|
+
* cheap, synchronous, best-effort accessor for in-process callers (e.g.
|
|
111
|
+
* `reserveInFlightStart`) that only care about this process's own view.
|
|
112
|
+
*/
|
|
113
|
+
resolveActiveDurable(name: string): Promise<WorkflowCatalogActivePointer | undefined>;
|
|
114
|
+
/**
|
|
115
|
+
* Durably remove the installed `(name, revision)` entry — delegates the
|
|
116
|
+
* CAS mechanics to {@link removeCatalogEntry}. On success, evicts the
|
|
117
|
+
* entry from this process's in-memory `#entries` cache too, so a
|
|
118
|
+
* subsequent `getEntry`/`listRevisions` call in this same process never
|
|
119
|
+
* observes a removed revision. Refuses (`'active'`) when `revision` is
|
|
120
|
+
* currently the active pointer for `name` — a structural invariant this
|
|
121
|
+
* method itself enforces, independent of any reference-count decision a
|
|
122
|
+
* caller layers on top (see `core/engine/catalog-removal.ts`).
|
|
123
|
+
*/
|
|
124
|
+
remove(name: string, revision: string): Promise<WorkflowCatalogRemovalOutcome>;
|
|
125
|
+
/**
|
|
126
|
+
* Install `manifest` (paired with `definition`, when this process holds
|
|
127
|
+
* one). Idempotent on a byte-identical reinstall for the same
|
|
128
|
+
* `(name, revision)` key; throws {@link WorkflowCatalogConflictError} when
|
|
129
|
+
* an existing entry for that key has different manifest content —
|
|
130
|
+
* checked against BOTH this process's in-memory cache and, on a cache
|
|
131
|
+
* miss, durable storage itself (a different `WorkflowCatalog`
|
|
132
|
+
* instance/process may already have installed this exact key). The
|
|
133
|
+
* durable write is CAS-guarded ({@link writeCatalogEntry}) rather than a
|
|
134
|
+
* plain `put`, so two processes racing to install genuinely different
|
|
135
|
+
* content under the same key — possible whenever `revision` is an
|
|
136
|
+
* explicit, non-content-derived caller value rather than the default
|
|
137
|
+
* content hash — cannot silently last-write-win each other; the loser
|
|
138
|
+
* re-reads and resolves through the same idempotent/conflict check.
|
|
139
|
+
*
|
|
140
|
+
* Defensively re-validates `name` against the wire-safe name grammar even
|
|
141
|
+
* though `engine.register()`'s existing `validateWorkflowOrActivityName`
|
|
142
|
+
* already guarantees this for the only current producer — `install()` is
|
|
143
|
+
* deliberately safe for a future producer that is not `engine.register()`.
|
|
144
|
+
*/
|
|
145
|
+
install(manifest: WorkflowRevisionManifest, definition?: RegisteredWorkflowDefinition): Promise<WorkflowCatalogEntry>;
|
|
146
|
+
/**
|
|
147
|
+
* Unconditionally activate `manifest` for `name`, installing it first if
|
|
148
|
+
* needed. Used exclusively by `engine.register()`'s drain path — never
|
|
149
|
+
* consults `checkWorkflowCompatibility`. Reactivating the currently active
|
|
150
|
+
* revision is a no-op (generation unchanged); activating a different
|
|
151
|
+
* revision bumps the generation by exactly 1. Retries the CAS write up to
|
|
152
|
+
* {@link MAX_ACTIVATE_REGISTERED_ATTEMPTS} times under contention, throwing
|
|
153
|
+
* {@link WorkflowCatalogActivationConflictError} on exhaustion.
|
|
154
|
+
*/
|
|
155
|
+
activateRegistered(name: string, manifest: WorkflowRevisionManifest, definition: RegisteredWorkflowDefinition): Promise<WorkflowCatalogActivePointer>;
|
|
156
|
+
/**
|
|
157
|
+
* The guarded activation primitive: reads the currently-active manifest
|
|
158
|
+
* for `name` (absence is treated as automatically compatible — first
|
|
159
|
+
* activation), checks `checkWorkflowCompatibility`, and refuses rather
|
|
160
|
+
* than applies when incompatible or when `expectedGeneration` disagrees
|
|
161
|
+
* with the durably-read generation. Single-shot CAS write — no retry; the
|
|
162
|
+
* caller decides whether to re-read and retry.
|
|
163
|
+
*/
|
|
164
|
+
activateCandidate(name: string, candidateManifest: WorkflowRevisionManifest, options?: ActivateCandidateOptions): Promise<WorkflowCatalogActivationResult>;
|
|
165
|
+
}
|