@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,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared validation and fault mapping for the five `weft.workflows.revisions.*`
|
|
3
|
+
* / `weft.workflows.active.*` operations (WFT-11): `install-workflow-revision.ts`,
|
|
4
|
+
* `activate-workflow-revision.ts`, `get-workflow-revision.ts`,
|
|
5
|
+
* `list-workflow-revisions.ts`, `get-active-workflow-revision.ts`.
|
|
6
|
+
*
|
|
7
|
+
* @module server/operations/workflow-catalog-operation-helpers
|
|
8
|
+
*/
|
|
9
|
+
import { type WorkflowCatalogActivationResult } from '../../core/catalog/index.ts';
|
|
10
|
+
import type { WorkflowCompatibilityPolicy } from '../../core/contract/compatibility.ts';
|
|
11
|
+
import type { WorkflowRevisionManifest } from '../../core/contract/types.ts';
|
|
12
|
+
import type { AccessPolicy } from '../authorization.ts';
|
|
13
|
+
import type { OperationFault } from '../operation-fault.ts';
|
|
14
|
+
import type { RestInputContext } from '../rest-binding.ts';
|
|
15
|
+
/** `workflows:admin` — required by `install` and `activate` (mutating). */
|
|
16
|
+
export declare const workflowsAdminAccess: AccessPolicy;
|
|
17
|
+
/** `workflows:read` — required by `get`/`list`/`active.get` (read-only). */
|
|
18
|
+
export declare const workflowsReadAccess: AccessPolicy;
|
|
19
|
+
/**
|
|
20
|
+
* Validate one `name` field per the wire-safe name grammar, raising the
|
|
21
|
+
* same `InvalidParams` fault both REST and JSON-RPC callers see for every
|
|
22
|
+
* other malformed identifier in this operation family. Bounded by
|
|
23
|
+
* `validateWorkflowOrActivityName` itself (`MAX_CONTRACT_IDENTIFIER_BYTES`).
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateWorkflowNameField(name: unknown): string;
|
|
26
|
+
/** Validate one `revision` field: a non-empty, bounded opaque string. */
|
|
27
|
+
export declare function validateWorkflowRevisionField(revision: unknown): string;
|
|
28
|
+
/** Validate an optional `expectedGeneration` field: a non-negative safe integer. */
|
|
29
|
+
export declare function validateExpectedGenerationField(value: unknown): number | undefined;
|
|
30
|
+
/** Validate an optional `policy` field against the one tunable compatibility axis. */
|
|
31
|
+
export declare function validatePolicyField(value: unknown): WorkflowCompatibilityPolicy | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Validate an untrusted `manifest` field via {@link parseWorkflowRevisionManifest} —
|
|
34
|
+
* the same hostile-input validation path (bounded sizes, recomputed
|
|
35
|
+
* `contractHash`) every other manifest consumer in this codebase uses.
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateManifestField(value: unknown): Promise<WorkflowRevisionManifest>;
|
|
38
|
+
/**
|
|
39
|
+
* Map one `applied: false` {@link WorkflowCatalogActivationResult} variant to
|
|
40
|
+
* the canonical `Conflict` fault. Exhaustive over all four refusal reasons —
|
|
41
|
+
* adding a fifth is a compile error here, forcing a deliberate wire mapping.
|
|
42
|
+
*/
|
|
43
|
+
export declare function activationRefusalToFault(result: Extract<WorkflowCatalogActivationResult, {
|
|
44
|
+
applied: false;
|
|
45
|
+
}>): OperationFault;
|
|
46
|
+
/**
|
|
47
|
+
* Map an error thrown by `engine.workflows.install()`/`activate()` to the
|
|
48
|
+
* canonical operation fault, or rethrow unchanged when it is neither typed
|
|
49
|
+
* error this family can produce (letting the operation pipeline's generic
|
|
50
|
+
* `EngineFailure` wrapping handle anything else).
|
|
51
|
+
*/
|
|
52
|
+
export declare function throwWorkflowCatalogOperationFault(error: unknown): never;
|
|
53
|
+
/**
|
|
54
|
+
* Read a REST request body as a JSON object, raising `InvalidParams` for
|
|
55
|
+
* malformed JSON or a non-object top-level value — shared by
|
|
56
|
+
* `install-workflow-revision.ts` (body-only) and
|
|
57
|
+
* `activate-workflow-revision.ts` (path `name` plus body fields).
|
|
58
|
+
*/
|
|
59
|
+
export declare function readWorkflowCatalogRestBody(request: Request, context: RestInputContext): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import {
|
|
3
|
+
WorkflowCatalogConflictError,
|
|
4
|
+
WorkflowRevisionNotInstalledError
|
|
5
|
+
} from "../../core/catalog/index.js";
|
|
6
|
+
import { MAX_CONTRACT_IDENTIFIER_BYTES } from "../../core/contract/limits.js";
|
|
7
|
+
import { parseWorkflowRevisionManifest } from "../../core/contract/manifest-parse.js";
|
|
8
|
+
import {
|
|
9
|
+
DynamicWorkflowSourceUnavailableError,
|
|
10
|
+
WorkflowSourceNotRegisteredError
|
|
11
|
+
} from "../../core/engine/dynamic-source-errors.js";
|
|
12
|
+
import { WorkflowNotRegisteredError } from "../../core/engine/errors.js";
|
|
13
|
+
import { WorkflowSourceValidationError } from "../../core/source/errors.js";
|
|
14
|
+
import { validateWorkflowOrActivityName } from "../../core/types/name-grammar.js";
|
|
15
|
+
import { readRestJsonBody } from "../rest-body.js";
|
|
16
|
+
import { invalidParamsFault, isOperationFault } from "./operation-helpers.js";
|
|
17
|
+
export const workflowsAdminAccess = {
|
|
18
|
+
kind: "scoped",
|
|
19
|
+
scopes: { kind: "anyOf", scopes: ["workflows:admin"] }
|
|
20
|
+
}, workflowsReadAccess = {
|
|
21
|
+
kind: "scoped",
|
|
22
|
+
scopes: { kind: "anyOf", scopes: ["workflows:read"] }
|
|
23
|
+
};
|
|
24
|
+
export function validateWorkflowNameField(name) {
|
|
25
|
+
if (typeof name !== "string" || name.length === 0)
|
|
26
|
+
throw invalidParamsFault('Field "name" must be a non-empty string');
|
|
27
|
+
try {
|
|
28
|
+
validateWorkflowOrActivityName(name, "workflow");
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw invalidParamsFault(error instanceof Error ? error.message : String(error));
|
|
31
|
+
}
|
|
32
|
+
return name;
|
|
33
|
+
}
|
|
34
|
+
export function validateWorkflowRevisionField(revision) {
|
|
35
|
+
if (typeof revision !== "string" || revision.length === 0)
|
|
36
|
+
throw invalidParamsFault('Field "revision" must be a non-empty string');
|
|
37
|
+
if (new TextEncoder().encode(revision).byteLength > MAX_CONTRACT_IDENTIFIER_BYTES)
|
|
38
|
+
throw invalidParamsFault(`Field "revision" exceeds the maximum identifier size of ${String(MAX_CONTRACT_IDENTIFIER_BYTES)} bytes`);
|
|
39
|
+
return revision;
|
|
40
|
+
}
|
|
41
|
+
export function validateExpectedGenerationField(value) {
|
|
42
|
+
if (value === void 0)
|
|
43
|
+
return;
|
|
44
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
45
|
+
throw invalidParamsFault('Field "expectedGeneration" must be a non-negative integer');
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
const compatibilityPolicyShape = z.object({ requireExactRevision: z.boolean().optional() }).strict();
|
|
49
|
+
export function validatePolicyField(value) {
|
|
50
|
+
if (value === void 0)
|
|
51
|
+
return;
|
|
52
|
+
const parsed = compatibilityPolicyShape.safeParse(value);
|
|
53
|
+
if (!parsed.success)
|
|
54
|
+
throw invalidParamsFault('Field "policy" must be an object with an optional boolean "requireExactRevision"');
|
|
55
|
+
return parsed.data.requireExactRevision === void 0 ? {} : { requireExactRevision: parsed.data.requireExactRevision };
|
|
56
|
+
}
|
|
57
|
+
export async function validateManifestField(value) {
|
|
58
|
+
const result = await parseWorkflowRevisionManifest(value);
|
|
59
|
+
if (!result.ok)
|
|
60
|
+
throw manifestValidationFailureFault(result);
|
|
61
|
+
return result.manifest;
|
|
62
|
+
}
|
|
63
|
+
function manifestValidationFailureFault(failure) {
|
|
64
|
+
return {
|
|
65
|
+
code: "InvalidParams",
|
|
66
|
+
message: failure.message,
|
|
67
|
+
data: {
|
|
68
|
+
issues: [
|
|
69
|
+
{
|
|
70
|
+
path: failure.path === void 0 ? [] : failure.path.split("."),
|
|
71
|
+
message: failure.message,
|
|
72
|
+
code: failure.reason
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function activationRefusalToFault(result) {
|
|
79
|
+
switch (result.reason) {
|
|
80
|
+
case "incompatible": {
|
|
81
|
+
const { verdict } = result, reasons = verdict.compatible ? [] : verdict.reasons;
|
|
82
|
+
return {
|
|
83
|
+
code: "Conflict",
|
|
84
|
+
message: `Candidate revision is incompatible with the currently active revision: ${reasons.join(", ")}`,
|
|
85
|
+
data: { reason: result.reason, compatibilityReasons: reasons }
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
case "stale-generation":
|
|
89
|
+
return {
|
|
90
|
+
code: "Conflict",
|
|
91
|
+
message: `Stale expectedGeneration: the current durable generation is ${String(result.currentGeneration)}`,
|
|
92
|
+
data: { reason: result.reason, currentGeneration: result.currentGeneration }
|
|
93
|
+
};
|
|
94
|
+
case "expected-generation-required":
|
|
95
|
+
return {
|
|
96
|
+
code: "Conflict",
|
|
97
|
+
message: "expectedGeneration is required once a workflow has an active revision \u2014 current " + `generation is ${String(result.currentGeneration)}`,
|
|
98
|
+
data: { reason: result.reason, currentGeneration: result.currentGeneration }
|
|
99
|
+
};
|
|
100
|
+
case "conflict":
|
|
101
|
+
return {
|
|
102
|
+
code: "Conflict",
|
|
103
|
+
message: "Activation lost a concurrent write race; re-read the active pointer and retry",
|
|
104
|
+
data: { reason: result.reason }
|
|
105
|
+
};
|
|
106
|
+
default:
|
|
107
|
+
throw Error(`Unknown activation refusal reason: ${JSON.stringify(result)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function throwWorkflowCatalogOperationFault(error) {
|
|
111
|
+
if (error instanceof WorkflowRevisionNotInstalledError)
|
|
112
|
+
throw {
|
|
113
|
+
code: "NotFound",
|
|
114
|
+
message: error.message,
|
|
115
|
+
data: {
|
|
116
|
+
resource: "workflow-revision",
|
|
117
|
+
identifier: `${error.workflowName}:${error.revision}`,
|
|
118
|
+
weftCode: error.code
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
if (error instanceof WorkflowNotRegisteredError)
|
|
122
|
+
throw invalidParamsFault(error.message, error.code);
|
|
123
|
+
if (error instanceof WorkflowCatalogConflictError)
|
|
124
|
+
throw {
|
|
125
|
+
code: "Conflict",
|
|
126
|
+
message: error.message,
|
|
127
|
+
data: { reason: "catalog-conflict", weftCode: error.code }
|
|
128
|
+
};
|
|
129
|
+
if (error instanceof WorkflowSourceNotRegisteredError)
|
|
130
|
+
throw {
|
|
131
|
+
code: "NotFound",
|
|
132
|
+
message: error.message,
|
|
133
|
+
data: { resource: "workflow-source", identifier: error.workflowType, weftCode: error.code }
|
|
134
|
+
};
|
|
135
|
+
if (error instanceof DynamicWorkflowSourceUnavailableError)
|
|
136
|
+
throw {
|
|
137
|
+
code: "Conflict",
|
|
138
|
+
message: error.reason === "load-failed" ? `Dynamic workflow source "${error.workflowType}"${error.revision === void 0 ? "" : ` revision "${error.revision}"`} failed to load.` : error.message,
|
|
139
|
+
data: { reason: error.reason, weftCode: error.code }
|
|
140
|
+
};
|
|
141
|
+
if (error instanceof WorkflowSourceValidationError)
|
|
142
|
+
throw {
|
|
143
|
+
code: "Conflict",
|
|
144
|
+
message: error.message,
|
|
145
|
+
data: {
|
|
146
|
+
reason: "validation-failed",
|
|
147
|
+
sourceValidationReasons: error.reasons,
|
|
148
|
+
weftCode: error.code
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
export async function readWorkflowCatalogRestBody(request, context) {
|
|
154
|
+
const body = await readRestJsonBody(request, context).catch((error) => {
|
|
155
|
+
if (isOperationFault(error))
|
|
156
|
+
throw error;
|
|
157
|
+
return null;
|
|
158
|
+
});
|
|
159
|
+
if (typeof body !== "object" || body === null || Array.isArray(body))
|
|
160
|
+
throw invalidParamsFault("Request body must be a JSON object.");
|
|
161
|
+
return body;
|
|
162
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the durable task-ledger envelope a fresh dispatch would create if no
|
|
3
|
+
* ledger record exists yet — split out of `task-dispatch.ts` purely to stay
|
|
4
|
+
* under this repository's 500-line-per-file ceiling, matching the existing
|
|
5
|
+
* `task-dispatch-revision.ts` precedent. There is no behavioral reason to
|
|
6
|
+
* import this module directly instead of `task-dispatch.ts`, which calls it
|
|
7
|
+
* from both `selectAndReserveWorker` and `enqueueTaskForLongPoll`.
|
|
8
|
+
*
|
|
9
|
+
* @module server/runtime/task-dispatch-envelope
|
|
10
|
+
*/
|
|
11
|
+
import type { TaskDispatch } from '../index.ts';
|
|
12
|
+
import type { CreateQueuedInput } from '../task-ledger-transitions.ts';
|
|
13
|
+
/** The durable envelope every fresh dispatch would create if no ledger record exists yet. */
|
|
14
|
+
export declare function buildCreateQueuedInput(task: TaskDispatch, queue: string, visibilityTimeout: number): CreateQueuedInput;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isJSONValue } from "../../core/json.js";
|
|
2
|
+
import { isValidWorkflowRevision, REMOTE_TASK_RECORD_VERSION } from "../task-ledger.js";
|
|
3
|
+
function buildOptionalCreateQueuedFields(task) {
|
|
4
|
+
return {
|
|
5
|
+
...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
|
|
6
|
+
...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
|
|
7
|
+
...task.workflowRevision !== void 0 ? { workflowRevision: task.workflowRevision } : {},
|
|
8
|
+
...task.priority !== void 0 ? { priority: task.priority } : {},
|
|
9
|
+
...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
|
|
10
|
+
...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
|
|
11
|
+
...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function buildCreateQueuedInput(task, queue, visibilityTimeout) {
|
|
15
|
+
const input = task.input === void 0 ? null : task.input;
|
|
16
|
+
if (!isJSONValue(input))
|
|
17
|
+
throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
|
|
18
|
+
if (task.workflowRevision !== void 0 && !isValidWorkflowRevision(task.workflowRevision))
|
|
19
|
+
throw Error(`TaskDispatch for operation "${task.operationId}" has an invalid "workflowRevision" \u2014 it must be a non-empty, bounded identifier.`);
|
|
20
|
+
return {
|
|
21
|
+
recordVersion: REMOTE_TASK_RECORD_VERSION,
|
|
22
|
+
operationId: task.operationId,
|
|
23
|
+
workflowType: task.workflowType,
|
|
24
|
+
activityName: task.activityName,
|
|
25
|
+
queue,
|
|
26
|
+
input,
|
|
27
|
+
headers: task.headers ?? {},
|
|
28
|
+
visibilityTimeoutMilliseconds: visibilityTimeout,
|
|
29
|
+
createdAt: Date.now(),
|
|
30
|
+
...buildOptionalCreateQueuedFields(task)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch-time revision staleness gate (WFT-20) — split out of
|
|
3
|
+
* `task-dispatch.ts` purely to stay under this repository's 500-line-per-file
|
|
4
|
+
* ceiling; there is no behavioral reason to import this module directly
|
|
5
|
+
* instead of `task-dispatch.ts`, which calls it from `dispatchTaskImpl`.
|
|
6
|
+
*
|
|
7
|
+
* @module server/runtime/task-dispatch-revision
|
|
8
|
+
*/
|
|
9
|
+
import { type ConditionalBatchCondition } from '../../storage/interface.ts';
|
|
10
|
+
import type { ServeOptions, TaskDispatch } from '../index.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Reject a dispatch whose caller-supplied `workflowRevision` disagrees with
|
|
13
|
+
* `task.workflowId`'s persisted `WorkflowState.revision` — a bounded,
|
|
14
|
+
* structured failure BEFORE any worker reservation or ledger write. A no-op
|
|
15
|
+
* (never reads storage) unless BOTH `workflowId` and `workflowRevision` are
|
|
16
|
+
* supplied; a no-op when no persisted `WorkflowState` exists for `workflowId`
|
|
17
|
+
* yet (nothing to compare against — the caller opted into an extra read, not
|
|
18
|
+
* an extra existence requirement).
|
|
19
|
+
*
|
|
20
|
+
* Returns the `conditionalBatch` precondition(s) (empty when this check was a
|
|
21
|
+
* no-op) that fence the CALLER's own ledger commit on the exact workflow-state
|
|
22
|
+
* bytes just read here. This check alone is only a pre-commit read: a
|
|
23
|
+
* `start-new` restart could still displace the workflow to a different
|
|
24
|
+
* revision in the gap between this read and the caller's later ledger write.
|
|
25
|
+
* The caller MUST include the returned conditions in the SAME
|
|
26
|
+
* `conditionalBatch` call that commits the ledger record, so that gap closes
|
|
27
|
+
* atomically instead of merely being read-checked up front (WFT-20).
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertDispatchTargetsFreshRevision(options: ServeOptions, task: TaskDispatch): Promise<ConditionalBatchCondition[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { decodeWorkflowState } from "../../core/engine/validation.js";
|
|
2
|
+
import { KEYS } from "../../storage/interface.js";
|
|
3
|
+
export async function assertDispatchTargetsFreshRevision(options, task) {
|
|
4
|
+
if (task.workflowId === void 0 || task.workflowRevision === void 0)
|
|
5
|
+
return [];
|
|
6
|
+
const workflowKey = KEYS.workflow(task.workflowId), persistedBytes = await options.engine.storage.get(workflowKey);
|
|
7
|
+
if (persistedBytes === null)
|
|
8
|
+
return [];
|
|
9
|
+
const persistedRevision = decodeWorkflowState(persistedBytes).revision;
|
|
10
|
+
if (persistedRevision !== task.workflowRevision)
|
|
11
|
+
throw Error(`TaskDispatch for operation "${task.operationId}" targets workflow "${task.workflowId}" at revision "${task.workflowRevision}", but the persisted run is pinned to revision ${persistedRevision === void 0 ? "undefined (a legacy, pre-pinning record)" : `"${persistedRevision}"`} ` + "\u2014 this dispatch is stale.");
|
|
12
|
+
return [{ key: workflowKey, expectedValue: persistedBytes }];
|
|
13
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isJSONValue } from "../../core/json.js";
|
|
2
1
|
import { buildWorkerExecutionIdentity } from "../../worker/manifest/execution-identity.js";
|
|
3
2
|
import { evictOldestAffinityEntries } from "../runtime-helpers.js";
|
|
4
3
|
import {
|
|
@@ -7,9 +6,10 @@ import {
|
|
|
7
6
|
} from "../task-ledger-transitions.js";
|
|
8
7
|
import {
|
|
9
8
|
decodeRemoteTaskRecord,
|
|
10
|
-
REMOTE_TASK_RECORD_VERSION,
|
|
11
9
|
taskLedgerKey
|
|
12
10
|
} from "../task-ledger.js";
|
|
11
|
+
import { buildCreateQueuedInput } from "./task-dispatch-envelope.js";
|
|
12
|
+
import { assertDispatchTargetsFreshRevision } from "./task-dispatch-revision.js";
|
|
13
13
|
import { commitTaskLedgerTransition } from "./task-ledger-runtime.js";
|
|
14
14
|
import {
|
|
15
15
|
recordTaskBacklogMetric,
|
|
@@ -65,33 +65,6 @@ function recordDispatchOutcome(context, task, workerId) {
|
|
|
65
65
|
operationIds.add(task.operationId);
|
|
66
66
|
context.operationToWorkflow.set(task.operationId, task.workflowId);
|
|
67
67
|
}
|
|
68
|
-
function buildOptionalCreateQueuedFields(task) {
|
|
69
|
-
return {
|
|
70
|
-
...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
|
|
71
|
-
...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
|
|
72
|
-
...task.priority !== void 0 ? { priority: task.priority } : {},
|
|
73
|
-
...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
|
|
74
|
-
...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
|
|
75
|
-
...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function buildCreateQueuedInput(task, queue, visibilityTimeout) {
|
|
79
|
-
const input = task.input === void 0 ? null : task.input;
|
|
80
|
-
if (!isJSONValue(input))
|
|
81
|
-
throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
|
|
82
|
-
return {
|
|
83
|
-
recordVersion: REMOTE_TASK_RECORD_VERSION,
|
|
84
|
-
operationId: task.operationId,
|
|
85
|
-
workflowType: task.workflowType,
|
|
86
|
-
activityName: task.activityName,
|
|
87
|
-
queue,
|
|
88
|
-
input,
|
|
89
|
-
headers: task.headers ?? {},
|
|
90
|
-
visibilityTimeoutMilliseconds: visibilityTimeout,
|
|
91
|
-
createdAt: Date.now(),
|
|
92
|
-
...buildOptionalCreateQueuedFields(task)
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
68
|
function buildCreateThenClaimTransition(createInput, claimInput) {
|
|
96
69
|
return (current, now) => {
|
|
97
70
|
let queuedRecord;
|
|
@@ -114,7 +87,7 @@ function bareActivityName(qualifiedActivityName) {
|
|
|
114
87
|
const dotIndex = qualifiedActivityName.indexOf(".");
|
|
115
88
|
return dotIndex === -1 ? qualifiedActivityName : qualifiedActivityName.slice(dotIndex + 1);
|
|
116
89
|
}
|
|
117
|
-
async function selectAndReserveWorker(context, options, task, queue, visibilityTimeout) {
|
|
90
|
+
async function selectAndReserveWorker(context, options, task, queue, visibilityTimeout, revisionFenceConditions) {
|
|
118
91
|
const routingOptions = buildRoutingOptions(context, task, queue), worker = context.registry.findWorker(task.activityName, routingOptions);
|
|
119
92
|
if (!worker)
|
|
120
93
|
return !1;
|
|
@@ -128,7 +101,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
128
101
|
workflowType: task.workflowType,
|
|
129
102
|
activityName: bareActivityName(task.activityName)
|
|
130
103
|
});
|
|
131
|
-
context.registry.assignTask(worker.id, task.operationId, visibilityTimeout, task.fairShareKey, attemptToken);
|
|
104
|
+
context.registry.assignTask(worker.id, task.operationId, visibilityTimeout, task.fairShareKey, attemptToken, task.workflowRevision);
|
|
132
105
|
let result;
|
|
133
106
|
try {
|
|
134
107
|
result = await commitTaskLedgerTransition(options.engine.storage, task.operationId, buildCreateThenClaimTransition(createInput, {
|
|
@@ -136,7 +109,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
136
109
|
workerSessionId: worker.id,
|
|
137
110
|
...executionIdentity !== void 0 ? { executionIdentity } : {},
|
|
138
111
|
leaseDurationMilliseconds: visibilityTimeout
|
|
139
|
-
}), 1);
|
|
112
|
+
}), 1, revisionFenceConditions);
|
|
140
113
|
} catch (error) {
|
|
141
114
|
context.registry.releaseReservation(task.operationId);
|
|
142
115
|
throw error;
|
|
@@ -159,6 +132,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
159
132
|
...task.workflowExecutionToken !== void 0 && {
|
|
160
133
|
workflowExecutionToken: task.workflowExecutionToken
|
|
161
134
|
},
|
|
135
|
+
...task.workflowRevision !== void 0 && { workflowRevision: task.workflowRevision },
|
|
162
136
|
...task.headers ? { headers: task.headers } : {}
|
|
163
137
|
}));
|
|
164
138
|
recordTaskQueueLatencyMetric(context.metricsCollector, {
|
|
@@ -169,11 +143,11 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
169
143
|
recordDispatchOutcome(context, task, worker.id);
|
|
170
144
|
return !0;
|
|
171
145
|
}
|
|
172
|
-
async function enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority) {
|
|
146
|
+
async function enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority, revisionFenceConditions) {
|
|
173
147
|
const storage = options.engine.storage, createInput = buildCreateQueuedInput(task, queue, visibilityTimeout), rawExisting = await storage.get(taskLedgerKey(task.operationId)), current = decodeRemoteTaskRecord(rawExisting);
|
|
174
148
|
let queuedRecord;
|
|
175
149
|
if (current === null) {
|
|
176
|
-
const result = await commitTaskLedgerTransition(storage, task.operationId, (freshCurrent, now) => createQueued(freshCurrent, createInput, now), 1);
|
|
150
|
+
const result = await commitTaskLedgerTransition(storage, task.operationId, (freshCurrent, now) => createQueued(freshCurrent, createInput, now), 1, revisionFenceConditions);
|
|
177
151
|
if (!result.ok) {
|
|
178
152
|
const raced = decodeRemoteTaskRecord(await storage.get(taskLedgerKey(task.operationId)));
|
|
179
153
|
if (raced === null || raced.state !== "queued")
|
|
@@ -194,6 +168,7 @@ async function enqueueTaskForLongPoll(context, options, task, queue, visibilityT
|
|
|
194
168
|
visibilityTimeout,
|
|
195
169
|
workflowId: task.workflowId,
|
|
196
170
|
workflowExecutionToken: task.workflowExecutionToken,
|
|
171
|
+
workflowRevision: queuedRecord.workflowRevision,
|
|
197
172
|
firstQueuedAt: queuedRecord.firstQueuedAt,
|
|
198
173
|
lastQueuedAt: queuedRecord.lastQueuedAt,
|
|
199
174
|
lastDispatchedAt: queuedRecord.lastDispatchedAt,
|
|
@@ -214,15 +189,15 @@ export async function dispatchTaskImpl(context, options, task) {
|
|
|
214
189
|
}
|
|
215
190
|
if (!task.workflowType)
|
|
216
191
|
throw Error(`TaskDispatch for operation "${task.operationId}" is missing required field "workflowType".`);
|
|
217
|
-
const dotIndex = task.activityName.indexOf(".");
|
|
192
|
+
const revisionFenceConditions = await assertDispatchTargetsFreshRevision(options, task), dotIndex = task.activityName.indexOf(".");
|
|
218
193
|
if (dotIndex !== -1 && task.activityName.slice(0, dotIndex) !== task.workflowType)
|
|
219
194
|
throw Error(`TaskDispatch for operation "${task.operationId}" has activityName "${task.activityName}" whose qualifier does not match workflowType "${task.workflowType}".`);
|
|
220
195
|
const queue = task.queue ?? "default", visibilityTimeout = clampVisibilityTimeout(task.visibilityTimeout), resolvedPriority = resolveTaskPriority(context, options, task);
|
|
221
196
|
if (!validateTaskEnvelope(context, task))
|
|
222
197
|
return !1;
|
|
223
|
-
if (await selectAndReserveWorker(context, options, task, queue, visibilityTimeout))
|
|
198
|
+
if (await selectAndReserveWorker(context, options, task, queue, visibilityTimeout, revisionFenceConditions))
|
|
224
199
|
return !0;
|
|
225
|
-
return enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority);
|
|
200
|
+
return enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority, revisionFenceConditions);
|
|
226
201
|
}
|
|
227
202
|
export function cancelTask(context, operationId) {
|
|
228
203
|
const task = context.registry.getTask(operationId);
|
|
@@ -16,7 +16,7 @@ function rebuildWorkflowIndex(context, operationId, workflowId) {
|
|
|
16
16
|
}
|
|
17
17
|
function rehydrateWorkerOwnership(context, record, now) {
|
|
18
18
|
const remaining = Math.max(0, record.leaseDeadline - now);
|
|
19
|
-
context.registry.assignTask(record.workerSessionId, record.operationId, remaining, record.fairShareKey, record.attemptToken);
|
|
19
|
+
context.registry.assignTask(record.workerSessionId, record.operationId, remaining, record.fairShareKey, record.attemptToken, record.workflowRevision);
|
|
20
20
|
const tracked = context.registry.getWorkerTasks(record.workerSessionId).find((task) => task.operationId === record.operationId);
|
|
21
21
|
if (tracked)
|
|
22
22
|
tracked.visibilityTimeout = record.visibilityTimeoutMilliseconds;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* @module server/runtime/task-ledger-runtime
|
|
18
18
|
*/
|
|
19
|
-
import { type Storage } from '../../storage/interface.ts';
|
|
19
|
+
import { type ConditionalBatchCondition, type Storage } from '../../storage/interface.ts';
|
|
20
20
|
import type { TaskLedgerPreconditionResult, TaskLedgerTransitionResult } from '../task-ledger-transitions.ts';
|
|
21
21
|
import { type RemoteTaskRecord } from '../task-ledger.ts';
|
|
22
22
|
export type TaskLedgerCommitResult<T extends RemoteTaskRecord> = Readonly<{
|
|
@@ -46,7 +46,19 @@ export type TaskLedgerDeleteResult = Readonly<{
|
|
|
46
46
|
* reflects reality and re-attempting the identical transition cannot change
|
|
47
47
|
* the outcome.
|
|
48
48
|
*/
|
|
49
|
-
export declare function commitTaskLedgerTransition<T extends RemoteTaskRecord>(storage: Storage, operationId: string, transitionFn: (current: RemoteTaskRecord | null, now: number) => TaskLedgerTransitionResult<T>, maxAttempts?: number
|
|
49
|
+
export declare function commitTaskLedgerTransition<T extends RemoteTaskRecord>(storage: Storage, operationId: string, transitionFn: (current: RemoteTaskRecord | null, now: number) => TaskLedgerTransitionResult<T>, maxAttempts?: number,
|
|
50
|
+
/**
|
|
51
|
+
* Extra same-transaction preconditions to fence the commit on — for
|
|
52
|
+
* example, "the target workflow's persisted state is still exactly the
|
|
53
|
+
* bytes read at dispatch time" (WFT-20's revision-staleness gate). Checked
|
|
54
|
+
* in the SAME `conditionalBatch` call as the ledger key's own CAS, so a
|
|
55
|
+
* concurrent write to any of these keys between read and commit loses the
|
|
56
|
+
* whole batch atomically, closing the gap a standalone pre-check
|
|
57
|
+
* (read-then-later-write, with unrelated work in between) cannot close.
|
|
58
|
+
* Re-supplied by the caller on each retry attempt since the caller, not
|
|
59
|
+
* this loop, owns re-reading whatever these conditions guard.
|
|
60
|
+
*/
|
|
61
|
+
additionalConditions?: readonly ConditionalBatchCondition[]): Promise<TaskLedgerCommitResult<T>>;
|
|
50
62
|
/**
|
|
51
63
|
* Read the current ledger record, check a delete-only precondition (WFT-24
|
|
52
64
|
* retention: {@link canDeleteRetainedTerminalTask}), and conditionally delete
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
storageConditionalBatch
|
|
3
|
+
} from "../../storage/interface.js";
|
|
2
4
|
import {
|
|
3
5
|
decodeRemoteTaskRecord,
|
|
4
6
|
encodeRemoteTaskRecord,
|
|
5
7
|
taskLedgerKey
|
|
6
8
|
} from "../task-ledger.js";
|
|
7
|
-
export async function commitTaskLedgerTransition(storage, operationId, transitionFn, maxAttempts = 1) {
|
|
9
|
+
export async function commitTaskLedgerTransition(storage, operationId, transitionFn, maxAttempts = 1, additionalConditions = []) {
|
|
8
10
|
const key = taskLedgerKey(operationId);
|
|
9
11
|
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
10
12
|
const rawExisting = await storage.get(key), current = decodeRemoteTaskRecord(rawExisting), result = transitionFn(current, Date.now());
|
|
11
13
|
if (!result.ok)
|
|
12
14
|
return result;
|
|
13
|
-
if (await storageConditionalBatch(storage, [{ key, expectedValue: rawExisting }], [{ type: "put", key, value: encodeRemoteTaskRecord(result.nextRecord) }]))
|
|
15
|
+
if (await storageConditionalBatch(storage, [{ key, expectedValue: rawExisting }, ...additionalConditions], [{ type: "put", key, value: encodeRemoteTaskRecord(result.nextRecord) }]))
|
|
14
16
|
return { ok: !0, record: result.nextRecord };
|
|
15
17
|
}
|
|
16
18
|
return {
|
|
@@ -58,7 +58,8 @@ function validateTaskResultBody(body) {
|
|
|
58
58
|
workerId: typeof body.workerId === "string" ? body.workerId : void 0,
|
|
59
59
|
value: body.value,
|
|
60
60
|
error: typeof body.error === "string" ? body.error : void 0,
|
|
61
|
-
attemptToken: rawAttemptToken
|
|
61
|
+
attemptToken: rawAttemptToken,
|
|
62
|
+
workflowRevision: typeof body.workflowRevision === "string" ? body.workflowRevision : void 0
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
65
|
function isLongPollCompletionAuthorized(record, validated) {
|
|
@@ -68,7 +69,11 @@ function isLongPollCompletionAuthorized(record, validated) {
|
|
|
68
69
|
return !1;
|
|
69
70
|
if (validated.workerId === void 0 || record.workerSessionId !== validated.workerId)
|
|
70
71
|
return !1;
|
|
71
|
-
|
|
72
|
+
if (validated.attemptToken !== record.attemptToken)
|
|
73
|
+
return !1;
|
|
74
|
+
if (record.workflowRevision !== void 0 && validated.workflowRevision !== record.workflowRevision)
|
|
75
|
+
return !1;
|
|
76
|
+
return !0;
|
|
72
77
|
}
|
|
73
78
|
async function applyTaskResult(context, options, result) {
|
|
74
79
|
const { operationId, status, value, error } = result, committed = await commitTaskLedgerCompletion(options.engine.storage, {
|
|
@@ -155,7 +160,8 @@ export async function handleTaskPollRequest(context, options, request, url, prin
|
|
|
155
160
|
attemptToken: claim.attemptToken,
|
|
156
161
|
...task.workflowExecutionToken !== void 0 && {
|
|
157
162
|
workflowExecutionToken: task.workflowExecutionToken
|
|
158
|
-
}
|
|
163
|
+
},
|
|
164
|
+
...task.workflowRevision !== void 0 && { workflowRevision: task.workflowRevision }
|
|
159
165
|
});
|
|
160
166
|
}
|
|
161
167
|
return new Response(null, { status: 204 });
|
|
@@ -65,7 +65,8 @@ export function taskDispatchFromLedgerRecord(record) {
|
|
|
65
65
|
input: record.input,
|
|
66
66
|
queue: record.queue,
|
|
67
67
|
visibilityTimeout: record.visibilityTimeoutMilliseconds,
|
|
68
|
-
workflowExecutionToken: record.workflowExecutionToken
|
|
68
|
+
workflowExecutionToken: record.workflowExecutionToken,
|
|
69
|
+
workflowRevision: record.workflowRevision
|
|
69
70
|
};
|
|
70
71
|
if (record.workflowId !== void 0)
|
|
71
72
|
taskDispatch.workflowId = record.workflowId;
|
|
@@ -69,6 +69,8 @@ function upgradeScope(connectionType) {
|
|
|
69
69
|
case "generic":
|
|
70
70
|
case void 0:
|
|
71
71
|
return null;
|
|
72
|
+
default:
|
|
73
|
+
throw Error(`Unknown WebSocket connection type: ${JSON.stringify(connectionType)}`);
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
export function handleWebSocketUpgrade(server, context, options, request, url, authContext) {
|
|
@@ -47,6 +47,15 @@ function onTaskResultMessage(context, options, ws, message, cleanupWorkflowIndex
|
|
|
47
47
|
});
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
+
const inFlightTask = context.registry.getTask(operationId);
|
|
51
|
+
if (inFlightTask?.workflowRevision !== void 0 && message.workflowRevision !== inFlightTask.workflowRevision) {
|
|
52
|
+
sendWorkerProtocolMessage(ws, {
|
|
53
|
+
type: "protocolError",
|
|
54
|
+
code: "invalid_message",
|
|
55
|
+
message: `taskResult for operation "${operationId}" rejected \u2014 revision mismatch`
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
50
59
|
const resolvedStatus = resolveTaskResultStatus(message), payloadError = taskResultPayloadSizeError({
|
|
51
60
|
status: resolvedStatus,
|
|
52
61
|
...message.status === "completed" ? { value: message.value } : { error: message.error }
|
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
* @module server/task-ledger-codec
|
|
16
16
|
*/
|
|
17
17
|
import type { RemoteTaskCancelling, RemoteTaskCompleting, RemoteTaskDeadLettered, RemoteTaskLeased, RemoteTaskQueued, RemoteTaskRecord, RemoteTaskTerminal, RemoteTaskTerminalCancelled, RemoteTaskTerminalResolved, RemoteTaskTerminalRetryExhausted } from './task-ledger-types.ts';
|
|
18
|
+
/**
|
|
19
|
+
* Whether `value` is a valid `workflowRevision` per the durable task
|
|
20
|
+
* ledger's non-empty, bounded identifier contract — the same contract
|
|
21
|
+
* `decodeRemoteTaskRecord` enforces on read. Exported so dispatch-time
|
|
22
|
+
* callers (`task-dispatch.ts`) can reject an invalid caller-supplied
|
|
23
|
+
* revision before it reaches a ledger write, instead of writing a record
|
|
24
|
+
* that later fails to decode.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isValidWorkflowRevision(value: unknown): value is string;
|
|
18
27
|
/** Bounded header map: at most {@link MAX_TASK_HEADER_COUNT} entries, each key/value at most {@link MAX_TASK_HEADER_VALUE_BYTES}. */
|
|
19
28
|
export declare function isValidTaskHeaders(value: unknown): value is Readonly<Record<string, string>>;
|
|
20
29
|
export declare function isRemoteTaskQueued(value: unknown): value is RemoteTaskQueued;
|
|
@@ -14,6 +14,9 @@ function isRecord(value) {
|
|
|
14
14
|
function isBoundedIdentifier(value, maxBytes = MAX_TASK_IDENTIFIER_BYTES) {
|
|
15
15
|
return typeof value === "string" && value.length > 0 && utf8ByteLength(value) <= maxBytes;
|
|
16
16
|
}
|
|
17
|
+
export function isValidWorkflowRevision(value) {
|
|
18
|
+
return isBoundedIdentifier(value);
|
|
19
|
+
}
|
|
17
20
|
function isBoundedOptionalIdentifier(value, maxBytes = MAX_TASK_IDENTIFIER_BYTES) {
|
|
18
21
|
return value === void 0 || isBoundedIdentifier(value, maxBytes);
|
|
19
22
|
}
|
|
@@ -86,7 +89,7 @@ function isOptionalExecutionIdentity(value) {
|
|
|
86
89
|
return value === void 0 || isValidExecutionIdentity(value);
|
|
87
90
|
}
|
|
88
91
|
function isValidTaskIdentityFields(value) {
|
|
89
|
-
return value.recordVersion === 1 && isBoundedIdentifier(value.operationId) && isBoundedOptionalIdentifier(value.workflowId) && isBoundedIdentifier(value.workflowType) && isBoundedOptionalIdentifier(value.workflowExecutionToken) && isBoundedIdentifier(value.activityName) && isBoundedIdentifier(value.queue);
|
|
92
|
+
return value.recordVersion === 1 && isBoundedIdentifier(value.operationId) && isBoundedOptionalIdentifier(value.workflowId) && isBoundedIdentifier(value.workflowType) && isBoundedOptionalIdentifier(value.workflowExecutionToken) && isBoundedOptionalIdentifier(value.workflowRevision) && isBoundedIdentifier(value.activityName) && isBoundedIdentifier(value.queue);
|
|
90
93
|
}
|
|
91
94
|
function isValidTaskRoutingFields(value) {
|
|
92
95
|
return isOptionalFiniteNumber(value.priority) && isBoundedOptionalIdentifier(value.fairShareKey) && isBoundedOptionalIdentifier(value.stickyWorkflowId) && isValidExecutionRequirement(value.executionRequirement);
|
|
@@ -5,6 +5,7 @@ export function pickBase(record) {
|
|
|
5
5
|
...record.workflowId !== void 0 ? { workflowId: record.workflowId } : {},
|
|
6
6
|
workflowType: record.workflowType,
|
|
7
7
|
...record.workflowExecutionToken !== void 0 ? { workflowExecutionToken: record.workflowExecutionToken } : {},
|
|
8
|
+
...record.workflowRevision !== void 0 ? { workflowRevision: record.workflowRevision } : {},
|
|
8
9
|
activityName: record.activityName,
|
|
9
10
|
queue: record.queue,
|
|
10
11
|
input: record.input,
|
|
@@ -48,6 +48,15 @@ export type RemoteTaskBase = Readonly<{
|
|
|
48
48
|
workflowId?: string;
|
|
49
49
|
workflowType: string;
|
|
50
50
|
workflowExecutionToken?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The dispatching workflow run's persisted revision (WFT-20), when the
|
|
53
|
+
* `TaskDispatch` caller supplied one. Same optionality rationale as
|
|
54
|
+
* `workflowExecutionToken` above — NOT the same field as
|
|
55
|
+
* `executionRequirement.workflowRevision` (a client-declared routing
|
|
56
|
+
* constraint carried by `WorkerExecutionRequirementInput`, unrelated to
|
|
57
|
+
* this plain wire echo/validation field).
|
|
58
|
+
*/
|
|
59
|
+
workflowRevision?: string;
|
|
51
60
|
activityName: string;
|
|
52
61
|
queue: string;
|
|
53
62
|
input: JSONValue;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module server/task-ledger
|
|
12
12
|
*/
|
|
13
|
-
export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidTaskHeaders, } from './task-ledger-codec.ts';
|
|
13
|
+
export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidTaskHeaders, isValidWorkflowRevision, } from './task-ledger-codec.ts';
|
|
14
14
|
export { taskLedgerKey } from './task-ledger-keys.ts';
|
|
15
15
|
export { MAX_TASK_HEADER_COUNT, MAX_TASK_HEADER_VALUE_BYTES, MAX_TASK_IDENTIFIER_BYTES, MAX_TASK_REASON_BYTES, utf8ByteLength, } from './task-ledger-limits.ts';
|
|
16
16
|
export { REMOTE_TASK_RECORD_VERSION } from './task-ledger-types.ts';
|