@adonis-agora/durable 0.49.0 → 0.50.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/CHANGELOG.md +261 -0
- package/README.md +53 -22
- package/dist/assets/spa/assets/index-DupjrK7N.js +16 -0
- package/dist/assets/spa/assets/index-DupjrK7N.js.map +1 -0
- package/dist/assets/spa/index.html +1 -1
- package/dist/commands/durable_worker.d.ts.map +1 -1
- package/dist/commands/durable_worker.js +9 -8
- package/dist/commands/durable_worker.js.map +1 -1
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +1 -0
- package/dist/configure.js.map +1 -1
- package/dist/providers/dashboard_provider.d.ts +2 -0
- package/dist/providers/dashboard_provider.d.ts.map +1 -1
- package/dist/providers/dashboard_provider.js +50 -6
- package/dist/providers/dashboard_provider.js.map +1 -1
- package/dist/providers/durable_provider.d.ts.map +1 -1
- package/dist/providers/durable_provider.js +143 -34
- package/dist/providers/durable_provider.js.map +1 -1
- package/dist/src/admission-redis/redis-admission-backend.d.ts.map +1 -1
- package/dist/src/admission-redis/redis-admission-backend.js +3 -1
- package/dist/src/admission-redis/redis-admission-backend.js.map +1 -1
- package/dist/src/ambient-step.d.ts +24 -0
- package/dist/src/ambient-step.d.ts.map +1 -0
- package/dist/src/ambient-step.js +42 -0
- package/dist/src/ambient-step.js.map +1 -0
- package/dist/src/base-workflow.d.ts +10 -1
- package/dist/src/base-workflow.d.ts.map +1 -1
- package/dist/src/base-workflow.js.map +1 -1
- package/dist/src/codec-state-store.d.ts +28 -2
- package/dist/src/codec-state-store.d.ts.map +1 -1
- package/dist/src/codec-state-store.js +61 -3
- package/dist/src/codec-state-store.js.map +1 -1
- package/dist/src/commands/worker.d.ts +4 -1
- package/dist/src/commands/worker.d.ts.map +1 -1
- package/dist/src/commands/worker.js +27 -3
- package/dist/src/commands/worker.js.map +1 -1
- package/dist/src/config_types.d.ts +6 -0
- package/dist/src/config_types.d.ts.map +1 -1
- package/dist/src/control-plane-redis/redis-control-plane.d.ts.map +1 -1
- package/dist/src/control-plane-redis/redis-control-plane.js +22 -6
- package/dist/src/control-plane-redis/redis-control-plane.js.map +1 -1
- package/dist/src/control-planes/factory.d.ts +6 -0
- package/dist/src/control-planes/factory.d.ts.map +1 -1
- package/dist/src/control-planes/factory.js +1 -0
- package/dist/src/control-planes/factory.js.map +1 -1
- package/dist/src/dashboard/gateway-adapter.d.ts +15 -5
- package/dist/src/dashboard/gateway-adapter.d.ts.map +1 -1
- package/dist/src/dashboard/gateway-adapter.js +71 -7
- package/dist/src/dashboard/gateway-adapter.js.map +1 -1
- package/dist/src/dashboard/handlers.d.ts +53 -1
- package/dist/src/dashboard/handlers.d.ts.map +1 -1
- package/dist/src/dashboard/handlers.js +200 -20
- package/dist/src/dashboard/handlers.js.map +1 -1
- package/dist/src/dashboard/index.d.ts +2 -2
- package/dist/src/dashboard/index.d.ts.map +1 -1
- package/dist/src/dashboard/index.js +2 -2
- package/dist/src/dashboard/index.js.map +1 -1
- package/dist/src/dashboard/openapi.d.ts.map +1 -1
- package/dist/src/dashboard/openapi.js +71 -1
- package/dist/src/dashboard/openapi.js.map +1 -1
- package/dist/src/define_config.d.ts +122 -8
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/diagnostics-bridge.d.ts +16 -3
- package/dist/src/diagnostics-bridge.d.ts.map +1 -1
- package/dist/src/diagnostics-bridge.js +9 -3
- package/dist/src/diagnostics-bridge.js.map +1 -1
- package/dist/src/discovery-roots.d.ts +92 -0
- package/dist/src/discovery-roots.d.ts.map +1 -0
- package/dist/src/discovery-roots.js +150 -0
- package/dist/src/discovery-roots.js.map +1 -0
- package/dist/src/engine.d.ts +418 -20
- package/dist/src/engine.d.ts.map +1 -1
- package/dist/src/engine.js +1523 -159
- package/dist/src/engine.js.map +1 -1
- package/dist/src/entities.d.ts +36 -1
- package/dist/src/entities.d.ts.map +1 -1
- package/dist/src/entities.js +65 -4
- package/dist/src/entities.js.map +1 -1
- package/dist/src/errors.d.ts +36 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +44 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/event-trigger-bridge.d.ts +8 -0
- package/dist/src/event-trigger-bridge.d.ts.map +1 -1
- package/dist/src/event-trigger-bridge.js +24 -3
- package/dist/src/event-trigger-bridge.js.map +1 -1
- package/dist/src/handshake/announced.d.ts +27 -0
- package/dist/src/handshake/announced.d.ts.map +1 -1
- package/dist/src/handshake/announced.js +62 -0
- package/dist/src/handshake/announced.js.map +1 -1
- package/dist/src/handshake/directory.d.ts +92 -0
- package/dist/src/handshake/directory.d.ts.map +1 -0
- package/dist/src/handshake/directory.js +139 -0
- package/dist/src/handshake/directory.js.map +1 -0
- package/dist/src/hooks/barrel-sources.d.ts +28 -0
- package/dist/src/hooks/barrel-sources.d.ts.map +1 -0
- package/dist/src/hooks/barrel-sources.js +92 -0
- package/dist/src/hooks/barrel-sources.js.map +1 -0
- package/dist/src/hooks/steps.d.ts +12 -3
- package/dist/src/hooks/steps.d.ts.map +1 -1
- package/dist/src/hooks/steps.js +7 -11
- package/dist/src/hooks/steps.js.map +1 -1
- package/dist/src/hooks/workflows.d.ts +12 -3
- package/dist/src/hooks/workflows.d.ts.map +1 -1
- package/dist/src/hooks/workflows.js +7 -13
- package/dist/src/hooks/workflows.js.map +1 -1
- package/dist/src/index.d.ts +12 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces.d.ts +309 -21
- package/dist/src/interfaces.d.ts.map +1 -1
- package/dist/src/interfaces.js +10 -0
- package/dist/src/interfaces.js.map +1 -1
- package/dist/src/metrics.d.ts.map +1 -1
- package/dist/src/metrics.js +5 -0
- package/dist/src/metrics.js.map +1 -1
- package/dist/src/namespaces.d.ts +17 -0
- package/dist/src/namespaces.d.ts.map +1 -0
- package/dist/src/namespaces.js +24 -0
- package/dist/src/namespaces.js.map +1 -0
- package/dist/src/otel/durable-metrics.d.ts.map +1 -1
- package/dist/src/otel/durable-metrics.js +5 -0
- package/dist/src/otel/durable-metrics.js.map +1 -1
- package/dist/src/otel/durable-otel.d.ts.map +1 -1
- package/dist/src/otel/durable-otel.js +5 -0
- package/dist/src/otel/durable-otel.js.map +1 -1
- package/dist/src/pollers.d.ts +10 -1
- package/dist/src/pollers.d.ts.map +1 -1
- package/dist/src/pollers.js +15 -5
- package/dist/src/pollers.js.map +1 -1
- package/dist/src/protocol.d.ts +12 -0
- package/dist/src/protocol.d.ts.map +1 -1
- package/dist/src/protocol.js +27 -1
- package/dist/src/protocol.js.map +1 -1
- package/dist/src/remote-event.d.ts +6 -0
- package/dist/src/remote-event.d.ts.map +1 -0
- package/dist/src/remote-event.js +19 -0
- package/dist/src/remote-event.js.map +1 -0
- package/dist/src/remote-workflow-executor.d.ts +34 -12
- package/dist/src/remote-workflow-executor.d.ts.map +1 -1
- package/dist/src/remote-workflow-executor.js +42 -40
- package/dist/src/remote-workflow-executor.js.map +1 -1
- package/dist/src/run-detail-summary.d.ts +90 -3
- package/dist/src/run-detail-summary.d.ts.map +1 -1
- package/dist/src/run-detail-summary.js +360 -2
- package/dist/src/run-detail-summary.js.map +1 -1
- package/dist/src/run-facets.d.ts +48 -0
- package/dist/src/run-facets.d.ts.map +1 -0
- package/dist/src/run-facets.js +100 -0
- package/dist/src/run-facets.js.map +1 -0
- package/dist/src/run-gateway/interface.d.ts +27 -1
- package/dist/src/run-gateway/interface.d.ts.map +1 -1
- package/dist/src/run-gateway/proxy-run-gateway.d.ts +32 -4
- package/dist/src/run-gateway/proxy-run-gateway.d.ts.map +1 -1
- package/dist/src/run-gateway/proxy-run-gateway.js +101 -5
- package/dist/src/run-gateway/proxy-run-gateway.js.map +1 -1
- package/dist/src/run-gateway/run-request-responder.d.ts +18 -5
- package/dist/src/run-gateway/run-request-responder.d.ts.map +1 -1
- package/dist/src/run-gateway/run-request-responder.js +155 -32
- package/dist/src/run-gateway/run-request-responder.js.map +1 -1
- package/dist/src/run-gateway/store-run-gateway.d.ts +23 -1
- package/dist/src/run-gateway/store-run-gateway.d.ts.map +1 -1
- package/dist/src/run-gateway/store-run-gateway.js +38 -0
- package/dist/src/run-gateway/store-run-gateway.js.map +1 -1
- package/dist/src/search-attributes-schema.d.ts +44 -0
- package/dist/src/search-attributes-schema.d.ts.map +1 -0
- package/dist/src/search-attributes-schema.js +51 -0
- package/dist/src/search-attributes-schema.js.map +1 -0
- package/dist/src/singleton-admission.d.ts +75 -0
- package/dist/src/singleton-admission.d.ts.map +1 -0
- package/dist/src/singleton-admission.js +156 -0
- package/dist/src/singleton-admission.js.map +1 -0
- package/dist/src/singleton-gate.d.ts +23 -8
- package/dist/src/singleton-gate.d.ts.map +1 -1
- package/dist/src/singleton-gate.js +59 -12
- package/dist/src/singleton-gate.js.map +1 -1
- package/dist/src/standard-schema.d.ts +83 -0
- package/dist/src/standard-schema.d.ts.map +1 -0
- package/dist/src/standard-schema.js +31 -0
- package/dist/src/standard-schema.js.map +1 -0
- package/dist/src/step-discovery.d.ts +21 -11
- package/dist/src/step-discovery.d.ts.map +1 -1
- package/dist/src/step-discovery.js +86 -45
- package/dist/src/step-discovery.js.map +1 -1
- package/dist/src/step-ref.d.ts +38 -12
- package/dist/src/step-ref.d.ts.map +1 -1
- package/dist/src/step-ref.js +5 -13
- package/dist/src/step-ref.js.map +1 -1
- package/dist/src/stores/factory.d.ts +6 -0
- package/dist/src/stores/factory.d.ts.map +1 -1
- package/dist/src/stores/factory.js +4 -1
- package/dist/src/stores/factory.js.map +1 -1
- package/dist/src/stores/lucid-helpers.d.ts +2 -0
- package/dist/src/stores/lucid-helpers.d.ts.map +1 -1
- package/dist/src/stores/lucid-helpers.js +7 -0
- package/dist/src/stores/lucid-helpers.js.map +1 -1
- package/dist/src/stores/lucid-mappers.d.ts +25 -0
- package/dist/src/stores/lucid-mappers.d.ts.map +1 -1
- package/dist/src/stores/lucid-mappers.js +81 -18
- package/dist/src/stores/lucid-mappers.js.map +1 -1
- package/dist/src/stores/lucid-schema.d.ts +59 -1
- package/dist/src/stores/lucid-schema.d.ts.map +1 -1
- package/dist/src/stores/lucid-schema.js +271 -25
- package/dist/src/stores/lucid-schema.js.map +1 -1
- package/dist/src/stores/lucid.d.ts +61 -2
- package/dist/src/stores/lucid.d.ts.map +1 -1
- package/dist/src/stores/lucid.js +346 -41
- package/dist/src/stores/lucid.js.map +1 -1
- package/dist/src/telescope/dashboard.d.ts.map +1 -1
- package/dist/src/telescope/dashboard.js +30 -1
- package/dist/src/telescope/dashboard.js.map +1 -1
- package/dist/src/telescope/data-providers.d.ts +19 -1
- package/dist/src/telescope/data-providers.d.ts.map +1 -1
- package/dist/src/telescope/data-providers.js +119 -3
- package/dist/src/telescope/data-providers.js.map +1 -1
- package/dist/src/telescope/extension.d.ts.map +1 -1
- package/dist/src/telescope/extension.js +2 -1
- package/dist/src/telescope/extension.js.map +1 -1
- package/dist/src/telescope/index.d.ts +1 -1
- package/dist/src/telescope/index.d.ts.map +1 -1
- package/dist/src/telescope/index.js +1 -1
- package/dist/src/telescope/index.js.map +1 -1
- package/dist/src/testing/in-memory-state-store.d.ts +44 -15
- package/dist/src/testing/in-memory-state-store.d.ts.map +1 -1
- package/dist/src/testing/in-memory-state-store.js +204 -41
- package/dist/src/testing/in-memory-state-store.js.map +1 -1
- package/dist/src/testing-kit/checkpoint-aggregation-contract.d.ts +16 -0
- package/dist/src/testing-kit/checkpoint-aggregation-contract.d.ts.map +1 -0
- package/dist/src/testing-kit/checkpoint-aggregation-contract.js +228 -0
- package/dist/src/testing-kit/checkpoint-aggregation-contract.js.map +1 -0
- package/dist/src/testing-kit/state-store-conformance.d.ts.map +1 -1
- package/dist/src/testing-kit/state-store-conformance.js +355 -3
- package/dist/src/testing-kit/state-store-conformance.js.map +1 -1
- package/dist/src/transport-pool.d.ts +15 -1
- package/dist/src/transport-pool.d.ts.map +1 -1
- package/dist/src/transport-pool.js +50 -4
- package/dist/src/transport-pool.js.map +1 -1
- package/dist/src/transports/adaptive-concurrency.d.ts +168 -0
- package/dist/src/transports/adaptive-concurrency.d.ts.map +1 -0
- package/dist/src/transports/adaptive-concurrency.js +353 -0
- package/dist/src/transports/adaptive-concurrency.js.map +1 -0
- package/dist/src/transports/bullmq/adaptive-concurrency.d.ts +1 -143
- package/dist/src/transports/bullmq/adaptive-concurrency.d.ts.map +1 -1
- package/dist/src/transports/bullmq/adaptive-concurrency.js +3 -311
- package/dist/src/transports/bullmq/adaptive-concurrency.js.map +1 -1
- package/dist/src/transports/bullmq/bullmq-transport.d.ts +49 -1
- package/dist/src/transports/bullmq/bullmq-transport.d.ts.map +1 -1
- package/dist/src/transports/bullmq/bullmq-transport.js +330 -38
- package/dist/src/transports/bullmq/bullmq-transport.js.map +1 -1
- package/dist/src/transports/bullmq/deps.d.ts +18 -2
- package/dist/src/transports/bullmq/deps.d.ts.map +1 -1
- package/dist/src/transports/bullmq/deps.js +44 -2
- package/dist/src/transports/bullmq/deps.js.map +1 -1
- package/dist/src/transports/db-helpers.d.ts +39 -0
- package/dist/src/transports/db-helpers.d.ts.map +1 -1
- package/dist/src/transports/db-helpers.js +73 -0
- package/dist/src/transports/db-helpers.js.map +1 -1
- package/dist/src/transports/db-remote.d.ts +53 -0
- package/dist/src/transports/db-remote.d.ts.map +1 -0
- package/dist/src/transports/db-remote.js +147 -0
- package/dist/src/transports/db-remote.js.map +1 -0
- package/dist/src/transports/db-schema.d.ts +44 -1
- package/dist/src/transports/db-schema.d.ts.map +1 -1
- package/dist/src/transports/db-schema.js +227 -88
- package/dist/src/transports/db-schema.js.map +1 -1
- package/dist/src/transports/db.d.ts +189 -6
- package/dist/src/transports/db.d.ts.map +1 -1
- package/dist/src/transports/db.js +1291 -137
- package/dist/src/transports/db.js.map +1 -1
- package/dist/src/transports/event-emitter.d.ts +8 -0
- package/dist/src/transports/event-emitter.d.ts.map +1 -1
- package/dist/src/transports/event-emitter.js +36 -3
- package/dist/src/transports/event-emitter.js.map +1 -1
- package/dist/src/transports/factory.d.ts +110 -5
- package/dist/src/transports/factory.d.ts.map +1 -1
- package/dist/src/transports/factory.js +56 -9
- package/dist/src/transports/factory.js.map +1 -1
- package/dist/src/transports/queue-mock-adapter.d.ts +7 -2
- package/dist/src/transports/queue-mock-adapter.d.ts.map +1 -1
- package/dist/src/transports/queue-mock-adapter.js +18 -2
- package/dist/src/transports/queue-mock-adapter.js.map +1 -1
- package/dist/src/transports/queue-remote.d.ts +146 -0
- package/dist/src/transports/queue-remote.d.ts.map +1 -0
- package/dist/src/transports/queue-remote.js +398 -0
- package/dist/src/transports/queue-remote.js.map +1 -0
- package/dist/src/transports/queue.d.ts +159 -6
- package/dist/src/transports/queue.d.ts.map +1 -1
- package/dist/src/transports/queue.js +747 -37
- package/dist/src/transports/queue.js.map +1 -1
- package/dist/src/transports/task-failure.d.ts +31 -0
- package/dist/src/transports/task-failure.d.ts.map +1 -0
- package/dist/src/transports/task-failure.js +50 -0
- package/dist/src/transports/task-failure.js.map +1 -0
- package/dist/src/workflow-als.d.ts +1 -1
- package/dist/src/workflow-als.d.ts.map +1 -1
- package/dist/src/workflow-ctx.d.ts +10 -0
- package/dist/src/workflow-ctx.d.ts.map +1 -1
- package/dist/src/workflow-ctx.js +97 -15
- package/dist/src/workflow-ctx.js.map +1 -1
- package/dist/src/workflow-discovery.d.ts +32 -41
- package/dist/src/workflow-discovery.d.ts.map +1 -1
- package/dist/src/workflow-discovery.js +65 -88
- package/dist/src/workflow-discovery.js.map +1 -1
- package/dist/src/workflow-ref.d.ts +24 -0
- package/dist/src/workflow-ref.d.ts.map +1 -1
- package/dist/src/workflow-ref.js.map +1 -1
- package/dist/stubs/config/durable.stub +6 -0
- package/dist/stubs/config/durable_dashboard.stub +7 -3
- package/dist/stubs/database/migrations/create_durable_tables.stub +2 -1
- package/dist/stubs/database/migrations/create_durable_transport_messages.stub +43 -0
- package/dist/stubs/database/migrations/create_durable_transport_tables.stub +12 -9
- package/dist/stubs/database/migrations/create_durable_transport_worker_keys.stub +1 -1
- package/dist/stubs/make/workflow/main.stub +1 -1
- package/package.json +6 -4
- package/skills/durable-cluster/SKILL.md +80 -11
- package/skills/durable-determinism/SKILL.md +11 -5
- package/skills/durable-reliability/SKILL.md +77 -37
- package/skills/durable-setup/SKILL.md +51 -22
- package/skills/durable-transports-stores/SKILL.md +130 -19
- package/skills/durable-workflows/SKILL.md +71 -18
- package/dist/assets/spa/assets/index-DdB9zxuX.js +0 -16
- package/dist/assets/spa/assets/index-DdB9zxuX.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SingletonQueueFullError } from './errors.js';
|
|
2
|
+
import { SINGLETON_ACTIVE_STATUSES, SINGLETON_ADMITTED_TAG, SINGLETON_TRACKED_TAG, } from './singleton-admission.js';
|
|
2
3
|
const SINGLETON_RETRY_MS = 1000;
|
|
3
4
|
/**
|
|
4
5
|
* Max jitter (ms, each direction) added to {@link SINGLETON_RETRY_MS} so a queue of N gated runs
|
|
@@ -7,13 +8,15 @@ const SINGLETON_RETRY_MS = 1000;
|
|
|
7
8
|
*/
|
|
8
9
|
const SINGLETON_RETRY_JITTER_MS = 250;
|
|
9
10
|
/**
|
|
10
|
-
* Per-key serialization for singleton workflows — start-time back-pressure, FIFO
|
|
11
|
-
* admission, and notify-on-release wakeups. Extracted from {@link WorkflowEngine} so the whole
|
|
11
|
+
* Per-key serialization for singleton workflows — start-time back-pressure, durable atomic FIFO
|
|
12
|
+
* admission (claimed by the store's {@link StateStore.tryAdmitSingleton}), and notify-on-release wakeups. Extracted from {@link WorkflowEngine} so the whole
|
|
12
13
|
* singleton feature lives in one place instead of being smeared across `start`, `execute`, both run
|
|
13
14
|
* loops, and `cancel`.
|
|
14
15
|
*/
|
|
15
16
|
export class SingletonGate {
|
|
16
17
|
deps;
|
|
18
|
+
/** The non-atomic-store warning is printed once per engine, not once per admission. */
|
|
19
|
+
warnedNonAtomic = false;
|
|
17
20
|
constructor(deps) {
|
|
18
21
|
this.deps = deps;
|
|
19
22
|
}
|
|
@@ -29,8 +32,8 @@ export class SingletonGate {
|
|
|
29
32
|
}
|
|
30
33
|
/**
|
|
31
34
|
* Reject a start that would grow the same-key backlog past `limit + maxQueueDepth` (counting
|
|
32
|
-
* `pending`/`running`/`suspended` runs sharing the key in one scan). No-op when no
|
|
33
|
-
* is configured.
|
|
35
|
+
* `pending`/`running`/`suspended`/`blocked` runs sharing the key in one scan). No-op when no
|
|
36
|
+
* `maxQueueDepth` is configured.
|
|
34
37
|
*/
|
|
35
38
|
async assertCapacity(workflow, cfg, input) {
|
|
36
39
|
if (cfg.maxQueueDepth == null)
|
|
@@ -39,27 +42,68 @@ export class SingletonGate {
|
|
|
39
42
|
const queued = await this.deps.store.listRuns({
|
|
40
43
|
tag: this.tag(cfg, input),
|
|
41
44
|
workflow,
|
|
42
|
-
statuses:
|
|
45
|
+
statuses: SINGLETON_ACTIVE_STATUSES,
|
|
43
46
|
});
|
|
44
47
|
if (queued.length >= cap) {
|
|
45
48
|
throw new SingletonQueueFullError(workflow, cfg.key(input), cfg.maxQueueDepth);
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
+
* Claim (or confirm) a slot for `run` under its key, atomically in the store: runs already holding
|
|
53
|
+
* a slot keep it, and free slots go to the oldest waiters by `(createdAt, id)`. A denied run is
|
|
54
|
+
* parked `suspended` on a jittered retry timer by the store, in the same critical section — never
|
|
55
|
+
* over a run a concurrent cancel already settled. Holding a slot is durable (a reserved tag), so a
|
|
56
|
+
* holder that sleeps, waits, is recovered on another instance or loses its lease keeps it until it
|
|
57
|
+
* settles terminally.
|
|
52
58
|
*/
|
|
53
59
|
async admit(run, cfg) {
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
const store = this.deps.store;
|
|
61
|
+
if (!store.tryAdmitSingleton)
|
|
62
|
+
return this.admitByScan(run, cfg);
|
|
63
|
+
const admitted = await store.tryAdmitSingleton(run.id, this.tag(cfg, run.input), run.workflow, cfg.limit ?? 1, this.retryWakeAt());
|
|
64
|
+
if (admitted && !run.tags?.includes(SINGLETON_ADMITTED_TAG)) {
|
|
65
|
+
run.tags = [
|
|
66
|
+
...(run.tags ?? []).filter((t) => t !== SINGLETON_TRACKED_TAG),
|
|
67
|
+
SINGLETON_ADMITTED_TAG,
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
return admitted;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The pre-atomic admission, kept for a custom store without {@link StateStore.tryAdmitSingleton}
|
|
74
|
+
* so an upgrade doesn't break it: `run` is admitted while it is among the `limit` oldest
|
|
75
|
+
* `running`/`suspended` runs sharing its key by `(createdAt, id)`. It is a read followed by a
|
|
76
|
+
* decision, not a claim, so replicas can briefly over-admit and a same-millisecond start can
|
|
77
|
+
* displace a holder — hence the one-time warning. A denied run is parked on the retry timer here,
|
|
78
|
+
* conditionally, so a concurrent cancel is not overwritten.
|
|
79
|
+
*/
|
|
80
|
+
async admitByScan(run, cfg) {
|
|
81
|
+
this.warnNonAtomic();
|
|
56
82
|
const inflight = (await this.deps.store.listRuns({
|
|
57
83
|
tag: this.tag(cfg, run.input),
|
|
58
84
|
workflow: run.workflow,
|
|
59
85
|
statuses: ['running', 'suspended'],
|
|
60
86
|
})).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id));
|
|
61
87
|
const idx = inflight.findIndex((r) => r.id === run.id);
|
|
62
|
-
|
|
88
|
+
if (idx >= 0 && idx < (cfg.limit ?? 1))
|
|
89
|
+
return true;
|
|
90
|
+
await this.deps.store.updateRunIf(run.id, SINGLETON_ACTIVE_STATUSES, {
|
|
91
|
+
status: 'suspended',
|
|
92
|
+
wakeAt: this.retryWakeAt(),
|
|
93
|
+
updatedAt: new Date(),
|
|
94
|
+
});
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
warnNonAtomic() {
|
|
98
|
+
if (this.warnedNonAtomic)
|
|
99
|
+
return;
|
|
100
|
+
this.warnedNonAtomic = true;
|
|
101
|
+
console.warn('[adonis-durable] singleton admission is NOT atomic on this state store: it does not implement ' +
|
|
102
|
+
'StateStore.tryAdmitSingleton, so the engine falls back to a scan of running/suspended runs. ' +
|
|
103
|
+
'Replicas can briefly admit more than `limit` runs per key, and a same-millisecond start can ' +
|
|
104
|
+
'displace a holder. Implement tryAdmitSingleton (see the exported singletonAdmissionTags / ' +
|
|
105
|
+
'singletonAdmissionDenialPatch helpers and the "Store support" section of the singleton docs) ' +
|
|
106
|
+
'to make admission atomic.');
|
|
63
107
|
}
|
|
64
108
|
/**
|
|
65
109
|
* Notify-on-release: a singleton run settled (freeing a slot), so dispatch the oldest gated
|
|
@@ -74,7 +118,10 @@ export class SingletonGate {
|
|
|
74
118
|
const tag = settled.tags?.find((t) => t.startsWith('singleton:'));
|
|
75
119
|
if (!tag)
|
|
76
120
|
return;
|
|
77
|
-
const gated = (await this.deps.store.listRuns({ tag, workflow: settled.workflow, statuses: ['suspended'] }))
|
|
121
|
+
const gated = (await this.deps.store.listRuns({ tag, workflow: settled.workflow, statuses: ['suspended'] }))
|
|
122
|
+
// A suspended HOLDER (sleeping, waiting on a signal) is not waiting for a slot — leave it be.
|
|
123
|
+
.filter((r) => !r.tags?.includes(SINGLETON_ADMITTED_TAG))
|
|
124
|
+
.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id));
|
|
78
125
|
for (const next of gated.slice(0, cfg.limit ?? 1)) {
|
|
79
126
|
// Make the run due NOW rather than clearing its retry timer. The dispatch below goes through
|
|
80
127
|
// the configured runDispatcher, which may legitimately be a NO-OP (a poll-only deployment
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleton-gate.js","sourceRoot":"","sources":["../../src/singleton-gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"singleton-gate.js","sourceRoot":"","sources":["../../src/singleton-gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAElC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC;;;;GAIG;AACH,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAWtC;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IAIK,IAAI;IAHjC,uFAAuF;IAC/E,eAAe,GAAG,KAAK,CAAC;IAEhC,YAA6B,IAAuB;oBAAvB,IAAI;IAAsB,CAAC;IAExD,oFAAoF;IACpF,GAAG,CAAC,GAAoB,EAAE,KAAc;QACtC,OAAO,aAAa,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;IACvC,CAAC;IAED,gGAAgG;IAChG,WAAW;QACT,OAAO,CACL,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YACjB,kBAAkB;YAClB,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,yBAAyB,CAAC,CAChE,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,GAAoB,EAAE,KAAc;QACzE,IAAI,GAAG,CAAC,aAAa,IAAI,IAAI;YAAE,OAAO;QACtC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC5C,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;YACzB,QAAQ;YACR,QAAQ,EAAE,yBAAyB;SACpC,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YACzB,MAAM,IAAI,uBAAuB,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,CAAC,GAAgB,EAAE,GAAoB;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,iBAAiB;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAC5C,GAAG,CAAC,EAAE,EACN,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EACxB,GAAG,CAAC,QAAQ,EACZ,GAAG,CAAC,KAAK,IAAI,CAAC,EACd,IAAI,CAAC,WAAW,EAAE,CACnB,CAAC;QACF,IAAI,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;YAC5D,GAAG,CAAC,IAAI,GAAG;gBACT,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,qBAAqB,CAAC;gBAC9D,sBAAsB;aACvB,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,WAAW,CAAC,GAAgB,EAAE,GAAoB;QAC9D,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,CACf,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC7B,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC;YAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC;SACnC,CAAC,CACH,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5F,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACpD,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,yBAAyB,EAAE;YACnE,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE;SACtB,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,aAAa;QACnB,IAAI,IAAI,CAAC,eAAe;YAAE,OAAO;QACjC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,OAAO,CAAC,IAAI,CACV,gGAAgG;YAC9F,8FAA8F;YAC9F,8FAA8F;YAC9F,4FAA4F;YAC5F,+FAA+F;YAC/F,2BAA2B,CAC9B,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,OAAoB;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,KAAK,GAAG,CACZ,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAC7F;YACC,8FAA8F;aAC7F,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC;aACxD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7F,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;YAClD,6FAA6F;YAC7F,0FAA0F;YAC1F,2FAA2F;YAC3F,uFAAuF;YACvF,4FAA4F;YAC5F,4FAA4F;YAC5F,2BAA2B;YAC3B,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK;iBAClB,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;iBACxE,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored subset of the Standard Schema spec (https://standardschema.dev) — the `~standard`
|
|
3
|
+
* property protocol implemented by zod (3.24+ / 4), valibot, arktype, effect schema and others.
|
|
4
|
+
* Vendored (rather than taken as a dependency) as the spec recommends, so the package stays free of
|
|
5
|
+
* any schema library at runtime: the interface is types only, erased by the build. Source:
|
|
6
|
+
* https://github.com/standard-schema/standard-schema (MIT) — trimmed to the `StandardSchemaV1` shape
|
|
7
|
+
* this package consumes, identical to the copy in the NestJS sibling (`@dudousxd/nestjs-durable-core`).
|
|
8
|
+
*
|
|
9
|
+
* Used by `@Step({ input, output })` / `defineStep`, `register(..., { inputSchema })` /
|
|
10
|
+
* `static workflow = { inputSchema }` and the typed `searchAttributes` schema, so each accepts
|
|
11
|
+
* whichever schema library the app already uses.
|
|
12
|
+
*/
|
|
13
|
+
export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
14
|
+
/** The Standard Schema properties. */
|
|
15
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
16
|
+
}
|
|
17
|
+
export declare namespace StandardSchemaV1 {
|
|
18
|
+
/** The Standard Schema properties interface. */
|
|
19
|
+
interface Props<Input = unknown, Output = Input> {
|
|
20
|
+
/** The version number of the standard. */
|
|
21
|
+
readonly version: 1;
|
|
22
|
+
/** The vendor name of the schema library. */
|
|
23
|
+
readonly vendor: string;
|
|
24
|
+
/** Validates unknown input values. */
|
|
25
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
26
|
+
/** Inferred types associated with the schema. */
|
|
27
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
28
|
+
}
|
|
29
|
+
/** The result interface of the validate function. */
|
|
30
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
31
|
+
/** The result interface if validation succeeds. */
|
|
32
|
+
interface SuccessResult<Output> {
|
|
33
|
+
/** The typed output value. */
|
|
34
|
+
readonly value: Output;
|
|
35
|
+
/** A falsy value for `issues` indicates success. */
|
|
36
|
+
readonly issues?: undefined;
|
|
37
|
+
}
|
|
38
|
+
/** The result interface if validation fails. */
|
|
39
|
+
interface FailureResult {
|
|
40
|
+
/** The issues of failed validation. */
|
|
41
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
42
|
+
}
|
|
43
|
+
/** The issue interface of the failure output. */
|
|
44
|
+
interface Issue {
|
|
45
|
+
/** The error message of the issue. */
|
|
46
|
+
readonly message: string;
|
|
47
|
+
/** The path of the issue, if any. */
|
|
48
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
49
|
+
}
|
|
50
|
+
/** The path segment interface of the issue. */
|
|
51
|
+
interface PathSegment {
|
|
52
|
+
/** The key representing a path segment. */
|
|
53
|
+
readonly key: PropertyKey;
|
|
54
|
+
}
|
|
55
|
+
/** The Standard Schema types interface. */
|
|
56
|
+
interface Types<Input = unknown, Output = Input> {
|
|
57
|
+
/** The input type of the schema. */
|
|
58
|
+
readonly input: Input;
|
|
59
|
+
/** The output type of the schema. */
|
|
60
|
+
readonly output: Output;
|
|
61
|
+
}
|
|
62
|
+
/** Infers the input type of a Standard Schema. */
|
|
63
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
|
|
64
|
+
/** Infers the output type of a Standard Schema. */
|
|
65
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate `value` against any Standard Schema and return the schema's OUTPUT value (parsed /
|
|
69
|
+
* coerced / defaulted — e.g. zod's `.transform`, valibot's `pipe`, arktype morphs). Both a sync and
|
|
70
|
+
* an async (`Promise`-returning) `~standard.validate` are supported. On failure throws a
|
|
71
|
+
* {@link SchemaValidationError} — a non-retryable `FatalError` (code `schema_validation`) carrying the
|
|
72
|
+
* issues in `details`, so a bad payload fails fast instead of being retried forever.
|
|
73
|
+
*
|
|
74
|
+
* `label` names what was validated in the error message, e.g. `step "billing:charge" input`.
|
|
75
|
+
*/
|
|
76
|
+
export declare function validateStandard<S extends StandardSchemaV1>(schema: S, value: unknown, label: string): Promise<StandardSchemaV1.InferOutput<S>>;
|
|
77
|
+
/**
|
|
78
|
+
* Synchronous {@link validateStandard}, for call sites that must not await a validator (the typed
|
|
79
|
+
* search-attributes write, where an async refinement could make replay nondeterministic). A schema
|
|
80
|
+
* whose `validate` returns a `Promise` throws a clear error instead of being silently awaited.
|
|
81
|
+
*/
|
|
82
|
+
export declare function validateStandardSync<S extends StandardSchemaV1>(schema: S, value: unknown, label: string): StandardSchemaV1.InferOutput<S>;
|
|
83
|
+
//# sourceMappingURL=standard-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard-schema.d.ts","sourceRoot":"","sources":["../../src/standard-schema.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;IAC/D,sCAAsC;IACtC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;CAC7D;AAED,MAAM,CAAC,OAAO,WAAW,gBAAgB,CAAC;IACxC,gDAAgD;IAChD,UAAU,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;QAC7C,0CAA0C;QAC1C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,6CAA6C;QAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,sCAAsC;QACtC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAChF,iDAAiD;QACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;KACnD;IAED,qDAAqD;IACrD,KAAK,MAAM,CAAC,MAAM,IAAI,aAAa,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC;IAE5D,mDAAmD;IACnD,UAAU,aAAa,CAAC,MAAM;QAC5B,8BAA8B;QAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,oDAAoD;QACpD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;KAC7B;IAED,gDAAgD;IAChD,UAAU,aAAa;QACrB,uCAAuC;QACvC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;KACvC;IAED,iDAAiD;IACjD,UAAU,KAAK;QACb,sCAAsC;QACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,qCAAqC;QACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,SAAS,CAAC;KACtE;IAED,+CAA+C;IAC/C,UAAU,WAAW;QACnB,2CAA2C;QAC3C,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;KAC3B;IAED,2CAA2C;IAC3C,UAAU,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;QAC7C,oCAAoC;QACpC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QACtB,qCAAqC;QACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB;IAED,kDAAkD;IAClD,KAAK,UAAU,CAAC,MAAM,SAAS,gBAAgB,IAAI,WAAW,CAC5D,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAC7B,CAAC,OAAO,CAAC,CAAC;IAEX,mDAAmD;IACnD,KAAK,WAAW,CAAC,MAAM,SAAS,gBAAgB,IAAI,WAAW,CAC7D,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAC7B,CAAC,QAAQ,CAAC,CAAC;CACb;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,EAC/D,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAI1C;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,gBAAgB,EAC7D,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,GACZ,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CASjC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SchemaValidationError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validate `value` against any Standard Schema and return the schema's OUTPUT value (parsed /
|
|
4
|
+
* coerced / defaulted — e.g. zod's `.transform`, valibot's `pipe`, arktype morphs). Both a sync and
|
|
5
|
+
* an async (`Promise`-returning) `~standard.validate` are supported. On failure throws a
|
|
6
|
+
* {@link SchemaValidationError} — a non-retryable `FatalError` (code `schema_validation`) carrying the
|
|
7
|
+
* issues in `details`, so a bad payload fails fast instead of being retried forever.
|
|
8
|
+
*
|
|
9
|
+
* `label` names what was validated in the error message, e.g. `step "billing:charge" input`.
|
|
10
|
+
*/
|
|
11
|
+
export async function validateStandard(schema, value, label) {
|
|
12
|
+
const result = await schema['~standard'].validate(value);
|
|
13
|
+
if (result.issues)
|
|
14
|
+
throw new SchemaValidationError(label, result.issues);
|
|
15
|
+
return result.value;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Synchronous {@link validateStandard}, for call sites that must not await a validator (the typed
|
|
19
|
+
* search-attributes write, where an async refinement could make replay nondeterministic). A schema
|
|
20
|
+
* whose `validate` returns a `Promise` throws a clear error instead of being silently awaited.
|
|
21
|
+
*/
|
|
22
|
+
export function validateStandardSync(schema, value, label) {
|
|
23
|
+
const result = schema['~standard'].validate(value);
|
|
24
|
+
if (result instanceof Promise) {
|
|
25
|
+
throw new TypeError(`${label}: schema validation must be synchronous (the schema's \`~standard.validate\` returned a Promise) — drop any async refinement from it.`);
|
|
26
|
+
}
|
|
27
|
+
if (result.issues)
|
|
28
|
+
throw new SchemaValidationError(label, result.issues);
|
|
29
|
+
return result.value;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=standard-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard-schema.js","sourceRoot":"","sources":["../../src/standard-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAkFpD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAS,EACT,KAAc,EACd,KAAa;IAEb,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzD,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC,KAAwC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAS,EACT,KAAc,EACd,KAAa;IAEb,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnD,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CACjB,GAAG,KAAK,uIAAuI,CAChJ,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC,KAAwC,CAAC;AACzD,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BarrelTree, type RootedBarrel } from './discovery-roots.js';
|
|
1
2
|
import type { StepLogger } from './interfaces.js';
|
|
2
3
|
import type { StepHandler } from './protocol.js';
|
|
3
4
|
import { type DurableStepMeta } from './step-ref.js';
|
|
@@ -13,7 +14,7 @@ export interface DiscoveredStep {
|
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* Register a single discovered step on `server` under its stamped name, wrapping it with any
|
|
16
|
-
* declared
|
|
17
|
+
* declared schema validation. The low-level `transport.handle(name, fn)` stays the escape hatch — this
|
|
17
18
|
* is the convention the `app/steps` discovery builds on.
|
|
18
19
|
*/
|
|
19
20
|
export declare function registerStep(server: StepServer, step: DiscoveredStep): void;
|
|
@@ -28,16 +29,25 @@ export declare function collectSteps(exported: unknown): DiscoveredStep[];
|
|
|
28
29
|
* onto `server`. De-duplicated by routing name (last wins). Returns the registered metadata. */
|
|
29
30
|
export declare function registerSteps(server: StepServer, exports: Iterable<unknown>): DurableStepMeta[];
|
|
30
31
|
/**
|
|
31
|
-
* Scan `dir`
|
|
32
|
-
* handler on `server
|
|
33
|
-
* extension present in
|
|
34
|
-
* (the convention is opt-in).
|
|
32
|
+
* Scan `dir` — one directory or several — RECURSIVELY and register every exported `@Step` class /
|
|
33
|
+
* `defineStep` handler on `server`: the `app/steps` convention, mirroring `app/workflows` discovery.
|
|
34
|
+
* Only the extension present in each directory is imported (see `pickModuleExt`). Missing
|
|
35
|
+
* directory → nothing from it (the convention is opt-in). With several directories the same step
|
|
36
|
+
* name defined by different handlers in two of them throws a {@link DuplicateDiscoveryError}.
|
|
37
|
+
* Returns the registered metadata.
|
|
38
|
+
*
|
|
39
|
+
* `server` is anything with `handle(name, fn)`: a transport, the store-less `WorkerRuntime`, or the
|
|
40
|
+
* `WorkflowEngine` itself (it forwards to its primary transport) — the latter is how app code
|
|
41
|
+
* serves an extra directory from a preload: `await registerStepsFromDir(engine, dir)`.
|
|
35
42
|
*/
|
|
36
|
-
export declare function registerStepsFromDir(server: StepServer, dir: string): Promise<DurableStepMeta[]>;
|
|
43
|
+
export declare function registerStepsFromDir(server: StepServer, dir: string | readonly string[]): Promise<DurableStepMeta[]>;
|
|
37
44
|
/** The build-time barrel shape the Assembler `init` hook generates for `app/steps` (key → lazy
|
|
38
|
-
* module import
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
* module import, nested per sub-directory), mirroring
|
|
46
|
+
* {@link import('./workflow-discovery.js').WorkflowsBarrel}. A multi-root hook writes a
|
|
47
|
+
* {@link RootedBarrel} array instead. */
|
|
48
|
+
export type StepsBarrel = BarrelTree;
|
|
49
|
+
/** Register every `@Step`/`defineStep` reachable from a generated {@link StepsBarrel} (or a
|
|
50
|
+
* multi-root {@link RootedBarrel} array) onto `server` — the build-time equivalent of
|
|
51
|
+
* {@link registerStepsFromDir} with no runtime `readdir`, same cross-root duplicate rule. */
|
|
52
|
+
export declare function registerStepsFromBarrel(server: StepServer, barrel: StepsBarrel | readonly RootedBarrel[]): Promise<DurableStepMeta[]>;
|
|
43
53
|
//# sourceMappingURL=step-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-discovery.d.ts","sourceRoot":"","sources":["../../src/step-discovery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"step-discovery.d.ts","sourceRoot":"","sources":["../../src/step-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAIf,KAAK,YAAY,EAElB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,KAAK,eAAe,EAAc,MAAM,eAAe,CAAC;AAEjE;uFACuF;AACvF,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7C;AAED,+FAA+F;AAC/F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAoBD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,cAAc,EAAE,CA8BhE;AAED;iGACiG;AACjG,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,eAAe,EAAE,CAY/F;AAmED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAC9B,OAAO,CAAC,eAAe,EAAE,CAAC,CAE5B;AAED;;;0CAG0C;AAC1C,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC;AAErC;;8FAE8F;AAC9F,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,WAAW,GAAG,SAAS,YAAY,EAAE,GAC5C,OAAO,CAAC,eAAe,EAAE,CAAC,CAE5B"}
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { pathToFileURL } from 'node:url';
|
|
1
|
+
import { barrelModules, DuplicateDiscoveryError, scanDirsModules, } from './discovery-roots.js';
|
|
2
|
+
import { validateStandard } from './standard-schema.js';
|
|
4
3
|
import { DURABLE_STEP_NAME } from './step-name-symbol.js';
|
|
5
4
|
import { stepMetaOf } from './step-ref.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
* schema is served as-is (compile-time types only). */
|
|
5
|
+
/** Wrap a handler with the opt-in Standard Schema validation its `@Step`/`defineStep` metadata
|
|
6
|
+
* declared: `input` is validated before the body runs (the body receives the schema's OUTPUT value),
|
|
7
|
+
* `output` before the result is handed back. A failure throws a non-retryable
|
|
8
|
+
* `SchemaValidationError`. A handler with neither schema is served as-is (compile-time types only). */
|
|
10
9
|
function validating(step) {
|
|
11
10
|
const { meta, handler } = step;
|
|
12
11
|
if (!meta.input && !meta.output)
|
|
13
12
|
return handler;
|
|
14
13
|
return async (input, log) => {
|
|
15
|
-
const parsed = meta.input
|
|
14
|
+
const parsed = meta.input
|
|
15
|
+
? await validateStandard(meta.input, input, `step "${meta.name}" input`)
|
|
16
|
+
: input;
|
|
16
17
|
const output = await handler(parsed, log);
|
|
17
|
-
return meta.output
|
|
18
|
+
return meta.output
|
|
19
|
+
? validateStandard(meta.output, output, `step "${meta.name}" output`)
|
|
20
|
+
: output;
|
|
18
21
|
};
|
|
19
22
|
}
|
|
20
23
|
/**
|
|
21
24
|
* Register a single discovered step on `server` under its stamped name, wrapping it with any
|
|
22
|
-
* declared
|
|
25
|
+
* declared schema validation. The low-level `transport.handle(name, fn)` stays the escape hatch — this
|
|
23
26
|
* is the convention the `app/steps` discovery builds on.
|
|
24
27
|
*/
|
|
25
28
|
export function registerStep(server, step) {
|
|
@@ -77,32 +80,65 @@ export function registerSteps(server, exports) {
|
|
|
77
80
|
}
|
|
78
81
|
return registered;
|
|
79
82
|
}
|
|
83
|
+
/** The routing names an export would serve, read off its stamps WITHOUT instantiating anything. */
|
|
84
|
+
function stepNamesOf(exported) {
|
|
85
|
+
const direct = stepMetaOf(exported);
|
|
86
|
+
if (direct)
|
|
87
|
+
return [direct.name];
|
|
88
|
+
if (typeof exported !== 'function' || !exported.prototype)
|
|
89
|
+
return [];
|
|
90
|
+
const proto = exported.prototype;
|
|
91
|
+
const names = [];
|
|
92
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
93
|
+
const value = proto[key];
|
|
94
|
+
if (typeof value !== 'function')
|
|
95
|
+
continue;
|
|
96
|
+
const name = stepMetaOf(value)?.name;
|
|
97
|
+
if (name)
|
|
98
|
+
names.push(name);
|
|
99
|
+
}
|
|
100
|
+
return names;
|
|
101
|
+
}
|
|
80
102
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
103
|
+
* Register every step reachable from `modules`, in order. Per module this is exactly
|
|
104
|
+
* {@link registerSteps} — the single-directory behaviour, kept as-is: inside one root a name served
|
|
105
|
+
* twice is served by the later module.
|
|
106
|
+
*
|
|
107
|
+
* Across roots, a step name already served from another root by a DIFFERENT export throws a
|
|
108
|
+
* {@link DuplicateDiscoveryError} naming both files — checked for every module BEFORE any handler is
|
|
109
|
+
* registered, so a clash never leaves a half-served transport. The same export reachable from two
|
|
110
|
+
* roots (a re-export, or overlapping roots) is served once.
|
|
85
111
|
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
112
|
+
async function registerStepModules(server, modules) {
|
|
113
|
+
const owners = new Map();
|
|
114
|
+
const plan = [];
|
|
115
|
+
for (const { root, file, load } of modules) {
|
|
116
|
+
const mod = await load();
|
|
117
|
+
const exports = [];
|
|
118
|
+
for (const exported of Object.values(mod)) {
|
|
119
|
+
let servedElsewhere = false;
|
|
120
|
+
for (const name of stepNamesOf(exported)) {
|
|
121
|
+
const owner = owners.get(name);
|
|
122
|
+
if (!owner) {
|
|
123
|
+
owners.set(name, { root, file, source: exported });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (owner.root === root)
|
|
127
|
+
continue;
|
|
128
|
+
if (owner.source !== exported) {
|
|
129
|
+
throw new DuplicateDiscoveryError('step', name, [owner.file, file]);
|
|
130
|
+
}
|
|
131
|
+
servedElsewhere = true;
|
|
132
|
+
}
|
|
133
|
+
if (!servedElsewhere)
|
|
134
|
+
exports.push(exported);
|
|
135
|
+
}
|
|
136
|
+
plan.push(exports);
|
|
95
137
|
}
|
|
96
|
-
const moduleExt = pickModuleExt(entries);
|
|
97
138
|
const registered = [];
|
|
98
|
-
if (moduleExt === null)
|
|
99
|
-
return registered;
|
|
100
139
|
const seen = new Set();
|
|
101
|
-
for (const
|
|
102
|
-
|
|
103
|
-
continue;
|
|
104
|
-
const mod = (await import(pathToFileURL(join(dir, entry)).href));
|
|
105
|
-
for (const meta of registerSteps(server, Object.values(mod))) {
|
|
140
|
+
for (const exports of plan) {
|
|
141
|
+
for (const meta of registerSteps(server, exports)) {
|
|
106
142
|
if (seen.has(meta.name))
|
|
107
143
|
continue;
|
|
108
144
|
seen.add(meta.name);
|
|
@@ -111,20 +147,25 @@ export async function registerStepsFromDir(server, dir) {
|
|
|
111
147
|
}
|
|
112
148
|
return registered;
|
|
113
149
|
}
|
|
114
|
-
/**
|
|
115
|
-
*
|
|
150
|
+
/**
|
|
151
|
+
* Scan `dir` — one directory or several — RECURSIVELY and register every exported `@Step` class /
|
|
152
|
+
* `defineStep` handler on `server`: the `app/steps` convention, mirroring `app/workflows` discovery.
|
|
153
|
+
* Only the extension present in each directory is imported (see `pickModuleExt`). Missing
|
|
154
|
+
* directory → nothing from it (the convention is opt-in). With several directories the same step
|
|
155
|
+
* name defined by different handlers in two of them throws a {@link DuplicateDiscoveryError}.
|
|
156
|
+
* Returns the registered metadata.
|
|
157
|
+
*
|
|
158
|
+
* `server` is anything with `handle(name, fn)`: a transport, the store-less `WorkerRuntime`, or the
|
|
159
|
+
* `WorkflowEngine` itself (it forwards to its primary transport) — the latter is how app code
|
|
160
|
+
* serves an extra directory from a preload: `await registerStepsFromDir(engine, dir)`.
|
|
161
|
+
*/
|
|
162
|
+
export async function registerStepsFromDir(server, dir) {
|
|
163
|
+
return registerStepModules(server, await scanDirsModules(typeof dir === 'string' ? [dir] : dir));
|
|
164
|
+
}
|
|
165
|
+
/** Register every `@Step`/`defineStep` reachable from a generated {@link StepsBarrel} (or a
|
|
166
|
+
* multi-root {@link RootedBarrel} array) onto `server` — the build-time equivalent of
|
|
167
|
+
* {@link registerStepsFromDir} with no runtime `readdir`, same cross-root duplicate rule. */
|
|
116
168
|
export async function registerStepsFromBarrel(server, barrel) {
|
|
117
|
-
|
|
118
|
-
const seen = new Set();
|
|
119
|
-
for (const load of Object.values(barrel)) {
|
|
120
|
-
const mod = await load();
|
|
121
|
-
for (const meta of registerSteps(server, Object.values(mod))) {
|
|
122
|
-
if (seen.has(meta.name))
|
|
123
|
-
continue;
|
|
124
|
-
seen.add(meta.name);
|
|
125
|
-
registered.push(meta);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return registered;
|
|
169
|
+
return registerStepModules(server, barrelModules(barrel));
|
|
129
170
|
}
|
|
130
171
|
//# sourceMappingURL=step-discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-discovery.js","sourceRoot":"","sources":["../../src/step-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"step-discovery.js","sourceRoot":"","sources":["../../src/step-discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/src/step-ref.d.ts
CHANGED
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
import type { z } from 'zod';
|
|
2
1
|
import type { BackoffStrategy, StepLogger } from './interfaces.js';
|
|
2
|
+
import type { StandardSchemaV1 } from './standard-schema.js';
|
|
3
3
|
import { type StepRef } from './step-name-symbol.js';
|
|
4
4
|
/**
|
|
5
5
|
* The full metadata a `@Step` / {@link defineStep} stamps on a step handler for discovery: its
|
|
6
|
-
* resolved routing `name` plus the opt-in runtime
|
|
6
|
+
* resolved routing `name` plus the opt-in runtime Standard Schemas (zod, valibot, arktype, …) an
|
|
7
|
+
* authoring layer attached. Stamped
|
|
7
8
|
* under {@link DURABLE_STEP_META} on the handler function so step discovery can wrap it with
|
|
8
9
|
* validation at the serve boundary. A global-registry symbol so it survives duplicate copies.
|
|
9
10
|
*/
|
|
10
11
|
export declare const DURABLE_STEP_META: unique symbol;
|
|
11
|
-
/** Discovery metadata a decorated/`defineStep` handler carries: routing name + optional
|
|
12
|
+
/** Discovery metadata a decorated/`defineStep` handler carries: routing name + optional schemas. */
|
|
12
13
|
export interface DurableStepMeta {
|
|
13
14
|
/** The resolved routing name — derived (`Class.method`) or explicit, always present. */
|
|
14
15
|
name: string;
|
|
15
16
|
/** Opt-in runtime input schema, validated when the handler is served. Absent on a bare `@Step()`. */
|
|
16
|
-
input?:
|
|
17
|
+
input?: StandardSchemaV1 | undefined;
|
|
17
18
|
/** Opt-in runtime output schema, validated before the handler's result is handed back. */
|
|
18
|
-
output?:
|
|
19
|
+
output?: StandardSchemaV1 | undefined;
|
|
19
20
|
}
|
|
20
21
|
/** Options for the object call form of {@link Step} / {@link defineStep}. */
|
|
21
22
|
export interface StepDecoratorOptions {
|
|
22
23
|
/** Explicit routing name, overriding the derived `Class.method`. */
|
|
23
24
|
name?: string;
|
|
24
|
-
/** Runtime input schema
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
output
|
|
25
|
+
/** Runtime input schema — any Standard Schema (zod, valibot, arktype, …) — validated at the serve
|
|
26
|
+
* boundary (opt-in — a bare `@Step()` skips it). The handler receives the schema's OUTPUT value. */
|
|
27
|
+
input?: StandardSchemaV1;
|
|
28
|
+
/** Runtime output schema (any Standard Schema), validated before the result is returned (opt-in).
|
|
29
|
+
* The caller receives the schema's OUTPUT value. */
|
|
30
|
+
output?: StandardSchemaV1;
|
|
28
31
|
/** Def-level policy: max attempts before the step (and run) fails. Read by `ctx.step` via `stepConfigOf`. */
|
|
29
32
|
retries?: number;
|
|
30
33
|
/** How the delay between retries grows: `fixed` (constant) or `exp` (doubles each attempt). */
|
|
@@ -45,6 +48,8 @@ export interface StepDecoratorOptions {
|
|
|
45
48
|
* protocol-compatible the run parks `blocked` with a precise reason. Absent/empty = runs anywhere. */
|
|
46
49
|
requires?: string[];
|
|
47
50
|
}
|
|
51
|
+
/** {@link defineStep}'s options minus the schemas — the overloads add `input`/`output` typed. */
|
|
52
|
+
export type DefineStepOptions = Omit<StepDecoratorOptions, 'name' | 'input' | 'output'>;
|
|
48
53
|
/**
|
|
49
54
|
* Marks a class method as a durable **step handler**. A dispatched task is routed to it BY NAME —
|
|
50
55
|
* `ctx.step(this.svc.method, input)` reads that same name off the method reference (the shared
|
|
@@ -56,21 +61,42 @@ export interface StepDecoratorOptions {
|
|
|
56
61
|
* - `@Step()` — bare: the routing name is DERIVED as `` `${ClassName}.${method}` `` — refactor-safe.
|
|
57
62
|
* - `@Step('custom:name')` — explicit name override (a stable cross-runtime contract).
|
|
58
63
|
* - `@Step({ name?, input?, output?, retries?, backoff?, backoffMs?, backoffMaxMs?, jitter?,
|
|
59
|
-
* timeoutMs? })` — optional name override, opt-in RUNTIME
|
|
60
|
-
* boundary by step discovery
|
|
64
|
+
* timeoutMs? })` — optional name override, opt-in RUNTIME Standard Schemas (zod, valibot,
|
|
65
|
+
* arktype, … — validated at the serve boundary by step discovery; a failure is a non-retryable
|
|
66
|
+
* `SchemaValidationError`), and a def-level durable-retry/liveness policy `ctx.step` reads via
|
|
61
67
|
* `stepConfigOf` (a per-call `opts` overrides it field-by-field).
|
|
62
68
|
*/
|
|
63
69
|
export declare function Step(nameOrOptions?: string | StepDecoratorOptions): MethodDecorator;
|
|
64
70
|
/**
|
|
65
71
|
* Build a durable step handler WITHOUT a class/decorator: stamps `fn` with the routing `name` (and
|
|
66
|
-
* optional
|
|
72
|
+
* optional Standard Schemas + dispatch policy) so it works as a typed {@link StepRef} for
|
|
67
73
|
* `ctx.step(fn, input)` AND is discoverable/registerable by name. The cross-runtime baseline — pass
|
|
68
74
|
* the returned ref to `ctx.step`, or register it on a transport via `registerStep`.
|
|
69
75
|
*
|
|
70
76
|
* ```ts
|
|
71
77
|
* export const charge = defineStep('billing:charge', async (input: ChargeInput) => { ... })
|
|
72
78
|
* ```
|
|
79
|
+
*
|
|
80
|
+
* With an `input` / `output` Standard Schema the types are INFERRED from it: the handler receives
|
|
81
|
+
* the input schema's output type (parsed/coerced), and the returned ref takes the input schema's
|
|
82
|
+
* input type and resolves to the output schema's output type — no hand-written annotation needed.
|
|
83
|
+
*
|
|
84
|
+
* ```ts
|
|
85
|
+
* const charge = defineStep('billing:charge', async (input) => ({ id: `ch_${input.amount}` }), {
|
|
86
|
+
* input: v.object({ amount: v.number() }), // valibot, zod, arktype, …
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
73
89
|
*/
|
|
90
|
+
export declare function defineStep<SI extends StandardSchemaV1, SO extends StandardSchemaV1>(name: string, fn: (input: StandardSchemaV1.InferOutput<SI>, log: StepLogger) => StandardSchemaV1.InferInput<SO> | Promise<StandardSchemaV1.InferInput<SO>>, config: DefineStepOptions & {
|
|
91
|
+
input: SI;
|
|
92
|
+
output: SO;
|
|
93
|
+
}): StepRef<StandardSchemaV1.InferInput<SI>, StandardSchemaV1.InferOutput<SO>>;
|
|
94
|
+
export declare function defineStep<SI extends StandardSchemaV1, TOutput>(name: string, fn: (input: StandardSchemaV1.InferOutput<SI>, log: StepLogger) => TOutput | Promise<TOutput>, config: DefineStepOptions & {
|
|
95
|
+
input: SI;
|
|
96
|
+
}): StepRef<StandardSchemaV1.InferInput<SI>, TOutput>;
|
|
97
|
+
export declare function defineStep<TInput, SO extends StandardSchemaV1>(name: string, fn: (input: TInput, log: StepLogger) => StandardSchemaV1.InferInput<SO> | Promise<StandardSchemaV1.InferInput<SO>>, config: DefineStepOptions & {
|
|
98
|
+
output: SO;
|
|
99
|
+
}): StepRef<TInput, StandardSchemaV1.InferOutput<SO>>;
|
|
74
100
|
export declare function defineStep<TInput, TOutput>(name: string, fn: (input: TInput, log: StepLogger) => TOutput | Promise<TOutput>, config?: Omit<StepDecoratorOptions, 'name'>): StepRef<TInput, TOutput>;
|
|
75
101
|
/** Read the {@link DurableStepMeta} a `@Step`/`defineStep` stamped on a handler, or `undefined`. */
|
|
76
102
|
export declare function stepMetaOf(ref: unknown): DurableStepMeta | undefined;
|