@lostgradient/weft 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -24
- package/dist/cli/conformance.js +7 -1
- package/dist/cli/generated/operation-client.generated.d.ts +28 -13
- package/dist/cli/generated/operation-client.generated.js +1 -0
- package/dist/cli/help-text.d.ts +1 -1
- package/dist/cli/help-text.js +1 -0
- package/dist/cli/operation-catalog-snapshot.d.ts +8 -0
- package/dist/cli/operation-catalog-snapshot.js +11 -0
- package/dist/cli/parse-schedule-arguments.js +3 -1
- package/dist/cli/schedule.js +2 -1
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli-main.js +79 -78
- package/dist/client/handle-delegation.d.ts +3 -2
- package/dist/client/handle-delegation.js +3 -1
- package/dist/client/http-client-requests.d.ts +2 -1
- package/dist/client/http-client-requests.js +7 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +10 -1
- package/dist/client/http-request.d.ts +11 -1
- package/dist/client/http-request.js +17 -7
- package/dist/client/index.d.ts +1 -1
- package/dist/client/interface.d.ts +46 -5
- package/dist/client/local.d.ts +4 -1
- package/dist/client/local.js +12 -4
- package/dist/client/start-body.d.ts +4 -3
- package/dist/core/byte-arrays.d.ts +5 -0
- package/dist/core/byte-arrays.js +5 -0
- package/dist/core/checkpoint/lifecycle.d.ts +3 -0
- package/dist/core/checkpoint/lifecycle.js +9 -4
- package/dist/core/checkpoint/serialization.js +12 -5
- package/dist/core/codec/extension-codec.d.ts +16 -0
- package/dist/core/codec/extension-codec.js +100 -6
- package/dist/core/context/activity-retry-state.d.ts +38 -0
- package/dist/core/context/activity-retry-state.js +89 -0
- package/dist/core/context/activity-schedule-to-close.d.ts +159 -0
- package/dist/core/context/activity-schedule-to-close.js +69 -0
- package/dist/core/context/child-workflow-pipe.d.ts +5 -5
- package/dist/core/context/child-workflow-pipe.js +15 -2
- package/dist/core/context/context-presence.d.ts +19 -0
- package/dist/core/context/context-presence.js +13 -0
- package/dist/core/context/durable-operations.d.ts +25 -0
- package/dist/core/context/durable-operations.js +64 -0
- package/dist/core/context/index.d.ts +9 -5
- package/dist/core/context/index.js +17 -12
- package/dist/core/context/internals.d.ts +20 -0
- package/dist/core/context/internals.js +3 -1
- package/dist/core/context/operation-request.d.ts +35 -0
- package/dist/core/context/parallel-cache-entry.d.ts +14 -5
- package/dist/core/context/run-operation.d.ts +6 -1
- package/dist/core/context/run-operation.js +41 -87
- package/dist/core/context/session-state.js +7 -8
- package/dist/core/context/speculative-child.js +2 -0
- package/dist/core/context/types.d.ts +15 -0
- package/dist/core/context/version-patching.d.ts +8 -0
- package/dist/core/context/version-patching.js +40 -0
- package/dist/core/context/workflow-logger.d.ts +98 -0
- package/dist/core/context/workflow-logger.js +68 -0
- package/dist/core/engine/activity-heartbeat-tracking.d.ts +64 -0
- package/dist/core/engine/activity-heartbeat-tracking.js +42 -0
- package/dist/core/engine/activity-per-attempt-timeout.d.ts +41 -0
- package/dist/core/engine/activity-per-attempt-timeout.js +36 -0
- package/dist/core/engine/activity-reconciliation.d.ts +1 -0
- package/dist/core/engine/activity-reconciliation.js +12 -1
- package/dist/core/engine/activity-resolution.d.ts +23 -0
- package/dist/core/engine/activity-resolution.js +37 -0
- package/dist/core/engine/aggregate.js +66 -30
- package/dist/core/engine/async-activity-completion.d.ts +23 -6
- package/dist/core/engine/async-activity-completion.js +53 -12
- package/dist/core/engine/attributes-tags.js +9 -4
- package/dist/core/engine/bulk-operations-purge.d.ts +26 -0
- package/dist/core/engine/bulk-operations-purge.js +38 -3
- package/dist/core/engine/bulk-operations-shared.d.ts +2 -0
- package/dist/core/engine/bulk-operations-shared.js +8 -2
- package/dist/core/engine/bulk-operations.d.ts +4 -1
- package/dist/core/engine/bulk-operations.js +235 -24
- package/dist/core/engine/callback-creators-bundles.d.ts +9 -0
- package/dist/core/engine/callback-creators-bundles.js +30 -2
- package/dist/core/engine/callback-creators-core.js +6 -4
- package/dist/core/engine/callback-creators-router.js +10 -0
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -2
- package/dist/core/engine/callback-creators-schedule.js +12 -8
- package/dist/core/engine/candidate-read-batching.d.ts +6 -0
- package/dist/core/engine/candidate-read-batching.js +1 -0
- package/dist/core/engine/checkpoint-io.js +61 -25
- package/dist/core/engine/checkpoint-reads.js +3 -2
- package/dist/core/engine/checkpoint-replay.d.ts +20 -0
- package/dist/core/engine/checkpoint-replay.js +242 -0
- package/dist/core/engine/checkpoint-side-effects.d.ts +23 -0
- package/dist/core/engine/checkpoint-side-effects.js +35 -0
- package/dist/core/engine/child-workflow-cancellation.d.ts +10 -0
- package/dist/core/engine/child-workflow-cancellation.js +40 -0
- package/dist/core/engine/child-workflow.js +27 -4
- package/dist/core/engine/condition-waiters.d.ts +14 -0
- package/dist/core/engine/condition-waiters.js +5 -0
- package/dist/core/engine/construction.d.ts +3 -0
- package/dist/core/engine/construction.js +21 -8
- package/dist/core/engine/coordination-branch-executors.d.ts +70 -0
- package/dist/core/engine/coordination-branch-executors.js +107 -0
- package/dist/core/engine/deferred-consume-envelope.d.ts +59 -0
- package/dist/core/engine/deferred-consume-envelope.js +14 -0
- package/dist/core/engine/disposal.js +13 -0
- package/dist/core/engine/engine-create-types.d.ts +14 -4
- package/dist/core/engine/engine-internal-types.d.ts +26 -3
- package/dist/core/engine/errors.d.ts +47 -0
- package/dist/core/engine/errors.js +20 -0
- package/dist/core/engine/event-log-compaction.d.ts +8 -0
- package/dist/core/engine/event-log-compaction.js +20 -2
- package/dist/core/engine/fenced-write.d.ts +65 -0
- package/dist/core/engine/fenced-write.js +71 -0
- package/dist/core/engine/finalizer-state.d.ts +28 -0
- package/dist/core/engine/finalizer-state.js +16 -0
- package/dist/core/engine/handles.d.ts +8 -0
- package/dist/core/engine/index.d.ts +34 -16
- package/dist/core/engine/index.js +133 -8
- package/dist/core/engine/inline-parking.js +3 -2
- package/dist/core/engine/internals.d.ts +107 -3
- package/dist/core/engine/lease-codec.d.ts +35 -0
- package/dist/core/engine/lease-codec.js +32 -0
- package/dist/core/engine/lease-deposition.d.ts +66 -0
- package/dist/core/engine/lease-deposition.js +10 -0
- package/dist/core/engine/lease-errors.d.ts +99 -0
- package/dist/core/engine/lease-errors.js +30 -0
- package/dist/core/engine/lease-manager.d.ts +114 -0
- package/dist/core/engine/lease-manager.js +135 -0
- package/dist/core/engine/lifecycle/persist.js +10 -32
- package/dist/core/engine/lifecycle/recovered-services.d.ts +8 -6
- package/dist/core/engine/lifecycle/recovered-services.js +18 -3
- package/dist/core/engine/lifecycle/resume.js +16 -9
- package/dist/core/engine/lifecycle/shared.d.ts +8 -1
- package/dist/core/engine/lifecycle/start-batch.d.ts +1 -1
- package/dist/core/engine/lifecycle/start-batch.js +2 -1
- package/dist/core/engine/lifecycle/start-commit.d.ts +9 -0
- package/dist/core/engine/lifecycle/start-commit.js +50 -8
- package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +58 -0
- package/dist/core/engine/lifecycle/start-or-signal-create.js +95 -0
- package/dist/core/engine/lifecycle/start-or-signal.d.ts +3 -2
- package/dist/core/engine/lifecycle/start-or-signal.js +11 -81
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +39 -0
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +28 -0
- package/dist/core/engine/lifecycle/start.d.ts +4 -4
- package/dist/core/engine/lifecycle/start.js +17 -9
- package/dist/core/engine/lifecycle/transition.js +17 -5
- package/dist/core/engine/lifecycle.d.ts +1 -1
- package/dist/core/engine/list-candidate-resolution.js +2 -2
- package/dist/core/engine/listing.js +9 -5
- package/dist/core/engine/operations-activity.d.ts +4 -11
- package/dist/core/engine/operations-activity.js +22 -49
- package/dist/core/engine/operations-coordination.d.ts +10 -0
- package/dist/core/engine/operations-coordination.js +43 -8
- package/dist/core/engine/operations-router.d.ts +6 -0
- package/dist/core/engine/operations-router.js +2 -0
- package/dist/core/engine/operations-speculate.js +6 -2
- package/dist/core/engine/operations-stream.js +12 -2
- package/dist/core/engine/operations-time.d.ts +4 -2
- package/dist/core/engine/operations-time.js +14 -2
- package/dist/core/engine/operations-wait-condition.d.ts +23 -0
- package/dist/core/engine/operations-wait-condition.js +62 -0
- package/dist/core/engine/ownership-options.d.ts +23 -0
- package/dist/core/engine/ownership-options.js +26 -0
- package/dist/core/engine/payload-size-policy.d.ts +3 -0
- package/dist/core/engine/payload-size-policy.js +4 -0
- package/dist/core/engine/pending-updates.d.ts +17 -0
- package/dist/core/engine/pending-updates.js +33 -11
- package/dist/core/engine/queries.js +1 -1
- package/dist/core/engine/registration.d.ts +1 -0
- package/dist/core/engine/registration.js +18 -3
- package/dist/core/engine/schedule-jitter.d.ts +5 -0
- package/dist/core/engine/schedule-jitter.js +10 -0
- package/dist/core/engine/schedule-run.d.ts +17 -0
- package/dist/core/engine/schedule-run.js +38 -0
- package/dist/core/engine/schedule-timer.js +81 -17
- package/dist/core/engine/schedules.d.ts +7 -4
- package/dist/core/engine/schedules.js +37 -16
- package/dist/core/engine/search-attribute-records.d.ts +4 -0
- package/dist/core/engine/search-attribute-records.js +17 -0
- package/dist/core/engine/signals.d.ts +18 -2
- package/dist/core/engine/signals.js +42 -21
- package/dist/core/engine/state-utilities.d.ts +49 -2
- package/dist/core/engine/state-utilities.js +114 -3
- package/dist/core/engine/storage-io.d.ts +16 -2
- package/dist/core/engine/storage-io.js +26 -5
- package/dist/core/engine/stream-chunk-loading.d.ts +2 -0
- package/dist/core/engine/stream-chunk-loading.js +24 -1
- package/dist/core/engine/sub-operation.js +22 -3
- package/dist/core/engine/termination/cleanup.d.ts +3 -1
- package/dist/core/engine/termination/cleanup.js +25 -1
- package/dist/core/engine/termination/complete.js +44 -6
- package/dist/core/engine/termination/finalizer-activity.d.ts +53 -0
- package/dist/core/engine/termination/finalizer-activity.js +30 -0
- package/dist/core/engine/termination/finalizer-claim.d.ts +110 -0
- package/dist/core/engine/termination/finalizer-claim.js +80 -0
- package/dist/core/engine/termination/finalizer.d.ts +48 -0
- package/dist/core/engine/termination/finalizer.js +159 -0
- package/dist/core/engine/termination/suspend.d.ts +3 -1
- package/dist/core/engine/termination.d.ts +1 -0
- package/dist/core/engine/termination.js +4 -0
- package/dist/core/engine/updates.js +5 -25
- package/dist/core/engine/validation/schedule.d.ts +2 -1
- package/dist/core/engine/validation/schedule.js +51 -2
- package/dist/core/engine/validation.js +32 -5
- package/dist/core/engine/waiting-update-response.d.ts +8 -0
- package/dist/core/engine/waiting-update-response.js +22 -0
- package/dist/core/engine/workflow-concurrency.d.ts +10 -0
- package/dist/core/engine/workflow-concurrency.js +136 -0
- package/dist/core/engine/workflow-feed.d.ts +4 -5
- package/dist/core/engine/workflow-feed.js +4 -1
- package/dist/core/engine/workflow-indexes.d.ts +9 -0
- package/dist/core/engine/workflow-indexes.js +10 -0
- package/dist/core/engine/workflow-state-stream.js +33 -13
- package/dist/core/engine/workflow-visibility-queries.d.ts +2 -2
- package/dist/core/engine-helpers.js +1 -0
- package/dist/core/events/activity-events.d.ts +43 -12
- package/dist/core/events/activity-events.js +28 -0
- package/dist/core/events/attribute-events.d.ts +2 -3
- package/dist/core/events/event-map.d.ts +18 -12
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/events/schedule-events.d.ts +71 -0
- package/dist/core/events/schedule-events.js +29 -0
- package/dist/core/events/signal-events.d.ts +4 -6
- package/dist/core/events/system-events.d.ts +29 -19
- package/dist/core/events/system-events.js +26 -0
- package/dist/core/events/update-events.d.ts +6 -8
- package/dist/core/events/workflow-events.d.ts +88 -23
- package/dist/core/events/workflow-events.js +26 -0
- package/dist/core/failure-categories.js +5 -17
- package/dist/core/fault-code.d.ts +9 -3
- package/dist/core/fault-code.js +1 -0
- package/dist/core/inline-execution-strategy.context-options.d.ts +69 -0
- package/dist/core/inline-execution-strategy.context-options.js +56 -0
- package/dist/core/inline-execution-strategy.d.ts +31 -36
- package/dist/core/inline-execution-strategy.js +16 -27
- package/dist/core/list-filter-validation.d.ts +1 -1
- package/dist/core/payload-size.d.ts +1 -1
- package/dist/core/persisted-data-incompatible-error.d.ts +9 -7
- package/dist/core/review/events.d.ts +6 -8
- package/dist/core/scheduler/scheduler-class.d.ts +10 -1
- package/dist/core/scheduler/scheduler-class.js +38 -11
- package/dist/core/scheduler/timer-batch.js +9 -1
- package/dist/core/scheduler/timer-sources.d.ts +1 -0
- package/dist/core/scheduler/timer-sources.js +11 -5
- package/dist/core/session-state.d.ts +0 -1
- package/dist/core/session-state.js +2 -2
- package/dist/core/start-workflow-validation.d.ts +34 -0
- package/dist/core/start-workflow-validation.js +19 -0
- package/dist/core/types/activity-verification.d.ts +67 -0
- package/dist/core/types/activity-verification.js +0 -0
- package/dist/core/types/activity.d.ts +80 -61
- package/dist/core/types/bulk.d.ts +50 -9
- package/dist/core/types/checkpoint.d.ts +44 -8
- package/dist/core/types/list-options.d.ts +146 -0
- package/dist/core/types/list-options.js +0 -0
- package/dist/core/types/options.d.ts +121 -165
- package/dist/core/types/schedules.d.ts +39 -3
- package/dist/core/types/services-resolution.d.ts +2 -2
- package/dist/core/types/workflow-builder-runtime.d.ts +12 -3
- package/dist/core/types/workflow-builder-runtime.js +11 -2
- package/dist/core/types/workflow-builder.d.ts +42 -11
- package/dist/core/types/workflow-concurrency.d.ts +39 -0
- package/dist/core/types/workflow-concurrency.js +0 -0
- package/dist/core/types/workflow-context.d.ts +157 -14
- package/dist/core/types/workflow-definition.d.ts +53 -10
- package/dist/core/types/workflow-function.d.ts +84 -9
- package/dist/core/types/workflow-log.d.ts +98 -0
- package/dist/core/types/workflow-log.js +0 -0
- package/dist/core/types/workflow-registries.d.ts +14 -3
- package/dist/core/types/workflow-registry.d.ts +3 -0
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.js +4 -0
- package/dist/core/versioning.d.ts +9 -39
- package/dist/core/versioning.js +2 -12
- package/dist/core/weft-error.d.ts +44 -1
- package/dist/core/weft-error.js +16 -0
- package/dist/core/worker-execution-strategy-options.d.ts +26 -0
- package/dist/core/worker-execution-strategy.js +40 -36
- package/dist/core/worker-inbound-message.d.ts +38 -0
- package/dist/core/worker-inbound-message.js +37 -0
- package/dist/core/worker-log-abuse-counter.d.ts +175 -0
- package/dist/core/worker-log-abuse-counter.js +107 -0
- package/dist/core/worker-message-helpers.d.ts +47 -0
- package/dist/core/worker-message-helpers.js +26 -0
- package/dist/core/worker-protocol-guard.js +1 -1
- package/dist/core/worker-protocol-log.d.ts +56 -0
- package/dist/core/worker-protocol-log.js +18 -0
- package/dist/core/worker-protocol.d.ts +23 -0
- package/dist/core/worker-protocol.js +12 -2
- package/dist/core/workflow-version-tuple.d.ts +3 -9
- package/dist/core/workflow-version-tuple.js +2 -3
- package/dist/diagnostics/format.js +1 -6
- package/dist/diagnostics/types.d.ts +4 -5
- package/dist/diagnostics/validate.d.ts +0 -1
- package/dist/diagnostics/version-check.d.ts +1 -1
- package/dist/diagnostics/version-check.js +4 -9
- package/dist/index.d.ts +12 -10
- package/dist/index.js +29 -3
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +27 -27
- package/dist/mcp/dispatcher.js +1 -1
- package/dist/mcp/http.js +16 -6
- package/dist/mcp/protocol.d.ts +2 -0
- package/dist/mcp/protocol.js +1 -1
- package/dist/mcp/session.d.ts +16 -0
- package/dist/mcp/session.js +59 -6
- package/dist/mcp/tools.js +73 -6
- package/dist/observability/index.js +2 -2
- package/dist/server/asyncapi-channels.js +5 -2
- package/dist/server/attribute-filters.d.ts +8 -3
- package/dist/server/attribute-filters.js +6 -1
- package/dist/server/authentication/api-key.d.ts +2 -1
- package/dist/server/authentication/api-key.js +5 -2
- package/dist/server/authentication/constant-time-api-key.d.ts +15 -0
- package/dist/server/authentication/constant-time-api-key.js +24 -0
- package/dist/server/authentication/index.d.ts +1 -1
- package/dist/server/authentication/index.js +7 -4
- package/dist/server/authentication/rotating-api-key-store.d.ts +5 -3
- package/dist/server/authentication/rotating-api-key-store.js +19 -11
- package/dist/server/engine-event-feed-backend.d.ts +4 -5
- package/dist/server/fault-to-http.js +8 -1
- package/dist/server/fault-to-json-rpc.js +1 -0
- package/dist/server/fleet-event-feed.d.ts +31 -0
- package/dist/server/fleet-event-feed.js +157 -0
- package/dist/server/handler/index.js +1 -1
- package/dist/server/handler/response-helpers.js +2 -1
- package/dist/server/handler/route-dispatch.d.ts +6 -3
- package/dist/server/handler/route-dispatch.js +2 -2
- package/dist/server/handler.js +23 -23
- package/dist/server/index.d.ts +32 -2
- package/dist/server/index.js +26 -26
- package/dist/server/json-rpc-transport-helpers.d.ts +1 -0
- package/dist/server/json-rpc-transport-helpers.js +2 -1
- package/dist/server/json-rpc-websocket-runtime.d.ts +11 -2
- package/dist/server/json-rpc-websocket-runtime.js +1 -0
- package/dist/server/json-rpc-websocket-subscriptions.d.ts +10 -0
- package/dist/server/json-rpc-websocket-subscriptions.js +29 -0
- package/dist/server/json-rpc-websocket-types.d.ts +22 -0
- package/dist/server/json-rpc-websocket-types.js +0 -0
- package/dist/server/json-rpc-websocket-validation.js +20 -4
- package/dist/server/json-rpc-websocket.d.ts +2 -43
- package/dist/server/json-rpc-websocket.js +57 -74
- package/dist/server/openapi.d.ts +2 -1
- package/dist/server/openapi.js +1 -3
- package/dist/server/openrpc-document-schema.d.ts +78 -0
- package/dist/server/openrpc-document-schema.js +27 -1
- package/dist/server/openrpc-errors.d.ts +3 -0
- package/dist/server/openrpc-errors.js +2 -1
- package/dist/server/openrpc.js +32 -0
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/pipeline-helpers.js +1 -0
- package/dist/server/operation-catalog/pipeline-stages.js +26 -12
- package/dist/server/operation-catalog/pipeline.js +8 -1
- package/dist/server/operation-catalog/registry.js +13 -0
- package/dist/server/operation-catalog/types.d.ts +20 -9
- package/dist/server/operation-fault.d.ts +10 -0
- package/dist/server/operation-fault.js +2 -0
- package/dist/server/operation-registry.d.ts +12 -11
- package/dist/server/operation-registry.js +12 -3
- package/dist/server/operations/aggregate-workflows.d.ts +15 -15
- package/dist/server/operations/async-activity.d.ts +2 -2
- package/dist/server/operations/async-activity.js +12 -7
- package/dist/server/operations/bulk-cancel-workflows.d.ts +1 -1
- package/dist/server/operations/bulk-cancel-workflows.js +2 -2
- package/dist/server/operations/bulk-delete-workflows.d.ts +1 -1
- package/dist/server/operations/bulk-delete-workflows.js +2 -2
- package/dist/server/operations/bulk-filter-helpers.d.ts +8 -6
- package/dist/server/operations/bulk-filter-helpers.js +54 -24
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +11 -9
- package/dist/server/operations/bulk-mutate-workflow-tags.js +2 -2
- package/dist/server/operations/bulk-operation-helpers.d.ts +2 -2
- package/dist/server/operations/bulk-retry-failed-workflows.d.ts +7 -0
- package/dist/server/operations/bulk-retry-failed-workflows.js +64 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +11 -9
- package/dist/server/operations/bulk-signal-workflows.js +2 -2
- package/dist/server/operations/cancel-schedule.d.ts +1 -1
- package/dist/server/operations/create-schedule.d.ts +3 -1
- package/dist/server/operations/create-schedule.js +29 -11
- package/dist/server/operations/fleet-events-subscription.d.ts +54 -0
- package/dist/server/operations/fleet-events-subscription.js +99 -0
- package/dist/server/operations/fork-workflow.d.ts +1 -1
- package/dist/server/operations/fork-workflow.js +3 -2
- package/dist/server/operations/get-checkpoint-at.d.ts +1 -1
- package/dist/server/operations/get-registry.d.ts +1 -1
- package/dist/server/operations/get-retention-overview.d.ts +1 -1
- package/dist/server/operations/get-review.d.ts +1 -1
- package/dist/server/operations/get-schedule.d.ts +1 -1
- package/dist/server/operations/get-stream-chunks.d.ts +1 -1
- package/dist/server/operations/get-system-metrics.d.ts +2 -2
- package/dist/server/operations/get-task-diagnostics.d.ts +45 -6
- package/dist/server/operations/get-task-diagnostics.js +101 -7
- package/dist/server/operations/get-update-result.d.ts +1 -1
- package/dist/server/operations/get-workflow-attributes.d.ts +1 -1
- package/dist/server/operations/get-workflow-events.d.ts +1 -1
- package/dist/server/operations/get-workflow-result.d.ts +1 -1
- package/dist/server/operations/get-workflow-timeline.d.ts +1 -1
- package/dist/server/operations/get-workflow.d.ts +1 -1
- package/dist/server/operations/list-checkpoints.d.ts +1 -1
- package/dist/server/operations/list-reviews.d.ts +1 -1
- package/dist/server/operations/list-schedules.d.ts +1 -1
- package/dist/server/operations/list-task-queues.d.ts +2 -2
- package/dist/server/operations/list-workers.d.ts +2 -2
- package/dist/server/operations/list-workflows.d.ts +1 -1
- package/dist/server/operations/operation-helpers.d.ts +16 -1
- package/dist/server/operations/operation-helpers.js +15 -3
- package/dist/server/operations/pause-schedule.d.ts +1 -1
- package/dist/server/operations/purge-workflows.d.ts +5 -5
- package/dist/server/operations/purge-workflows.js +2 -2
- package/dist/server/operations/query-workflow.d.ts +1 -1
- package/dist/server/operations/query-workflow.js +3 -2
- package/dist/server/operations/recover-all.d.ts +1 -1
- package/dist/server/operations/replay-workflow.d.ts +1 -1
- package/dist/server/operations/resume-schedule.d.ts +1 -1
- package/dist/server/operations/set-workflow-attributes.d.ts +1 -1
- package/dist/server/operations/set-workflow-attributes.js +6 -3
- package/dist/server/operations/signal-workflow.js +8 -3
- package/dist/server/operations/single-workflow-tag-mutation.js +13 -3
- package/dist/server/operations/start-or-signal-workflow.d.ts +6 -1
- package/dist/server/operations/start-or-signal-workflow.js +14 -24
- package/dist/server/operations/start-workflow-options.d.ts +6 -0
- package/dist/server/operations/start-workflow-rest-input.d.ts +14 -0
- package/dist/server/operations/start-workflow-rest-input.js +31 -0
- package/dist/server/operations/start-workflow.d.ts +1 -1
- package/dist/server/operations/start-workflow.js +8 -23
- package/dist/server/operations/storage.d.ts +6 -6
- package/dist/server/operations/storage.js +24 -14
- package/dist/server/operations/stream-workflow-sse.d.ts +1 -1
- package/dist/server/operations/submit-review-decision.d.ts +1 -1
- package/dist/server/operations/submit-review-decision.js +6 -3
- package/dist/server/operations/update-schedule.d.ts +1 -1
- package/dist/server/operations/update-schedule.js +7 -4
- package/dist/server/operations/update-workflow.d.ts +1 -1
- package/dist/server/operations/update-workflow.js +7 -3
- package/dist/server/operations/worker-drain.d.ts +8 -8
- package/dist/server/operations/worker-drain.js +11 -8
- package/dist/server/operations/workflow-events-subscription.d.ts +7 -8
- package/dist/server/operations/workflow-events-subscription.js +43 -8
- package/dist/server/rest-binding.d.ts +3 -1
- package/dist/server/rest-bindings.js +12 -0
- package/dist/server/rest-body.d.ts +10 -0
- package/dist/server/rest-body.js +80 -0
- package/dist/server/runtime/authentication-bridge.d.ts +1 -0
- package/dist/server/runtime/authentication-bridge.js +33 -6
- package/dist/server/runtime/client-visible-events.d.ts +3 -0
- package/dist/server/runtime/client-visible-events.js +65 -0
- package/dist/server/runtime/context.d.ts +7 -0
- package/dist/server/runtime/event-broadcasting.d.ts +6 -0
- package/dist/server/runtime/event-broadcasting.js +72 -38
- package/dist/server/runtime/retry.d.ts +1 -0
- package/dist/server/runtime/retry.js +14 -0
- package/dist/server/runtime/shutdown.d.ts +7 -6
- package/dist/server/runtime/shutdown.js +6 -1
- package/dist/server/runtime/task-polling.js +61 -20
- package/dist/server/runtime/task-reconciliation.js +9 -1
- package/dist/server/runtime/task-result-resolution.d.ts +15 -0
- package/dist/server/runtime/task-result-resolution.js +81 -0
- package/dist/server/runtime/websocket-stream.d.ts +20 -1
- package/dist/server/runtime/websocket-stream.js +173 -7
- package/dist/server/runtime/websocket-upgrade.js +22 -3
- package/dist/server/runtime/websocket-worker.d.ts +1 -1
- package/dist/server/runtime/websocket-worker.js +38 -30
- package/dist/server/serve-internals.d.ts +3 -1
- package/dist/server/serve-internals.js +18 -2
- package/dist/server/task-state.d.ts +30 -0
- package/dist/server/task-state.js +28 -0
- package/dist/server/workflow-event-feed.d.ts +36 -115
- package/dist/server/workflow-event-feed.js +92 -27
- package/dist/service-worker/index.js +30 -30
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +24 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/default-scope.d.ts +7 -4
- package/dist/storage/http.js +2 -2
- package/dist/storage/index.d.ts +76 -4
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/interface.d.ts +163 -0
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +10 -0
- package/dist/storage/lmdb.d.ts +4 -3
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon-batch.d.ts +30 -0
- package/dist/storage/neon-batch.js +30 -0
- package/dist/storage/neon-value-mapping.d.ts +30 -3
- package/dist/storage/neon-value-mapping.js +12 -0
- package/dist/storage/neon.d.ts +16 -0
- package/dist/storage/neon.js +9 -4
- package/dist/storage/node-sqlite.js +23 -0
- package/dist/storage/postgres-key-value-queries.d.ts +69 -44
- package/dist/storage/postgres-key-value-queries.js +62 -24
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.d.ts +168 -0
- package/dist/storage/testing.js +2 -0
- package/dist/storage/turso.d.ts +8 -0
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +1 -1
- package/dist/storage/web-extension.js +1 -1
- package/dist/testing/index.js +28 -28
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/protocol.js +1 -1
- package/dist/workers/worker-replay-state.d.ts +32 -0
- package/dist/workers/worker-replay-state.js +35 -0
- package/dist/workers/worker-state-namespace.d.ts +21 -0
- package/dist/workers/worker-state-namespace.js +13 -0
- package/dist/workers/workflow-runner.d.ts +19 -15
- package/dist/workers/workflow-runner.js +72 -60
- package/dist/workers/workflow-worker-entry.js +5 -2
- package/package.json +5 -1
|
@@ -1,12 +1,24 @@
|
|
|
1
|
+
import { decode } from "../../core/codec.js";
|
|
2
|
+
import { loadStoredStreamTailSequence } from "../../core/engine/stream-chunk-loading.js";
|
|
1
3
|
import { KEYS } from "../../storage/interface.js";
|
|
2
|
-
const TOKEN_EVENT_TYPE = "stream:token";
|
|
4
|
+
const TOKEN_EVENT_TYPE = "stream:token", STREAM_CONNECTION_POLICY_CLOSE_CODE = 1008, MAX_WATCH_REPLAY_EVENTS = 1000, MAX_PENDING_WATCH_REPLAY_MESSAGES = 1000;
|
|
5
|
+
export const DEFAULT_MAX_STREAM_CONNECTIONS_PER_WORKFLOW = 100;
|
|
3
6
|
export function sendStreamMessage(ws, sequence, message) {
|
|
4
|
-
if (sequence <= (ws.data.
|
|
7
|
+
if (sequence <= (ws.data.streamLastDeliveredSequence ?? -1))
|
|
5
8
|
return;
|
|
6
9
|
ws.send(message);
|
|
7
|
-
ws.data.
|
|
10
|
+
ws.data.streamLastDeliveredSequence = sequence;
|
|
11
|
+
}
|
|
12
|
+
export function sendWatchMessage(ws, sequence, message) {
|
|
13
|
+
if (sequence <= (ws.data.watchLastDeliveredSequence ?? -1))
|
|
14
|
+
return;
|
|
15
|
+
ws.send(message);
|
|
16
|
+
ws.data.watchLastDeliveredSequence = sequence;
|
|
8
17
|
}
|
|
9
18
|
export async function getHighestStoredStreamSequence(engine, workflowId, key) {
|
|
19
|
+
const tailSequence = await loadStoredStreamTailSequence(engine.storage, workflowId, key);
|
|
20
|
+
if (tailSequence !== null)
|
|
21
|
+
return tailSequence;
|
|
10
22
|
const prefix = KEYS.streamChunkPrefix(workflowId, key);
|
|
11
23
|
for await (const [storageKey] of engine.storage.scan(prefix, { reverse: !0, limit: 1 })) {
|
|
12
24
|
const sequenceText = storageKey.slice(prefix.length), sequence = Number.parseInt(sequenceText, 10);
|
|
@@ -15,13 +27,37 @@ export async function getHighestStoredStreamSequence(engine, workflowId, key) {
|
|
|
15
27
|
}
|
|
16
28
|
return -1;
|
|
17
29
|
}
|
|
30
|
+
export async function getHighestStoredWatchSequence(engine, workflowId) {
|
|
31
|
+
const prefix = KEYS.eventPrefix(workflowId);
|
|
32
|
+
for await (const [storageKey] of engine.storage.scan(prefix, { reverse: !0, limit: 50 })) {
|
|
33
|
+
const sequence = parseSequenceFromEventKey(prefix, storageKey);
|
|
34
|
+
if (sequence === null)
|
|
35
|
+
continue;
|
|
36
|
+
return sequence;
|
|
37
|
+
}
|
|
38
|
+
return -1;
|
|
39
|
+
}
|
|
18
40
|
export function addStreamSocket(context, workflowId, ws) {
|
|
41
|
+
if (!addWorkflowStreamConnection(context, workflowId, ws))
|
|
42
|
+
return !1;
|
|
19
43
|
let sockets = context.streamSockets.get(workflowId);
|
|
20
44
|
if (!sockets) {
|
|
21
45
|
sockets = new Set;
|
|
22
46
|
context.streamSockets.set(workflowId, sockets);
|
|
23
47
|
}
|
|
24
48
|
sockets.add(ws);
|
|
49
|
+
return !0;
|
|
50
|
+
}
|
|
51
|
+
export function addWatchSocket(context, workflowId, ws) {
|
|
52
|
+
if (!addWorkflowStreamConnection(context, workflowId, ws))
|
|
53
|
+
return !1;
|
|
54
|
+
let sockets = context.watchSockets.get(workflowId);
|
|
55
|
+
if (!sockets) {
|
|
56
|
+
sockets = new Set;
|
|
57
|
+
context.watchSockets.set(workflowId, sockets);
|
|
58
|
+
}
|
|
59
|
+
sockets.add(ws);
|
|
60
|
+
return !0;
|
|
25
61
|
}
|
|
26
62
|
export function removeStreamSocket(context, ws) {
|
|
27
63
|
const workflowId = ws.data.workflowId;
|
|
@@ -34,6 +70,39 @@ export function removeStreamSocket(context, ws) {
|
|
|
34
70
|
if (sockets.size === 0)
|
|
35
71
|
context.streamSockets.delete(workflowId);
|
|
36
72
|
}
|
|
73
|
+
export function removeWatchSocket(context, ws) {
|
|
74
|
+
const workflowId = ws.data.workflowId;
|
|
75
|
+
if (!workflowId)
|
|
76
|
+
return;
|
|
77
|
+
const sockets = context.watchSockets.get(workflowId);
|
|
78
|
+
if (!sockets)
|
|
79
|
+
return;
|
|
80
|
+
sockets.delete(ws);
|
|
81
|
+
if (sockets.size === 0)
|
|
82
|
+
context.watchSockets.delete(workflowId);
|
|
83
|
+
}
|
|
84
|
+
export function removeWorkflowStreamConnection(context, ws) {
|
|
85
|
+
const workflowId = ws.data.workflowId;
|
|
86
|
+
if (!workflowId || !ws.data.workflowStreamConnectionAccepted)
|
|
87
|
+
return;
|
|
88
|
+
ws.data.workflowStreamConnectionAccepted = !1;
|
|
89
|
+
const currentCount = context.workflowStreamConnectionCounts.get(workflowId);
|
|
90
|
+
if (currentCount === void 0 || currentCount <= 1) {
|
|
91
|
+
context.workflowStreamConnectionCounts.delete(workflowId);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
context.workflowStreamConnectionCounts.set(workflowId, currentCount - 1);
|
|
95
|
+
}
|
|
96
|
+
function addWorkflowStreamConnection(context, workflowId, ws) {
|
|
97
|
+
const currentCount = context.workflowStreamConnectionCounts.get(workflowId) ?? 0, maxConnections = context.maxStreamConnectionsPerWorkflow;
|
|
98
|
+
if (currentCount >= maxConnections) {
|
|
99
|
+
ws.close(STREAM_CONNECTION_POLICY_CLOSE_CODE, `maximum stream connections per workflow (${maxConnections}) exceeded`);
|
|
100
|
+
return !1;
|
|
101
|
+
}
|
|
102
|
+
context.workflowStreamConnectionCounts.set(workflowId, currentCount + 1);
|
|
103
|
+
ws.data.workflowStreamConnectionAccepted = !0;
|
|
104
|
+
return !0;
|
|
105
|
+
}
|
|
37
106
|
export function flushPendingStreamMessages(_context, ws) {
|
|
38
107
|
const pendingMessages = ws.data.pendingStreamMessages ?? [];
|
|
39
108
|
pendingMessages.sort((left, right) => left.sequence - right.sequence);
|
|
@@ -41,12 +110,19 @@ export function flushPendingStreamMessages(_context, ws) {
|
|
|
41
110
|
sendStreamMessage(ws, pending.sequence, pending.message);
|
|
42
111
|
ws.data.pendingStreamMessages = [];
|
|
43
112
|
}
|
|
113
|
+
export function flushPendingWatchMessages(_context, ws) {
|
|
114
|
+
const pendingMessages = ws.data.pendingWatchMessages ?? [];
|
|
115
|
+
pendingMessages.sort((left, right) => left.sequence - right.sequence);
|
|
116
|
+
for (const pending of pendingMessages)
|
|
117
|
+
sendWatchMessage(ws, pending.sequence, pending.message);
|
|
118
|
+
ws.data.pendingWatchMessages = [];
|
|
119
|
+
}
|
|
44
120
|
export function publishTokenMessage(context, workflowId, sequence, message) {
|
|
45
121
|
const sockets = context.streamSockets.get(workflowId);
|
|
46
122
|
if (!sockets)
|
|
47
123
|
return;
|
|
48
124
|
for (const ws of sockets) {
|
|
49
|
-
if (ws.data.
|
|
125
|
+
if (ws.data.streamReplayInProgress) {
|
|
50
126
|
ws.data.pendingStreamMessages ??= [];
|
|
51
127
|
ws.data.pendingStreamMessages.push({ sequence, message });
|
|
52
128
|
continue;
|
|
@@ -54,11 +130,29 @@ export function publishTokenMessage(context, workflowId, sequence, message) {
|
|
|
54
130
|
sendStreamMessage(ws, sequence, message);
|
|
55
131
|
}
|
|
56
132
|
}
|
|
133
|
+
export function publishWatchMessage(context, workflowId, sequence, message) {
|
|
134
|
+
const sockets = context.watchSockets.get(workflowId);
|
|
135
|
+
if (!sockets)
|
|
136
|
+
return;
|
|
137
|
+
for (const ws of sockets) {
|
|
138
|
+
if (ws.data.watchReplayInProgress) {
|
|
139
|
+
const pendingMessages = ws.data.pendingWatchMessages ?? [];
|
|
140
|
+
if (pendingMessages.length >= MAX_PENDING_WATCH_REPLAY_MESSAGES) {
|
|
141
|
+
closeWatchSocketForReplayLimit(context, ws, `watch replay buffer exceeded ${MAX_PENDING_WATCH_REPLAY_MESSAGES} pending messages`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
pendingMessages.push({ sequence, message });
|
|
145
|
+
ws.data.pendingWatchMessages = pendingMessages;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
sendWatchMessage(ws, sequence, message);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
57
151
|
export async function replayTokenStream(context, engine, ws, workflowId) {
|
|
58
|
-
ws.data.
|
|
152
|
+
ws.data.streamLastDeliveredSequence = -1;
|
|
59
153
|
try {
|
|
60
154
|
const requestedResumeFrom = ws.data.resumeFrom, after = requestedResumeFrom === void 0 ? -1 : Math.min(requestedResumeFrom, await getHighestStoredStreamSequence(engine, workflowId, "tokens"));
|
|
61
|
-
ws.data.
|
|
155
|
+
ws.data.streamLastDeliveredSequence = after;
|
|
62
156
|
const chunks = after >= 0 ? await engine.getStreamChunks(workflowId, "tokens", { after }) : await engine.getStreamChunks(workflowId, "tokens");
|
|
63
157
|
for (const chunk of chunks) {
|
|
64
158
|
if (typeof chunk.value !== "object" || chunk.value === null)
|
|
@@ -73,7 +167,79 @@ export async function replayTokenStream(context, engine, ws, workflowId) {
|
|
|
73
167
|
} catch (error) {
|
|
74
168
|
console.error(`[weft] Failed to replay token stream for workflow "${workflowId}":`, error);
|
|
75
169
|
} finally {
|
|
76
|
-
ws.data.
|
|
170
|
+
ws.data.streamReplayInProgress = !1;
|
|
77
171
|
flushPendingStreamMessages(context, ws);
|
|
78
172
|
}
|
|
79
173
|
}
|
|
174
|
+
export async function replayWatchEvents(context, engine, ws, workflowId) {
|
|
175
|
+
ws.data.watchLastDeliveredSequence = -1;
|
|
176
|
+
let shouldFlushPending = !0, replayedEvents = 0;
|
|
177
|
+
try {
|
|
178
|
+
const requestedResumeFrom = ws.data.resumeFrom, after = requestedResumeFrom === void 0 ? -1 : Math.min(requestedResumeFrom, await getHighestStoredWatchSequence(engine, workflowId));
|
|
179
|
+
ws.data.watchLastDeliveredSequence = after;
|
|
180
|
+
const prefix = KEYS.eventPrefix(workflowId), scanOptions = after >= 0 ? { gt: KEYS.event(workflowId, after) } : void 0;
|
|
181
|
+
for await (const [storageKey, value] of engine.storage.scan(prefix, scanOptions)) {
|
|
182
|
+
const sequence = parseSequenceFromEventKey(prefix, storageKey);
|
|
183
|
+
if (sequence === null || sequence <= after)
|
|
184
|
+
continue;
|
|
185
|
+
const decoded = decodeStoredWatchEvent(value);
|
|
186
|
+
if (!isStoredWatchEvent(decoded))
|
|
187
|
+
continue;
|
|
188
|
+
if (replayedEvents >= MAX_WATCH_REPLAY_EVENTS) {
|
|
189
|
+
shouldFlushPending = !1;
|
|
190
|
+
closeWatchSocketForReplayLimit(context, ws, `watch replay window exceeds ${MAX_WATCH_REPLAY_EVENTS} events; reconnect with a newer resumeFrom`);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
sendWatchMessage(ws, sequence, JSON.stringify({
|
|
194
|
+
type: decoded.type,
|
|
195
|
+
timestamp: decoded.timestamp,
|
|
196
|
+
data: decoded.data,
|
|
197
|
+
sequence,
|
|
198
|
+
cursor: String(sequence)
|
|
199
|
+
}));
|
|
200
|
+
replayedEvents += 1;
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error(`[weft] Failed to replay watch events for workflow "${workflowId}":`, error);
|
|
204
|
+
shouldFlushPending = !1;
|
|
205
|
+
closeWatchSocketForReplayLimit(context, ws, "watch replay failed before catch-up completed; reconnect with a newer resumeFrom");
|
|
206
|
+
} finally {
|
|
207
|
+
ws.data.watchReplayInProgress = !1;
|
|
208
|
+
if (shouldFlushPending)
|
|
209
|
+
flushPendingWatchMessages(context, ws);
|
|
210
|
+
else
|
|
211
|
+
ws.data.pendingWatchMessages = [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function closeWatchSocketForReplayLimit(context, ws, reason) {
|
|
215
|
+
ws.data.pendingWatchMessages = [];
|
|
216
|
+
ws.data.watchReplayInProgress = !1;
|
|
217
|
+
ws.close(STREAM_CONNECTION_POLICY_CLOSE_CODE, reason);
|
|
218
|
+
removeWatchSocket(context, ws);
|
|
219
|
+
removeWorkflowStreamConnection(context, ws);
|
|
220
|
+
}
|
|
221
|
+
function decodeStoredWatchEvent(value) {
|
|
222
|
+
try {
|
|
223
|
+
return decode(value);
|
|
224
|
+
} catch {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function parseSequenceFromEventKey(prefix, storageKey) {
|
|
229
|
+
if (!storageKey.startsWith(prefix))
|
|
230
|
+
return null;
|
|
231
|
+
const rawSequence = storageKey.slice(prefix.length);
|
|
232
|
+
if (!/^\d+$/.test(rawSequence))
|
|
233
|
+
return null;
|
|
234
|
+
const sequence = Number.parseInt(rawSequence, 10);
|
|
235
|
+
return Number.isSafeInteger(sequence) ? sequence : null;
|
|
236
|
+
}
|
|
237
|
+
function isStoredWatchEvent(value) {
|
|
238
|
+
if (typeof value !== "object" || value === null)
|
|
239
|
+
return !1;
|
|
240
|
+
const record = value;
|
|
241
|
+
return typeof record.type === "string" && typeof record.timestamp === "number" && Number.isFinite(record.timestamp) && isPlainRecord(record.data);
|
|
242
|
+
}
|
|
243
|
+
function isPlainRecord(value) {
|
|
244
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
245
|
+
}
|
|
@@ -37,7 +37,7 @@ function rejectsCrossOriginUpgrade(context, request) {
|
|
|
37
37
|
return context.corsPolicy !== null && origin !== null && !isOriginAllowed(context.corsPolicy, origin);
|
|
38
38
|
}
|
|
39
39
|
function resolvePrincipalForUpgrade(connectionType, authContext) {
|
|
40
|
-
if (connectionType !== "jsonrpc" && connectionType !== "worker")
|
|
40
|
+
if (connectionType !== "jsonrpc" && connectionType !== "worker" && connectionType !== "watch" && connectionType !== "stream")
|
|
41
41
|
return { ok: !0, principal: void 0 };
|
|
42
42
|
if (authContext === void 0)
|
|
43
43
|
return { ok: !0, principal: void 0 };
|
|
@@ -48,10 +48,29 @@ function resolvePrincipalForUpgrade(connectionType, authContext) {
|
|
|
48
48
|
console.error("[weft] WebSocket upgrade principal resolution failed", error);
|
|
49
49
|
return { ok: !1, response: new Response("Authentication context invalid", { status: 401 }) };
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const requiredScope = upgradeScope(connectionType);
|
|
52
|
+
if (requiredScope !== null) {
|
|
53
|
+
if (!isAuthenticated(principal))
|
|
54
|
+
return { ok: !1, response: new Response("Authentication required", { status: 401 }) };
|
|
55
|
+
if (!principal.hasScope(requiredScope))
|
|
56
|
+
return { ok: !1, response: new Response("Insufficient scope", { status: 403 }) };
|
|
57
|
+
}
|
|
53
58
|
return { ok: !0, principal };
|
|
54
59
|
}
|
|
60
|
+
function upgradeScope(connectionType) {
|
|
61
|
+
switch (connectionType) {
|
|
62
|
+
case "worker":
|
|
63
|
+
return "workers:write";
|
|
64
|
+
case "watch":
|
|
65
|
+
return "events:read";
|
|
66
|
+
case "stream":
|
|
67
|
+
return "streams:read";
|
|
68
|
+
case "jsonrpc":
|
|
69
|
+
case "generic":
|
|
70
|
+
case void 0:
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
55
74
|
export function handleWebSocketUpgrade(server, context, options, request, url, authContext) {
|
|
56
75
|
if (request.headers.get("upgrade") !== "websocket")
|
|
57
76
|
return null;
|
|
@@ -3,5 +3,5 @@ import type { ServeOptions } from '../index.ts';
|
|
|
3
3
|
import type { WebSocketData } from '../json-rpc-websocket-runtime.ts';
|
|
4
4
|
import type { ServerContext } from './context.ts';
|
|
5
5
|
export { isInflightRecord } from '../task-state.ts';
|
|
6
|
-
export
|
|
6
|
+
export { withRetry } from './retry.ts';
|
|
7
7
|
export declare function handleWorkerWebSocketMessage(context: ServerContext, options: ServeOptions, ws: ServerWebSocket<WebSocketData>, rawMessage: string | Buffer, cleanupWorkflowIndex: (operationId: string) => void): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decode, encode } from "../../core/codec.js";
|
|
2
|
+
import { WorkerConnectedEvent } from "../../core/events.js";
|
|
2
3
|
import { KEYS } from "../../storage/interface.js";
|
|
3
4
|
import {
|
|
4
5
|
REMOTE_WORKER_PROTOCOL_VERSION,
|
|
@@ -7,35 +8,20 @@ import {
|
|
|
7
8
|
} from "../../worker/protocol.js";
|
|
8
9
|
import { workerProtocolIncompatibleMessage } from "../../worker/worker-protocol-incompatible-error.js";
|
|
9
10
|
import { isAuthenticated } from "../principal.js";
|
|
11
|
+
import { isInflightRecord, readInflightRecord } from "../task-state.js";
|
|
12
|
+
import { withRetry } from "./retry.js";
|
|
13
|
+
import { recordWorkerCapacitySaturationMetric } from "./task-metrics.js";
|
|
10
14
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "../task-state.js";
|
|
15
|
-
import {
|
|
16
|
-
recordTaskExecutionLatencyMetric,
|
|
17
|
-
recordWorkerCapacitySaturationMetric
|
|
18
|
-
} from "./task-metrics.js";
|
|
15
|
+
taskResultPayloadSizeError,
|
|
16
|
+
transitionTaskResultToResolvedWithRetry
|
|
17
|
+
} from "./task-result-resolution.js";
|
|
19
18
|
import { WORKER_STREAM_RE } from "./websocket-upgrade.js";
|
|
20
19
|
const MAX_WORKER_CONCURRENCY = 1000, DEFAULT_WORKER_CONCURRENCY = 10, WORKER_PROTOCOL_CLOSE_CODE = 1002, WORKER_REGISTRATION_CLOSE_CODE = 1008;
|
|
21
20
|
function isWorkerConnection(pathname) {
|
|
22
21
|
return WORKER_STREAM_RE.test(pathname);
|
|
23
22
|
}
|
|
24
23
|
export { isInflightRecord } from "../task-state.js";
|
|
25
|
-
export
|
|
26
|
-
let lastError;
|
|
27
|
-
for (let attempt = 1;attempt <= maxAttempts; attempt++)
|
|
28
|
-
try {
|
|
29
|
-
return await operation();
|
|
30
|
-
} catch (error) {
|
|
31
|
-
lastError = error;
|
|
32
|
-
if (attempt < maxAttempts) {
|
|
33
|
-
console.warn(`[weft] Retrying "${label}" (attempt ${attempt + 1}/${maxAttempts})`);
|
|
34
|
-
await Bun.sleep(100 * attempt);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
throw lastError;
|
|
38
|
-
}
|
|
24
|
+
export { withRetry } from "./retry.js";
|
|
39
25
|
function sendWorkerProtocolMessage(ws, message) {
|
|
40
26
|
ws.send(JSON.stringify(message));
|
|
41
27
|
}
|
|
@@ -83,7 +69,7 @@ function buildWorkerRegistrationInfo(message, queue, concurrency) {
|
|
|
83
69
|
...message.capabilities !== void 0 ? { capabilities: message.capabilities } : {}
|
|
84
70
|
};
|
|
85
71
|
}
|
|
86
|
-
function registerWorker(context, ws, message) {
|
|
72
|
+
function registerWorker(context, options, ws, message) {
|
|
87
73
|
if (!principalMayRegisterWorker(ws.data.principal)) {
|
|
88
74
|
rejectRegistration(ws, "invalid_registration", "Worker registration requires the workers:write scope", message.protocolVersion);
|
|
89
75
|
return;
|
|
@@ -106,6 +92,7 @@ function registerWorker(context, ws, message) {
|
|
|
106
92
|
activities: [...message.activities],
|
|
107
93
|
concurrency: clampedConcurrency
|
|
108
94
|
});
|
|
95
|
+
options.engine.dispatchEvent(new WorkerConnectedEvent(message.workerId, queue, [...message.activities], clampedConcurrency));
|
|
109
96
|
}
|
|
110
97
|
function resolveTaskResultStatus(message) {
|
|
111
98
|
return message.status === "completed" ? "completed" : "failed";
|
|
@@ -128,20 +115,41 @@ function onTaskResultMessage(context, options, ws, message, cleanupWorkflowIndex
|
|
|
128
115
|
});
|
|
129
116
|
return;
|
|
130
117
|
}
|
|
118
|
+
const resolvedStatus = resolveTaskResultStatus(message), payloadError = taskResultPayloadSizeError({
|
|
119
|
+
operationId,
|
|
120
|
+
status: resolvedStatus,
|
|
121
|
+
resolutionReason: resolvedStatus,
|
|
122
|
+
...message.status === "completed" ? { value: message.value } : { error: message.error }
|
|
123
|
+
}, context.payloadSizeMaxBytes);
|
|
131
124
|
context.registry.completeTask(operationId);
|
|
132
125
|
context.deadlineTracker.remove(operationId);
|
|
133
126
|
cleanupWorkflowIndex(operationId);
|
|
134
127
|
recordWorkerCapacitySaturationMetric(context.metricsCollector, context.registry);
|
|
135
128
|
(async () => {
|
|
136
|
-
const inflightRecord = await readInflightRecord(options.engine.storage, operationId)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
const inflightRecord = await readInflightRecord(options.engine.storage, operationId);
|
|
130
|
+
if (payloadError !== null) {
|
|
131
|
+
sendWorkerProtocolMessage(ws, {
|
|
132
|
+
type: "protocolError",
|
|
133
|
+
code: "invalid_message",
|
|
134
|
+
message: payloadError.message
|
|
135
|
+
});
|
|
136
|
+
await transitionTaskResultToResolvedWithRetry(context, options, {
|
|
137
|
+
operationId,
|
|
138
|
+
status: "failed",
|
|
139
|
+
resolutionReason: "failed",
|
|
140
|
+
inflightRecord,
|
|
141
|
+
error: payloadError.message,
|
|
142
|
+
skipPayloadSizeCheck: !0
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
await transitionTaskResultToResolvedWithRetry(context, options, {
|
|
147
|
+
operationId,
|
|
148
|
+
status: resolvedStatus,
|
|
140
149
|
resolutionReason: resolvedStatus,
|
|
150
|
+
inflightRecord,
|
|
141
151
|
...message.status === "completed" ? { value: message.value } : { error: message.error }
|
|
142
152
|
});
|
|
143
|
-
if (inflightRecord !== null)
|
|
144
|
-
recordTaskExecutionLatencyMetric(context.metricsCollector, inflightRecord, resolvedAt);
|
|
145
153
|
})().catch((error) => {
|
|
146
154
|
console.error(`[weft] Failed to transition task "${operationId}" to resolved \u2014 inflight record may leak:`, error);
|
|
147
155
|
});
|
|
@@ -215,7 +223,7 @@ export function handleWorkerWebSocketMessage(context, options, ws, rawMessage, c
|
|
|
215
223
|
}
|
|
216
224
|
switch (message.type) {
|
|
217
225
|
case "register": {
|
|
218
|
-
registerWorker(context, ws, message);
|
|
226
|
+
registerWorker(context, options, ws, message);
|
|
219
227
|
break;
|
|
220
228
|
}
|
|
221
229
|
case "taskResult": {
|
|
@@ -19,12 +19,14 @@ import { type EventBroadcastingHandle } from './runtime/event-broadcasting.ts';
|
|
|
19
19
|
* `tests/auth-warning-filter.test.ts`) and not part of the public API surface.
|
|
20
20
|
*/
|
|
21
21
|
export declare const NO_AUTHENTICATION_WARNING = "[weft] WARNING: server started with NO authentication; all non-public operations are publicly accessible. Configure serve({ auth }) to lock down, or set unauthenticatedAccess: \"reject\" in production to fail closed.";
|
|
22
|
+
export declare const MCP_ORIGIN_CONFIGURATION_WARNING = "[weft] WARNING: MCP HTTP transport is enabled without publicOrigin or trustedHosts. Cross-origin /mcp requests are rejected, and discovery routes that emit absolute URLs return 503. Configure serve({ publicOrigin: \"https://api.example.com\" }) or serve({ trustedHosts: [\"api.example.com\"] }) before exposing the server through a browser or reverse proxy.";
|
|
22
23
|
/**
|
|
23
24
|
* Clamp a user-supplied `workerReconnectGracePeriodMs` into `[0, 5_000]`.
|
|
24
|
-
* Returns the default when undefined or non-finite.
|
|
25
|
+
* Returns the 2000ms default when undefined or non-finite.
|
|
25
26
|
*/
|
|
26
27
|
export declare function clampWorkerReconnectGracePeriod(value: number | undefined): number;
|
|
27
28
|
export declare function assertAuthenticationPosture(options: ServeOptions, environmentRequirement?: string | undefined): void;
|
|
29
|
+
export declare function warnIfMcpOriginConfigurationMissing(options: ServeOptions): void;
|
|
28
30
|
/**
|
|
29
31
|
* A mutable holder for the Bun server instance. The `fetch` handler needs to
|
|
30
32
|
* call back into the server (for WebSocket upgrades) but the server isn't
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decode } from "../core/codec.js";
|
|
2
|
+
import { getEnginePayloadSizeMaxBytes } from "../core/engine/payload-size-policy.js";
|
|
2
3
|
import { createMcpSessionManager } from "../mcp/session.js";
|
|
3
4
|
import { createMetricsCollectorExporter, MetricsCollector } from "../observability/metrics.js";
|
|
4
5
|
import { WorkerRegistry } from "../worker/registry.js";
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
} from "./authentication.js";
|
|
12
13
|
import { DeadlineTracker } from "./deadline-tracker.js";
|
|
13
14
|
import { createEngineEventFeedBackend } from "./engine-event-feed-backend.js";
|
|
15
|
+
import { createFleetEventFeed } from "./fleet-event-feed.js";
|
|
14
16
|
import { closeJsonRpcSessionsForShutdown } from "./json-rpc-websocket-runtime.js";
|
|
15
17
|
import { createLiveOperationRegistry, createLiveRestBindings } from "./rest-bindings.js";
|
|
16
18
|
import {
|
|
@@ -22,12 +24,14 @@ import { resolveCorsPolicy, validateCorsOptions } from "./runtime/cors.js";
|
|
|
22
24
|
import {
|
|
23
25
|
registerWorkflowEventLifecycle
|
|
24
26
|
} from "./runtime/event-broadcasting.js";
|
|
27
|
+
import { shutdownAllWorkers } from "./runtime/shutdown.js";
|
|
25
28
|
import { reconcileOrphanedRecords, scanExpiredTasks } from "./runtime/task-reconciliation.js";
|
|
29
|
+
import { DEFAULT_MAX_STREAM_CONNECTIONS_PER_WORKFLOW } from "./runtime/websocket-stream.js";
|
|
26
30
|
import { isInflightRecord, withRetry } from "./runtime/websocket-worker.js";
|
|
27
31
|
import { TaskQueue } from "./task-queue.js";
|
|
28
32
|
import { createWorkflowEventFeed } from "./workflow-event-feed.js";
|
|
29
|
-
const RECONCILIATION_MULTIPLIER = 12, DEFAULT_WORKER_RECONNECT_GRACE_PERIOD_MS =
|
|
30
|
-
export const NO_AUTHENTICATION_WARNING = '[weft] WARNING: server started with NO authentication; all non-public operations are publicly accessible. Configure serve({ auth }) to lock down, or set unauthenticatedAccess: "reject" in production to fail closed.';
|
|
33
|
+
const RECONCILIATION_MULTIPLIER = 12, DEFAULT_WORKER_RECONNECT_GRACE_PERIOD_MS = 2000, MAX_WORKER_RECONNECT_GRACE_PERIOD_MS = 5000, AUTHENTICATION_REQUIRED_ENVIRONMENT_VARIABLE = "WEFT_SERVER_AUTHENTICATION_REQUIRED";
|
|
34
|
+
export const NO_AUTHENTICATION_WARNING = '[weft] WARNING: server started with NO authentication; all non-public operations are publicly accessible. Configure serve({ auth }) to lock down, or set unauthenticatedAccess: "reject" in production to fail closed.', MCP_ORIGIN_CONFIGURATION_WARNING = '[weft] WARNING: MCP HTTP transport is enabled without publicOrigin or trustedHosts. Cross-origin /mcp requests are rejected, and discovery routes that emit absolute URLs return 503. Configure serve({ publicOrigin: "https://api.example.com" }) or serve({ trustedHosts: ["api.example.com"] }) before exposing the server through a browser or reverse proxy.';
|
|
31
35
|
const NO_AUTHENTICATION_REJECT_ERROR = '[weft] Refusing to start server with no authentication. Configure serve({ auth }) or set unauthenticatedAccess: "allow" only for trusted local development.', NO_AUTHENTICATION_ENVIRONMENT_ERROR = "[weft] Refusing to start server with no authentication because WEFT_SERVER_AUTHENTICATION_REQUIRED requires authentication. Configure serve({ auth }) or unset WEFT_SERVER_AUTHENTICATION_REQUIRED only for trusted local development.", TRUTHY_AUTHENTICATION_REQUIREMENT_VALUES = new Set(["1", "true", "yes", "on"]), FALSY_AUTHENTICATION_REQUIREMENT_VALUES = new Set(["0", "false", "no", "off"]);
|
|
32
36
|
export function clampWorkerReconnectGracePeriod(value) {
|
|
33
37
|
if (value === void 0 || !Number.isFinite(value))
|
|
@@ -61,6 +65,11 @@ export function assertAuthenticationPosture(options, environmentRequirement = Bu
|
|
|
61
65
|
return;
|
|
62
66
|
console.warn(NO_AUTHENTICATION_WARNING);
|
|
63
67
|
}
|
|
68
|
+
export function warnIfMcpOriginConfigurationMissing(options) {
|
|
69
|
+
if (options.publicOrigin !== void 0 || options.trustedHosts !== void 0)
|
|
70
|
+
return;
|
|
71
|
+
console.warn(MCP_ORIGIN_CONFIGURATION_WARNING);
|
|
72
|
+
}
|
|
64
73
|
export function resolveNetworkConfig(options) {
|
|
65
74
|
if (options.auth)
|
|
66
75
|
validateAuthConfig(options.auth);
|
|
@@ -69,6 +78,7 @@ export function resolveNetworkConfig(options) {
|
|
|
69
78
|
if (options.cors)
|
|
70
79
|
validateCorsOptions(options.cors, options.auth !== void 0);
|
|
71
80
|
assertAuthenticationPosture(options);
|
|
81
|
+
warnIfMcpOriginConfigurationMissing(options);
|
|
72
82
|
const port = options.port ?? 7233, hostname = options.hostname ?? "0.0.0.0", development = options.development ?? !1, serverMetricsCollector = new MetricsCollector, prometheusExporter = options.prometheusExporter ?? createMetricsCollectorExporter(serverMetricsCollector), serverOptions = { ...options, prometheusExporter }, tlsOptions = buildTLSOptions(options.auth);
|
|
73
83
|
return { port, hostname, development, tlsOptions, serverOptions, serverMetricsCollector };
|
|
74
84
|
}
|
|
@@ -79,6 +89,9 @@ export function buildServerContext(options, serverMetricsCollector) {
|
|
|
79
89
|
taskQueue,
|
|
80
90
|
workerSockets: new Map,
|
|
81
91
|
streamSockets: new Map,
|
|
92
|
+
watchSockets: new Map,
|
|
93
|
+
workflowStreamConnectionCounts: new Map,
|
|
94
|
+
maxStreamConnectionsPerWorkflow: options.maxStreamConnectionsPerWorkflow ?? DEFAULT_MAX_STREAM_CONNECTIONS_PER_WORKFLOW,
|
|
82
95
|
workerAffinity: new Map,
|
|
83
96
|
workflowOperations: new Map,
|
|
84
97
|
operationToWorkflow: new Map,
|
|
@@ -95,12 +108,14 @@ export function buildServerContext(options, serverMetricsCollector) {
|
|
|
95
108
|
metricsCollector: serverMetricsCollector,
|
|
96
109
|
eventFeedBackend,
|
|
97
110
|
workflowEventFeed: createWorkflowEventFeed(eventFeedBackend),
|
|
111
|
+
fleetEventFeed: createFleetEventFeed(options.engine.storage),
|
|
98
112
|
activeJsonRpcSessions: new Set,
|
|
99
113
|
mcpSessionManager: createMcpSessionManager(options.engine),
|
|
100
114
|
authenticatorPromise: options.auth ? createAuthenticator(options.auth) : null,
|
|
101
115
|
rateLimiter: options.rateLimit ? createRateLimiter(options.rateLimit) : null,
|
|
102
116
|
visibilityPollMs: options.visibilityPollIntervalMs ?? 5000,
|
|
103
117
|
workerReconnectGracePeriodMs: clampWorkerReconnectGracePeriod(options.workerReconnectGracePeriodMs),
|
|
118
|
+
payloadSizeMaxBytes: getEnginePayloadSizeMaxBytes(options.engine),
|
|
104
119
|
pendingWorkerRequeues: new Map,
|
|
105
120
|
scanRunning: !1,
|
|
106
121
|
processingOperations: new Set,
|
|
@@ -148,6 +163,7 @@ export function registerStackDisposers(stack, context, options, broadcastingHand
|
|
|
148
163
|
});
|
|
149
164
|
stack.defer(() => context.mcpSessionManager[Symbol.asyncDispose]());
|
|
150
165
|
stack.defer(registerWorkflowEventLifecycle(options.engine, context, broadcastingHandle));
|
|
166
|
+
stack.defer(() => shutdownAllWorkers(context, options.workerShutdownTimeoutMs === void 0 ? void 0 : { timeoutMs: options.workerShutdownTimeoutMs, stopWaitingWhenIdle: !0 }));
|
|
151
167
|
const visibilityPollHandle = setInterval(() => {
|
|
152
168
|
scanExpiredTasks(context, options, onOperationCleanup);
|
|
153
169
|
}, context.visibilityPollMs), reconciliationIntervalMs = context.visibilityPollMs * RECONCILIATION_MULTIPLIER, reconciliationHandle = setInterval(() => {
|
|
@@ -20,6 +20,8 @@ export type TaskState = 'queued' | 'inflight' | 'resolved';
|
|
|
20
20
|
export type TaskRequeueReason = 'visibility-timeout' | 'worker-disconnect';
|
|
21
21
|
/** Final reason captured when a task reaches the resolved state. */
|
|
22
22
|
export type TaskResolutionReason = 'completed' | 'failed' | 'cancelled' | 'max-attempts-exceeded';
|
|
23
|
+
/** Why a task-result transition was moved to the operator dead-letter guard. */
|
|
24
|
+
export type TaskDeadLetterReason = 'result-resolution-storage-exhausted';
|
|
23
25
|
/** Lifecycle evidence persisted with task records for diagnostics. */
|
|
24
26
|
export interface TaskLifecycleFields {
|
|
25
27
|
/** First time this operation entered a task queue. */
|
|
@@ -103,6 +105,24 @@ export interface ResolvedRecord {
|
|
|
103
105
|
queueLatencyMs?: number | undefined;
|
|
104
106
|
executionLatencyMs?: number | undefined;
|
|
105
107
|
}
|
|
108
|
+
/** Durable operator guard for a task result whose resolved write exhausted retries. */
|
|
109
|
+
export interface DeadLetteredTaskRecord {
|
|
110
|
+
operationId: string;
|
|
111
|
+
reason: TaskDeadLetterReason;
|
|
112
|
+
deadLetteredAt: number;
|
|
113
|
+
errorMessage: string;
|
|
114
|
+
retryAttempts: number;
|
|
115
|
+
status: 'completed' | 'failed';
|
|
116
|
+
activityName?: string | undefined;
|
|
117
|
+
queue?: string | undefined;
|
|
118
|
+
workerId?: string | undefined;
|
|
119
|
+
attempt?: number | undefined;
|
|
120
|
+
visibilityTimeout?: number | undefined;
|
|
121
|
+
workflowId?: string | undefined;
|
|
122
|
+
retryCount?: number | undefined;
|
|
123
|
+
requeueCount?: number | undefined;
|
|
124
|
+
lastRequeueReason?: TaskRequeueReason | undefined;
|
|
125
|
+
}
|
|
106
126
|
export interface TransitionInflightToResolvedOptions {
|
|
107
127
|
resolutionReason?: TaskResolutionReason;
|
|
108
128
|
resolvedAt?: number;
|
|
@@ -131,10 +151,20 @@ export declare function isQueuedRecord(value: unknown): value is QueuedRecord;
|
|
|
131
151
|
export declare function isInflightRecord(value: unknown): value is InflightRecord;
|
|
132
152
|
/** Type guard for decoded storage records in the resolved state. */
|
|
133
153
|
export declare function isResolvedRecord(value: unknown): value is ResolvedRecord;
|
|
154
|
+
/** Type guard for decoded task-result dead-letter records. */
|
|
155
|
+
export declare function isDeadLetteredTaskRecord(value: unknown): value is DeadLetteredTaskRecord;
|
|
134
156
|
/** Decode the queued record for an operation, returning null when absent or malformed. */
|
|
135
157
|
export declare function readQueuedRecord(storage: Storage, operationId: string): Promise<QueuedRecord | null>;
|
|
136
158
|
/** Decode the inflight record for an operation, returning null when absent or malformed. */
|
|
137
159
|
export declare function readInflightRecord(storage: Storage, operationId: string): Promise<InflightRecord | null>;
|
|
160
|
+
/** Decode the task-result dead-letter record for an operation. */
|
|
161
|
+
export declare function readDeadLetteredTaskRecord(storage: Storage, operationId: string): Promise<DeadLetteredTaskRecord | null>;
|
|
162
|
+
/** True when reconciliation should not re-dispatch the operation. */
|
|
163
|
+
export declare function isTaskDeadLettered(storage: Storage, operationId: string): Promise<boolean>;
|
|
164
|
+
/** Persist a task-result dead-letter guard. */
|
|
165
|
+
export declare function writeDeadLetteredTaskRecord(storage: Storage, record: DeadLetteredTaskRecord): Promise<void>;
|
|
166
|
+
/** Clear a task-result dead-letter guard so reconciliation may handle the inflight record again. */
|
|
167
|
+
export declare function clearDeadLetteredTaskRecord(storage: Storage, operationId: string): Promise<void>;
|
|
138
168
|
export declare function calculateQueueLatencyMs(record: TaskLifecycleFields): number | undefined;
|
|
139
169
|
export declare function calculateExecutionLatencyMs(record: TaskLifecycleFields, completedAt: number): number | undefined;
|
|
140
170
|
export declare function calculateHeartbeatAgeMs(record: TaskLifecycleFields & {
|
|
@@ -49,6 +49,12 @@ export function isResolvedRecord(value) {
|
|
|
49
49
|
const record = value;
|
|
50
50
|
return typeof record.operationId === "string" && (record.status === "completed" || record.status === "failed") && typeof record.resolvedAt === "number";
|
|
51
51
|
}
|
|
52
|
+
export function isDeadLetteredTaskRecord(value) {
|
|
53
|
+
if (value === null || typeof value !== "object")
|
|
54
|
+
return !1;
|
|
55
|
+
const record = value;
|
|
56
|
+
return typeof record.operationId === "string" && record.reason === "result-resolution-storage-exhausted" && typeof record.deadLetteredAt === "number" && typeof record.errorMessage === "string" && typeof record.retryAttempts === "number" && (record.status === "completed" || record.status === "failed");
|
|
57
|
+
}
|
|
52
58
|
export async function readQueuedRecord(storage, operationId) {
|
|
53
59
|
const value = await storage.get(KEYS.operationQueued(operationId));
|
|
54
60
|
if (value === null)
|
|
@@ -63,6 +69,28 @@ export async function readInflightRecord(storage, operationId) {
|
|
|
63
69
|
const decoded = decode(value);
|
|
64
70
|
return isInflightRecord(decoded) ? decoded : null;
|
|
65
71
|
}
|
|
72
|
+
export async function readDeadLetteredTaskRecord(storage, operationId) {
|
|
73
|
+
const value = await storage.get(KEYS.operationDeadLetter(operationId));
|
|
74
|
+
if (value === null)
|
|
75
|
+
return null;
|
|
76
|
+
const decoded = decode(value);
|
|
77
|
+
return isDeadLetteredTaskRecord(decoded) ? decoded : null;
|
|
78
|
+
}
|
|
79
|
+
export async function isTaskDeadLettered(storage, operationId) {
|
|
80
|
+
return await readDeadLetteredTaskRecord(storage, operationId) !== null;
|
|
81
|
+
}
|
|
82
|
+
export async function writeDeadLetteredTaskRecord(storage, record) {
|
|
83
|
+
await storage.batch([
|
|
84
|
+
{
|
|
85
|
+
type: "put",
|
|
86
|
+
key: KEYS.operationDeadLetter(record.operationId),
|
|
87
|
+
value: encode(record)
|
|
88
|
+
}
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
export async function clearDeadLetteredTaskRecord(storage, operationId) {
|
|
92
|
+
await storage.delete(KEYS.operationDeadLetter(operationId));
|
|
93
|
+
}
|
|
66
94
|
function normalizeQueuedRecordLifecycle(record, previous) {
|
|
67
95
|
const normalized = {
|
|
68
96
|
...record,
|