@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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builders for the `run`/`resume` {@link WorkerInboundMessage} envelopes the
|
|
3
|
+
* {@link import('./worker-execution-strategy.ts').WorkerExecutionStrategy} sends to a
|
|
4
|
+
* worker. Extracted as free functions so the strategy stays under the line cap and the
|
|
5
|
+
* envelope-construction rules (protocol version, turn id, size cap, host-log-sink
|
|
6
|
+
* stamping) live in one place. The strategy keeps ownership of the turn-id counter and
|
|
7
|
+
* the assert-and-send; these functions only assemble the message.
|
|
8
|
+
*
|
|
9
|
+
* @module core/worker-inbound-message
|
|
10
|
+
*/
|
|
11
|
+
import type { OperationOutcome, WorkerInboundMessage } from './types.ts';
|
|
12
|
+
/** The turn-protocol context every inbound message carries, owned by the strategy. */
|
|
13
|
+
export interface WorkerInboundMessageContext {
|
|
14
|
+
turnId: number;
|
|
15
|
+
maxProtocolMessageBytes: number | undefined;
|
|
16
|
+
/** Whether the engine host installed an `onLog` sink; stamps `hostHasLogSink` (#529). */
|
|
17
|
+
hasLogSink: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Build a `run` inbound message from start parameters and the turn context. */
|
|
20
|
+
export declare function buildRunMessage(parameters: {
|
|
21
|
+
workflowId: string;
|
|
22
|
+
workflowType: string;
|
|
23
|
+
input: unknown;
|
|
24
|
+
checkpoint: ArrayBuffer;
|
|
25
|
+
executionStateOwnerId?: string;
|
|
26
|
+
deadline?: number;
|
|
27
|
+
headers?: [string, string][];
|
|
28
|
+
}, context: WorkerInboundMessageContext): WorkerInboundMessage & {
|
|
29
|
+
type: 'run';
|
|
30
|
+
};
|
|
31
|
+
/** Build a `resume` inbound message from resume parameters and the turn context. */
|
|
32
|
+
export declare function buildResumeMessage(parameters: {
|
|
33
|
+
workflowId: string;
|
|
34
|
+
checkpoint: ArrayBuffer;
|
|
35
|
+
operationResult: OperationOutcome;
|
|
36
|
+
}, context: WorkerInboundMessageContext): WorkerInboundMessage & {
|
|
37
|
+
type: 'resume';
|
|
38
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { WORKER_PROTOCOL_VERSION } from "./worker-protocol.js";
|
|
2
|
+
export function buildRunMessage(parameters, context) {
|
|
3
|
+
const message = {
|
|
4
|
+
type: "run",
|
|
5
|
+
protocolVersion: WORKER_PROTOCOL_VERSION,
|
|
6
|
+
turnId: context.turnId,
|
|
7
|
+
workflowId: parameters.workflowId,
|
|
8
|
+
workflowType: parameters.workflowType,
|
|
9
|
+
checkpoint: parameters.checkpoint,
|
|
10
|
+
input: parameters.input,
|
|
11
|
+
executionStateOwnerId: parameters.executionStateOwnerId ?? parameters.workflowId
|
|
12
|
+
};
|
|
13
|
+
if (context.maxProtocolMessageBytes !== void 0)
|
|
14
|
+
message.maxProtocolMessageBytes = context.maxProtocolMessageBytes;
|
|
15
|
+
if (parameters.deadline !== void 0)
|
|
16
|
+
message.deadline = parameters.deadline;
|
|
17
|
+
if (parameters.headers)
|
|
18
|
+
message.headers = parameters.headers;
|
|
19
|
+
if (context.hasLogSink)
|
|
20
|
+
message.hostHasLogSink = !0;
|
|
21
|
+
return message;
|
|
22
|
+
}
|
|
23
|
+
export function buildResumeMessage(parameters, context) {
|
|
24
|
+
const message = {
|
|
25
|
+
type: "resume",
|
|
26
|
+
protocolVersion: WORKER_PROTOCOL_VERSION,
|
|
27
|
+
turnId: context.turnId,
|
|
28
|
+
workflowId: parameters.workflowId,
|
|
29
|
+
checkpoint: parameters.checkpoint,
|
|
30
|
+
operationResult: parameters.operationResult
|
|
31
|
+
};
|
|
32
|
+
if (context.maxProtocolMessageBytes !== void 0)
|
|
33
|
+
message.maxProtocolMessageBytes = context.maxProtocolMessageBytes;
|
|
34
|
+
if (context.hasLogSink)
|
|
35
|
+
message.hostHasLogSink = !0;
|
|
36
|
+
return message;
|
|
37
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { FailureCategory } from './types.ts';
|
|
2
|
+
import type { WorkflowLogRecord } from './types/workflow-log.ts';
|
|
3
|
+
import type { WorkerExecutionStrategyOptions } from './worker-execution-strategy-options.ts';
|
|
4
|
+
import { type ForwardedWorkerLogOutcome } from './worker-message-helpers.ts';
|
|
5
|
+
import type { WorkerLogMessageCandidate } from './worker-protocol-log.ts';
|
|
6
|
+
/**
|
|
7
|
+
* The verdict the abuse counter returns after recording one forwarded-log outcome:
|
|
8
|
+
* whether the strategy should DISCARD the sending worker for sustained abuse.
|
|
9
|
+
* `'tolerate'` means a single anomaly or an in-budget burst that does not discard.
|
|
10
|
+
* `'discard'` means a threshold was crossed (flood within the window, or accumulated
|
|
11
|
+
* lifetime strikes) and the worker should be discarded as the hardened-worker threat
|
|
12
|
+
* model prescribes.
|
|
13
|
+
*/
|
|
14
|
+
export type WorkerLogAbuseVerdict = 'tolerate' | 'discard';
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for {@link WorkerLogAbuseCounter}. All three thresholds are internal:
|
|
17
|
+
* the engine fixes them to generous defaults rather than exposing operator tuning,
|
|
18
|
+
* because a false discard fails a real user's in-flight workflows (an asymmetric harm).
|
|
19
|
+
* The flood window/threshold are large so honest high-log workflows never trip them; the
|
|
20
|
+
* strike threshold is a small constant because oversize/invalid records are never produced
|
|
21
|
+
* by a well-behaved logger, so a handful in a worker's lifetime already signals abuse.
|
|
22
|
+
*/
|
|
23
|
+
export interface WorkerLogAbuseCounterOptions {
|
|
24
|
+
/** Fixed/anchored window length in milliseconds for the flood budget. */
|
|
25
|
+
readonly floodWindowMs: number;
|
|
26
|
+
/**
|
|
27
|
+
* Maximum forwarded-log ARRIVALS tolerated per worker within `floodWindowMs`
|
|
28
|
+
* before the worker is discarded. Counts every `type:'log'` arrival for a worker
|
|
29
|
+
* — valid, oversize, invalid, or wrong-owner — because the host paid the clone
|
|
30
|
+
* cost on receipt regardless of the record's fate.
|
|
31
|
+
*/
|
|
32
|
+
readonly floodThreshold: number;
|
|
33
|
+
/**
|
|
34
|
+
* Maximum cumulative anomalous (oversize OR invalid) records tolerated over a
|
|
35
|
+
* worker's whole lifetime before discard. NOT window-scoped and NOT reset, so a
|
|
36
|
+
* worker cannot evade by spacing anomalies across windows.
|
|
37
|
+
*/
|
|
38
|
+
readonly strikeThreshold: number;
|
|
39
|
+
/** Monotonic-enough wall clock (ms), injected so tests advance time deterministically. */
|
|
40
|
+
readonly getNow: () => number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Per-worker forwarded-log abuse accounting for the hardened worker path (#545).
|
|
44
|
+
*
|
|
45
|
+
* The #529 host-sink routing forwards a worker's `ctx.log` records to the engine's
|
|
46
|
+
* `EngineOptions.onLog` sink through a deliberately LENIENT lane that bypasses the
|
|
47
|
+
* strict turn watchdog, so a single malformed/oversize/wrong-owner log drops the
|
|
48
|
+
* record without discarding the worker. That leniency leaves two availability gaps
|
|
49
|
+
* a compromised or buggy worker can exploit:
|
|
50
|
+
*
|
|
51
|
+
* 1. **Flooding** — unlimited valid, in-budget logs apply host CPU / sink-buffer
|
|
52
|
+
* pressure without ever tripping the watchdog.
|
|
53
|
+
* 2. **Repeat oversize/invalid** — each forwarded log is structured-cloned by the
|
|
54
|
+
* runtime on receipt (a platform-inherent cost paid before any handler runs), so
|
|
55
|
+
* a worker can repeatedly force large/garbage allocations that the lenient lane
|
|
56
|
+
* then drops.
|
|
57
|
+
*
|
|
58
|
+
* This counter closes both by keeping per-worker state (keyed by the {@link Worker}
|
|
59
|
+
* reference in a {@link WeakMap}, so a discarded/GC'd worker's state is reclaimed
|
|
60
|
+
* automatically). It exposes two record paths the strategy calls and returns a
|
|
61
|
+
* {@link WorkerLogAbuseVerdict} telling the strategy whether to discard:
|
|
62
|
+
*
|
|
63
|
+
* - {@link recordArrival} is called for EVERY `type:'log'` message a worker sends,
|
|
64
|
+
* at the top of the log branch BEFORE the ownership gate — so a worker flooding
|
|
65
|
+
* logs for workflows it does not own is still counted (the host paid the clone
|
|
66
|
+
* cost). It drives the windowed flood budget.
|
|
67
|
+
* - {@link recordOutcome} is called after the ownership gate, with the delivery
|
|
68
|
+
* {@link ForwardedWorkerLogOutcome}, to drive the lifetime strike bucket on
|
|
69
|
+
* anomalous (oversize/invalid) records.
|
|
70
|
+
*
|
|
71
|
+
* Granularity is per-worker (not per-workflow): a pooled worker runs many workflows
|
|
72
|
+
* over its lifetime, the remediation ({@link Worker} discard) is worker-scoped, and
|
|
73
|
+
* the threat model treats the whole worker as the adversary, so per-worker both
|
|
74
|
+
* matches the remediation and defeats spreading abuse thin across many workflows.
|
|
75
|
+
*/
|
|
76
|
+
export declare class WorkerLogAbuseCounter {
|
|
77
|
+
#private;
|
|
78
|
+
constructor(options: WorkerLogAbuseCounterOptions);
|
|
79
|
+
/**
|
|
80
|
+
* Record one forwarded-log ARRIVAL for `worker` and return whether the worker
|
|
81
|
+
* should be discarded for flooding. Called for every `type:'log'` message before
|
|
82
|
+
* the ownership gate. This is a fixed/anchored window (not a true rolling window): an
|
|
83
|
+
* arrival at or beyond `floodWindowMs` after the window's start anchors a fresh window
|
|
84
|
+
* (count resets to 1). Within a window, the verdict is `discard` once arrivals exceed
|
|
85
|
+
* `floodThreshold`. A backwards clock jump (`now < windowStartedAt`, e.g. an NTP step
|
|
86
|
+
* when `getNow` is wall-clock) also re-anchors the window, so clock regression can never
|
|
87
|
+
* hold a window open and accumulate toward a premature discard.
|
|
88
|
+
*/
|
|
89
|
+
recordArrival(worker: Worker): WorkerLogAbuseVerdict;
|
|
90
|
+
/**
|
|
91
|
+
* Record the delivery `outcome` for one forwarded log from `worker` and return
|
|
92
|
+
* whether the worker should be discarded for accumulated anomalies. An
|
|
93
|
+
* `accepted-valid` outcome is a no-op (valid logs are accounted only by the flood
|
|
94
|
+
* budget). An oversize or invalid outcome adds one lifetime strike; the verdict is
|
|
95
|
+
* `discard` once lifetime strikes reach `strikeThreshold`. The `switch` is exhaustive
|
|
96
|
+
* (the `never` default) so that adding a future non-strike dropped outcome forces the
|
|
97
|
+
* strike-vs-no-strike policy decision to be made here rather than defaulting to a strike.
|
|
98
|
+
*/
|
|
99
|
+
recordOutcome(worker: Worker, outcome: ForwardedWorkerLogOutcome): WorkerLogAbuseVerdict;
|
|
100
|
+
/** Drop a worker's accounting (called when the worker is discarded/forgotten). */
|
|
101
|
+
forget(worker: Worker): void;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Narrow construction config for {@link ForwardedLogGate} — decoupled from
|
|
105
|
+
* `WorkerExecutionStrategyOptions` so the gate names only what it consumes. The
|
|
106
|
+
* threshold fields are `| undefined` (the gate applies each default); build this from
|
|
107
|
+
* a strategy's options with {@link forwardedLogGateFromStrategyOptions}.
|
|
108
|
+
*/
|
|
109
|
+
export interface ForwardedLogGateOptions {
|
|
110
|
+
readonly onLog: ((record: WorkflowLogRecord) => void) | undefined;
|
|
111
|
+
readonly maxProtocolMessageBytes: number | undefined;
|
|
112
|
+
readonly getNow: (() => number) | undefined;
|
|
113
|
+
readonly floodWindowMs: number | undefined;
|
|
114
|
+
readonly floodThreshold: number | undefined;
|
|
115
|
+
readonly strikeThreshold: number | undefined;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The complete forwarded-log lane for the hardened worker path: #529 delivery
|
|
119
|
+
* orchestration plus the #545 per-worker abuse counter. Extracted from
|
|
120
|
+
* `WorkerExecutionStrategy` so the strategy's message branch is a one-line delegate
|
|
121
|
+
* and this whole concern — counting policy, ownership-gated delivery, discard
|
|
122
|
+
* decisions — lives in one focused, independently tested module.
|
|
123
|
+
*
|
|
124
|
+
* {@link handle} is the single entry point. It counts EVERY arrival toward the flood
|
|
125
|
+
* budget BEFORE the ownership gate (a worker flooding logs for workflows it does not
|
|
126
|
+
* own is still counted — the host already paid the structured-clone cost on receipt),
|
|
127
|
+
* applies the trust-boundary ownership gate (a worker may forward logs only for a
|
|
128
|
+
* workflow it owns, checked by the injected `ownedByWorker` predicate), delivers
|
|
129
|
+
* owned records to the sink, and feeds the delivery outcome to the lifetime strike
|
|
130
|
+
* bucket. It returns a human-readable discard reason when sustained abuse (flooding
|
|
131
|
+
* OR repeated anomalies) crosses a threshold, or `null` to tolerate. The caller owns
|
|
132
|
+
* the actual worker discard; this gate only decides.
|
|
133
|
+
*/
|
|
134
|
+
export declare class ForwardedLogGate {
|
|
135
|
+
#private;
|
|
136
|
+
/**
|
|
137
|
+
* Construct from a narrow gate-local config (decoupled from the strategy). Defaults
|
|
138
|
+
* are applied here so this is the one place every forwarded-log default lives: `getNow`
|
|
139
|
+
* → `Date.now`, flood window/threshold → the generous worker-protocol constants, strike
|
|
140
|
+
* threshold → the small non-configurable constant. Build it from a strategy's options
|
|
141
|
+
* with {@link forwardedLogGateFromStrategyOptions}.
|
|
142
|
+
*/
|
|
143
|
+
constructor(config: ForwardedLogGateOptions);
|
|
144
|
+
/** Whether a host `onLog` sink is installed (drives the worker's `hostHasLogSink` flag). */
|
|
145
|
+
get hasSink(): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Process one forwarded `log` from `worker`. `ownedByWorker` reports whether the
|
|
148
|
+
* sending worker owns `message.workflowId` (active or parked) — the strategy's
|
|
149
|
+
* ownership state stays the source of truth. Returns ready-to-use discard options on
|
|
150
|
+
* sustained abuse (the strategy passes them straight to its worker-discard path), or
|
|
151
|
+
* `null` to tolerate this occurrence.
|
|
152
|
+
*/
|
|
153
|
+
handle(worker: Worker, message: WorkerLogMessageCandidate, ownedByWorker: (workflowId: string) => boolean): LogAbuseDiscardOptions | null;
|
|
154
|
+
/** Drop a worker's accounting (called when the worker is discarded/forgotten). */
|
|
155
|
+
forget(worker: Worker): void;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The discard options {@link ForwardedLogGate.handle} returns for an abusive worker —
|
|
159
|
+
* a `system`-category discard whose target and other failures carry the same reason.
|
|
160
|
+
* Structurally a subset of the strategy's worker-discard options, so the strategy
|
|
161
|
+
* passes it straight through.
|
|
162
|
+
*/
|
|
163
|
+
export interface LogAbuseDiscardOptions {
|
|
164
|
+
readonly targetCategory: FailureCategory;
|
|
165
|
+
readonly targetError: string;
|
|
166
|
+
readonly otherCategory: FailureCategory;
|
|
167
|
+
readonly otherError: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Build a {@link ForwardedLogGate} from a strategy's options. This is the one place that
|
|
171
|
+
* names {@link WorkerExecutionStrategyOptions} (type-only), so the gate class itself stays
|
|
172
|
+
* decoupled from the broader strategy surface. `maxProtocolMessageBytes` is passed
|
|
173
|
+
* separately because the strategy also consumes it for its protocol guard.
|
|
174
|
+
*/
|
|
175
|
+
export declare function forwardedLogGateFromStrategyOptions(options: WorkerExecutionStrategyOptions | undefined, maxProtocolMessageBytes: number | undefined): ForwardedLogGate;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deliverForwardedWorkerLog
|
|
3
|
+
} from "./worker-message-helpers.js";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD,
|
|
6
|
+
DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS,
|
|
7
|
+
FORWARDED_LOG_STRIKE_THRESHOLD
|
|
8
|
+
} from "./worker-protocol.js";
|
|
9
|
+
|
|
10
|
+
export class WorkerLogAbuseCounter {
|
|
11
|
+
#floodWindowMs;
|
|
12
|
+
#floodThreshold;
|
|
13
|
+
#strikeThreshold;
|
|
14
|
+
#getNow;
|
|
15
|
+
#stateByWorker = new WeakMap;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.#floodWindowMs = options.floodWindowMs;
|
|
18
|
+
this.#floodThreshold = options.floodThreshold;
|
|
19
|
+
this.#strikeThreshold = options.strikeThreshold;
|
|
20
|
+
this.#getNow = options.getNow;
|
|
21
|
+
}
|
|
22
|
+
recordArrival(worker) {
|
|
23
|
+
const now = this.#getNow(), state = this.#stateFor(worker), elapsed = now - state.windowStartedAt;
|
|
24
|
+
if (elapsed >= this.#floodWindowMs || elapsed < 0) {
|
|
25
|
+
state.windowStartedAt = now;
|
|
26
|
+
state.arrivalsInWindow = 0;
|
|
27
|
+
}
|
|
28
|
+
state.arrivalsInWindow += 1;
|
|
29
|
+
return state.arrivalsInWindow > this.#floodThreshold ? "discard" : "tolerate";
|
|
30
|
+
}
|
|
31
|
+
recordOutcome(worker, outcome) {
|
|
32
|
+
switch (outcome) {
|
|
33
|
+
case "accepted-valid":
|
|
34
|
+
return "tolerate";
|
|
35
|
+
case "dropped-oversize":
|
|
36
|
+
case "dropped-invalid": {
|
|
37
|
+
const state = this.#stateFor(worker);
|
|
38
|
+
state.lifetimeStrikes += 1;
|
|
39
|
+
return state.lifetimeStrikes >= this.#strikeThreshold ? "discard" : "tolerate";
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
throw Error(`Unknown forwarded-log outcome: ${String(outcome)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
forget(worker) {
|
|
46
|
+
this.#stateByWorker.delete(worker);
|
|
47
|
+
}
|
|
48
|
+
#stateFor(worker) {
|
|
49
|
+
let state = this.#stateByWorker.get(worker);
|
|
50
|
+
if (!state) {
|
|
51
|
+
state = { windowStartedAt: this.#getNow(), arrivalsInWindow: 0, lifetimeStrikes: 0 };
|
|
52
|
+
this.#stateByWorker.set(worker, state);
|
|
53
|
+
}
|
|
54
|
+
return state;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class ForwardedLogGate {
|
|
59
|
+
#counter;
|
|
60
|
+
#onLog;
|
|
61
|
+
#maxProtocolMessageBytes;
|
|
62
|
+
constructor(config) {
|
|
63
|
+
this.#onLog = config.onLog;
|
|
64
|
+
this.#maxProtocolMessageBytes = config.maxProtocolMessageBytes;
|
|
65
|
+
this.#counter = new WorkerLogAbuseCounter({
|
|
66
|
+
floodWindowMs: config.floodWindowMs ?? DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS,
|
|
67
|
+
floodThreshold: config.floodThreshold ?? DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD,
|
|
68
|
+
strikeThreshold: config.strikeThreshold ?? FORWARDED_LOG_STRIKE_THRESHOLD,
|
|
69
|
+
getNow: config.getNow ?? Date.now
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
get hasSink() {
|
|
73
|
+
return this.#onLog !== void 0;
|
|
74
|
+
}
|
|
75
|
+
handle(worker, message, ownedByWorker) {
|
|
76
|
+
if (this.#counter.recordArrival(worker) === "discard")
|
|
77
|
+
return discardForLogAbuse("forwarded-log flooding");
|
|
78
|
+
if (typeof message.workflowId !== "string" || !ownedByWorker(message.workflowId))
|
|
79
|
+
return null;
|
|
80
|
+
const outcome = deliverForwardedWorkerLog(message, this.#onLog, this.#maxProtocolMessageBytes);
|
|
81
|
+
if (this.#counter.recordOutcome(worker, outcome) === "discard")
|
|
82
|
+
return discardForLogAbuse("repeated oversize/invalid forwarded logs");
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
forget(worker) {
|
|
86
|
+
this.#counter.forget(worker);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function discardForLogAbuse(reason) {
|
|
90
|
+
const error = `Worker discarded for log abuse: ${reason}`;
|
|
91
|
+
return {
|
|
92
|
+
targetCategory: "system",
|
|
93
|
+
targetError: error,
|
|
94
|
+
otherCategory: "system",
|
|
95
|
+
otherError: error
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function forwardedLogGateFromStrategyOptions(options, maxProtocolMessageBytes) {
|
|
99
|
+
return new ForwardedLogGate({
|
|
100
|
+
onLog: options?.onLog,
|
|
101
|
+
maxProtocolMessageBytes,
|
|
102
|
+
getNow: options?.getNow,
|
|
103
|
+
floodWindowMs: options?.forwardedLogFloodWindowMs,
|
|
104
|
+
floodThreshold: options?.forwardedLogFloodThreshold,
|
|
105
|
+
strikeThreshold: options?.forwardedLogStrikeThreshold
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
import type { WorkerOutboundMessage } from './types.ts';
|
|
2
|
+
import type { WorkflowLogRecord } from './types/workflow-log.ts';
|
|
3
|
+
import { type WorkerLogMessageCandidate } from './worker-protocol-log.ts';
|
|
4
|
+
/**
|
|
5
|
+
* The outcome of attempting to deliver one forwarded worker `ctx.log` (#545), produced
|
|
6
|
+
* by {@link deliverForwardedWorkerLog} and consumed by the abuse counter, which
|
|
7
|
+
* classifies each forwarded log by this outcome to feed its two buckets independently:
|
|
8
|
+
*
|
|
9
|
+
* - `accepted-valid`: a structurally valid, in-budget record. Counted toward the flood
|
|
10
|
+
* budget (every owned arrival is) but never a strike. Returned even when no host sink
|
|
11
|
+
* is installed — a valid log still consumes flood budget, because the host already
|
|
12
|
+
* paid the structured-clone cost on receipt regardless of the sink.
|
|
13
|
+
* - `dropped-oversize`: the record exceeded the protocol size cap. An anomaly — a
|
|
14
|
+
* well-behaved worker-side logger never emits oversize records — so it is a strike.
|
|
15
|
+
* - `dropped-invalid`: the record is not a structurally valid {@link WorkflowLogRecord},
|
|
16
|
+
* or its `workflowId` does not match the envelope. Also a strike: a legitimate logger
|
|
17
|
+
* always emits a well-formed record whose id matches the workflow it owns.
|
|
18
|
+
*
|
|
19
|
+
* `dropped-oversize` and `dropped-invalid` both feed the SAME lifetime strike bucket;
|
|
20
|
+
* the distinction is retained only for diagnostics/console fidelity.
|
|
21
|
+
*/
|
|
22
|
+
export type ForwardedWorkerLogOutcome = 'accepted-valid' | 'dropped-oversize' | 'dropped-invalid';
|
|
2
23
|
export declare function emitWorkerMessageToEngine(handler: ((message: WorkerOutboundMessage) => void | Promise<void>) | null, message: WorkerOutboundMessage): boolean | Promise<boolean>;
|
|
3
24
|
export declare function isParkableWaitSignalCheckpoint(message: Extract<WorkerOutboundMessage, {
|
|
4
25
|
type: 'checkpoint';
|
|
5
26
|
}>): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Deliver a forwarded worker `ctx.log` to the host `onLog` sink (#529), AFTER the
|
|
29
|
+
* caller has verified the sending worker owns `message.workflowId` (the trust-boundary
|
|
30
|
+
* ownership gate stays inline in the strategy). This is the mechanical tail: DROP unless
|
|
31
|
+
* the message is within the size cap AND the record is a structurally valid
|
|
32
|
+
* {@link WorkflowLogRecord} whose `workflowId` matches the envelope; then deliver to
|
|
33
|
+
* `onLog`. The log lane is non-fatal per delivery — malformed, identity-mismatched,
|
|
34
|
+
* oversize, throwing-sink — so a SINGLE occurrence never throws and never discards the
|
|
35
|
+
* worker. A throwing host sink falls back to the console via the shared
|
|
36
|
+
* {@link logRecordToConsole}, mirroring the inline sink, so a logging error can never
|
|
37
|
+
* fail the workflow.
|
|
38
|
+
*
|
|
39
|
+
* The size check is intentionally performed BEFORE the structural check so that a huge
|
|
40
|
+
* but otherwise-encodable malformed record is classified `dropped-oversize` rather than
|
|
41
|
+
* `dropped-invalid` (#545): the dominant abuse cost of an oversize record — the runtime's
|
|
42
|
+
* structured clone on receipt — is paid regardless of whether the payload is well-formed.
|
|
43
|
+
* Only a genuine size-cap breach ({@link WorkerProtocolMessageSizeError}) is oversize; the
|
|
44
|
+
* estimator's other throw (cyclic / non-cloneable payloads) is classified `dropped-invalid`.
|
|
45
|
+
*
|
|
46
|
+
* The returned {@link ForwardedWorkerLogOutcome} is what the strategy feeds to the
|
|
47
|
+
* per-worker abuse counter (#545): `accepted-valid` counts a delivered (or, with no
|
|
48
|
+
* sink, would-be-delivered) record; `dropped-oversize`/`dropped-invalid` are anomalies
|
|
49
|
+
* that accumulate lifetime strikes. The helper still NEVER discards a worker — that
|
|
50
|
+
* remediation decision belongs to the counter and the strategy.
|
|
51
|
+
*/
|
|
52
|
+
export declare function deliverForwardedWorkerLog(message: WorkerLogMessageCandidate, onLog: ((record: WorkflowLogRecord) => void) | undefined, maxProtocolMessageBytes: number | undefined): ForwardedWorkerLogOutcome;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { logRecordToConsole } from "./context/workflow-logger.js";
|
|
2
|
+
import { isValidWorkerLogRecord } from "./worker-protocol-log.js";
|
|
3
|
+
import {
|
|
4
|
+
assertWorkerProtocolMessageWithinLimit,
|
|
5
|
+
WorkerProtocolMessageSizeError
|
|
6
|
+
} from "./worker-protocol.js";
|
|
1
7
|
export function emitWorkerMessageToEngine(handler, message) {
|
|
2
8
|
try {
|
|
3
9
|
const emitResult = handler?.(message);
|
|
@@ -12,3 +18,23 @@ export function isParkableWaitSignalCheckpoint(message) {
|
|
|
12
18
|
const operationRequest = message.operationRequest;
|
|
13
19
|
return operationRequest.type === "wait-signal" || operationRequest.kind === "signal-wait";
|
|
14
20
|
}
|
|
21
|
+
export function deliverForwardedWorkerLog(message, onLog, maxProtocolMessageBytes) {
|
|
22
|
+
if (maxProtocolMessageBytes !== void 0)
|
|
23
|
+
try {
|
|
24
|
+
assertWorkerProtocolMessageWithinLimit(message, maxProtocolMessageBytes);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return error instanceof WorkerProtocolMessageSizeError ? "dropped-oversize" : "dropped-invalid";
|
|
27
|
+
}
|
|
28
|
+
if (!isValidWorkerLogRecord(message.record))
|
|
29
|
+
return "dropped-invalid";
|
|
30
|
+
const record = message.record;
|
|
31
|
+
if (record.workflowId !== message.workflowId)
|
|
32
|
+
return "dropped-invalid";
|
|
33
|
+
if (onLog !== void 0)
|
|
34
|
+
try {
|
|
35
|
+
onLog(record);
|
|
36
|
+
} catch {
|
|
37
|
+
logRecordToConsole(record);
|
|
38
|
+
}
|
|
39
|
+
return "accepted-valid";
|
|
40
|
+
}
|
|
@@ -49,7 +49,7 @@ export class WorkerProtocolGuard {
|
|
|
49
49
|
const turn = this.#turnWatchdog.get(worker);
|
|
50
50
|
if (!turn)
|
|
51
51
|
throw new WorkerProtocolError("Worker message arrived outside an active turn");
|
|
52
|
-
if (message.turnId !== turn.turnId || message.workflowId !== turn.workflowId)
|
|
52
|
+
if ((message.type === "log" ? void 0 : message.turnId) !== turn.turnId || message.workflowId !== turn.workflowId)
|
|
53
53
|
throw new WorkerProtocolError("Worker message did not match the active turn");
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure structural validators for worker `log` protocol messages (#529). These have
|
|
3
|
+
* NO dependency on the rest of `worker-protocol.ts` — they are leaf predicates so
|
|
4
|
+
* `worker-protocol.ts` (which owns `WorkerProtocolError` and the strict asserters)
|
|
5
|
+
* can import them without an import cycle. The strict, throwing path
|
|
6
|
+
* (`assertWorkerLogOutbound` in `worker-protocol.ts`) wraps {@link isValidWorkerLogRecord},
|
|
7
|
+
* and the host's lenient delivery path routes on {@link isWorkerLogMessage}, so both
|
|
8
|
+
* paths share one definition of "valid worker log".
|
|
9
|
+
*
|
|
10
|
+
* The `log` lane is intentionally version-tolerant: a `log` carries no turn-protocol
|
|
11
|
+
* state and is best-effort observability, so it bypasses the strict protocol-version
|
|
12
|
+
* negotiation that gates state-changing messages. That is safe while only protocol v1
|
|
13
|
+
* exists; a future incompatible protocol would still send `type: 'log'` and have its
|
|
14
|
+
* record validated structurally here rather than rejected on version. This is the one
|
|
15
|
+
* place that decision lives — see {@link isWorkerLogMessage}.
|
|
16
|
+
*
|
|
17
|
+
* @module core/worker-protocol-log
|
|
18
|
+
*/
|
|
19
|
+
import type { WorkflowLogRecord } from './types/workflow-log.ts';
|
|
20
|
+
/**
|
|
21
|
+
* A candidate `log` outbound message: every field is `unknown` because this lane
|
|
22
|
+
* accepts the message by `type` ALONE and validates the payload separately. Narrowing
|
|
23
|
+
* to this (rather than the final `Extract<WorkerOutboundMessage, { type: 'log' }>`)
|
|
24
|
+
* keeps {@link isWorkerLogMessage} a SOUND predicate — it promises only what it
|
|
25
|
+
* checks. The record is treated as a {@link WorkflowLogRecord} only after
|
|
26
|
+
* {@link isValidWorkerLogRecord} succeeds.
|
|
27
|
+
*/
|
|
28
|
+
export interface WorkerLogMessageCandidate {
|
|
29
|
+
readonly type: 'log';
|
|
30
|
+
readonly protocolVersion?: unknown;
|
|
31
|
+
readonly workflowId?: unknown;
|
|
32
|
+
readonly record?: unknown;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Whether `record` is a structurally complete {@link WorkflowLogRecord} — the single
|
|
36
|
+
* source of truth for "valid worker log payload", shared by the strict-protocol
|
|
37
|
+
* asserter (which throws) and the host's lenient delivery path (which drops). Because
|
|
38
|
+
* the host sink is typed to receive a `WorkflowLogRecord`, this validates the FULL
|
|
39
|
+
* envelope an untrusted worker must supply: `level` (allowed literal), `message`,
|
|
40
|
+
* `workflowId`, `workflowType` (strings), `timestamp` (finite number), and — when
|
|
41
|
+
* present — `attributes` (a plain object). A record missing any required field or
|
|
42
|
+
* carrying a wrong-typed field is rejected so a malformed wire payload can never reach
|
|
43
|
+
* a strongly typed host sink.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isValidWorkerLogRecord(record: unknown): record is WorkflowLogRecord;
|
|
46
|
+
/**
|
|
47
|
+
* Structural type-guard that routes a message into the host's LENIENT log lane: any
|
|
48
|
+
* message whose `type` is `'log'`. It matches on `type` ALONE and narrows only to
|
|
49
|
+
* {@link WorkerLogMessageCandidate} (all payload fields `unknown`) — payload validity
|
|
50
|
+
* is decided later by {@link isValidWorkerLogRecord}, so a malformed log is DROPPED,
|
|
51
|
+
* not sent to the strict accept-or-discard gate. A `log` is best-effort observability
|
|
52
|
+
* and carries no turn-protocol state, so no malformed/oversize/out-of-turn log may
|
|
53
|
+
* ever discard the worker. A non-`log` message returns `false` and flows on to the
|
|
54
|
+
* strict gate unchanged.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isWorkerLogMessage(message: unknown): message is WorkerLogMessageCandidate;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const WORKFLOW_LOG_LEVELS = new Set(["debug", "info", "warn", "error"]);
|
|
2
|
+
function isValidLogAttributes(attributes) {
|
|
3
|
+
if (attributes === void 0)
|
|
4
|
+
return !0;
|
|
5
|
+
if (typeof attributes !== "object" || attributes === null)
|
|
6
|
+
return !1;
|
|
7
|
+
const prototype = Object.getPrototypeOf(attributes);
|
|
8
|
+
return prototype === Object.prototype || prototype === null;
|
|
9
|
+
}
|
|
10
|
+
export function isValidWorkerLogRecord(record) {
|
|
11
|
+
if (typeof record !== "object" || record === null)
|
|
12
|
+
return !1;
|
|
13
|
+
const candidate = record;
|
|
14
|
+
return WORKFLOW_LOG_LEVELS.has(candidate.level) && typeof candidate.message === "string" && typeof candidate.workflowId === "string" && typeof candidate.workflowType === "string" && typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp) && isValidLogAttributes(candidate.attributes);
|
|
15
|
+
}
|
|
16
|
+
export function isWorkerLogMessage(message) {
|
|
17
|
+
return typeof message === "object" && message !== null && message.type === "log";
|
|
18
|
+
}
|
|
@@ -6,6 +6,29 @@ export declare const WORKER_PROTOCOL_VERSION = 1;
|
|
|
6
6
|
export declare const DEFAULT_WORKER_TURN_TIMEOUT_MS = 1000;
|
|
7
7
|
export declare const DEFAULT_WORKER_PROTOCOL_MESSAGE_BYTES = 1048576;
|
|
8
8
|
export declare const MIN_WORKER_PROTOCOL_MESSAGE_BYTES = 4096;
|
|
9
|
+
/**
|
|
10
|
+
* Default fixed-window length (ms) for the forwarded-log flood budget (#545). Paired
|
|
11
|
+
* with {@link DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD} over this window.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS = 60000;
|
|
14
|
+
/**
|
|
15
|
+
* Default maximum forwarded-log arrivals per worker within
|
|
16
|
+
* {@link DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS} before the worker is discarded for
|
|
17
|
+
* flooding (#545). This budget is AGGREGATE per (pooled) worker, across every workflow
|
|
18
|
+
* the worker currently owns — not per workflow. Set deliberately high (~83 arrivals/sec
|
|
19
|
+
* sustained) because the harm is asymmetric: a false discard fails ALL of that worker's
|
|
20
|
+
* in-flight workflows, while a real flood from a compromised worker runs at thousands per
|
|
21
|
+
* second and still trips comfortably. Honest high-log workflows stay well under it.
|
|
22
|
+
*/
|
|
23
|
+
export declare const DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD = 5000;
|
|
24
|
+
/**
|
|
25
|
+
* Cumulative lifetime anomalous (oversize OR structurally invalid) forwarded-log
|
|
26
|
+
* records tolerated per worker before discard (#545). A small constant — a well-behaved
|
|
27
|
+
* worker-side logger never emits oversize or malformed records, so a few in a worker's
|
|
28
|
+
* whole lifetime already signal abuse, and there is no legitimate-traffic reason to make
|
|
29
|
+
* this configurable. Not window-scoped and never reset.
|
|
30
|
+
*/
|
|
31
|
+
export declare const FORWARDED_LOG_STRIKE_THRESHOLD = 5;
|
|
9
32
|
export declare class WorkerProtocolError extends Error {
|
|
10
33
|
constructor(message: string);
|
|
11
34
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { copyBytesToArrayBuffer } from "./byte-arrays.js";
|
|
1
2
|
import { encode, validateCloneable } from "./codec.js";
|
|
2
3
|
import {
|
|
3
4
|
WORKER_REPLAY_SIGNATURE_FORMAT
|
|
4
5
|
} from "./types/checkpoint.js";
|
|
6
|
+
import { isValidWorkerLogRecord } from "./worker-protocol-log.js";
|
|
5
7
|
export {
|
|
6
8
|
WORKER_REPLAY_SIGNATURE_FORMAT
|
|
7
9
|
} from "./types/checkpoint.js";
|
|
8
|
-
export const WORKER_PROTOCOL_VERSION = 1, DEFAULT_WORKER_TURN_TIMEOUT_MS = 1000, DEFAULT_WORKER_PROTOCOL_MESSAGE_BYTES = 1048576, MIN_WORKER_PROTOCOL_MESSAGE_BYTES = 4096;
|
|
10
|
+
export const WORKER_PROTOCOL_VERSION = 1, DEFAULT_WORKER_TURN_TIMEOUT_MS = 1000, DEFAULT_WORKER_PROTOCOL_MESSAGE_BYTES = 1048576, MIN_WORKER_PROTOCOL_MESSAGE_BYTES = 4096, DEFAULT_FORWARDED_LOG_FLOOD_WINDOW_MS = 60000, DEFAULT_FORWARDED_LOG_FLOOD_THRESHOLD = 5000, FORWARDED_LOG_STRIKE_THRESHOLD = 5;
|
|
9
11
|
const BINARY_MARKER = "__weftBinaryBytes", DATE_MARKER = "__weftDate", ERROR_MARKER = "__weftError", MAP_MARKER = "__weftMap", SET_MARKER = "__weftSet", MAX_BOUNDED_ERROR_LENGTH = 512, WORKER_SIGNATURE_EXCLUDED_FIELDS = new Set([
|
|
10
12
|
"attempt",
|
|
11
13
|
"callerStack",
|
|
@@ -21,6 +23,7 @@ const BINARY_MARKER = "__weftBinaryBytes", DATE_MARKER = "__weftDate", ERROR_MAR
|
|
|
21
23
|
"activity",
|
|
22
24
|
"archive",
|
|
23
25
|
"child-workflow",
|
|
26
|
+
"get-version",
|
|
24
27
|
"load",
|
|
25
28
|
"memo",
|
|
26
29
|
"offload",
|
|
@@ -107,6 +110,9 @@ function assertWorkerOutboundVariant(record) {
|
|
|
107
110
|
case "failed":
|
|
108
111
|
assertWorkerFailedOutbound(record);
|
|
109
112
|
return;
|
|
113
|
+
case "log":
|
|
114
|
+
assertWorkerLogOutbound(record);
|
|
115
|
+
return;
|
|
110
116
|
default:
|
|
111
117
|
throw new WorkerProtocolError("Worker outbound message has an unsupported type");
|
|
112
118
|
}
|
|
@@ -121,11 +127,15 @@ function assertWorkerFailedOutbound(record) {
|
|
|
121
127
|
if (typeof record.error !== "string")
|
|
122
128
|
throw new WorkerProtocolError("Worker failed message must include an error string");
|
|
123
129
|
}
|
|
130
|
+
function assertWorkerLogOutbound(record) {
|
|
131
|
+
if (!isValidWorkerLogRecord(record.record))
|
|
132
|
+
throw new WorkerProtocolError("Worker log message must include a valid log record");
|
|
133
|
+
}
|
|
124
134
|
export async function createWorkerReplayOperationSignature(operation, maxStableFieldsBytes) {
|
|
125
135
|
const operationType = workerOperationType(operation), stableFields = stableWorkerOperationFields(operation, operationType), encodedStableFields = encode(stableFields);
|
|
126
136
|
if (encodedStableFields.byteLength > maxStableFieldsBytes)
|
|
127
137
|
throw new WorkerProtocolError(`Worker replay signature input is ${encodedStableFields.byteLength} bytes, exceeding limit ${maxStableFieldsBytes}`);
|
|
128
|
-
const digestBytes = await crypto.subtle.digest("SHA-256", encodedStableFields);
|
|
138
|
+
const digestBytes = await crypto.subtle.digest("SHA-256", copyBytesToArrayBuffer(encodedStableFields));
|
|
129
139
|
return {
|
|
130
140
|
format: WORKER_REPLAY_SIGNATURE_FORMAT,
|
|
131
141
|
operationType,
|
|
@@ -38,19 +38,13 @@ export type WorkflowVersionDiff = {
|
|
|
38
38
|
/**
|
|
39
39
|
* Collect sorted `"${name}@${version}"` version strings from a tool array.
|
|
40
40
|
*
|
|
41
|
-
* Each element
|
|
42
|
-
* `
|
|
43
|
-
*
|
|
44
|
-
* so comparisons are order-independent.
|
|
41
|
+
* Each element exposes a `name` plus an optional `version`. Missing versions
|
|
42
|
+
* default to `"0.0.0"`. The returned array is sorted alphabetically so
|
|
43
|
+
* comparisons are order-independent.
|
|
45
44
|
*/
|
|
46
45
|
export declare function collectToolVersions(tools: Array<{
|
|
47
46
|
name: string;
|
|
48
47
|
version?: string | undefined;
|
|
49
|
-
} | {
|
|
50
|
-
definition: {
|
|
51
|
-
name: string;
|
|
52
|
-
};
|
|
53
|
-
version?: string | undefined;
|
|
54
48
|
}>): string[];
|
|
55
49
|
/**
|
|
56
50
|
* Compare two {@link WorkflowVersionTuple}s and return structured field-level diffs.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export function collectToolVersions(tools) {
|
|
2
2
|
return tools.map((tool) => {
|
|
3
|
-
|
|
4
|
-
if (!name)
|
|
3
|
+
if (!tool.name)
|
|
5
4
|
throw Error("collectToolVersions: tool is missing a required name field");
|
|
6
|
-
return `${name}@${tool.version ?? "0.0.0"}`;
|
|
5
|
+
return `${tool.name}@${tool.version ?? "0.0.0"}`;
|
|
7
6
|
}).toSorted();
|
|
8
7
|
}
|
|
9
8
|
export function diffWorkflowVersionTuples(stored, registered) {
|