@adonis-agora/durable 0.1.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/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/assets/dashboard.html +446 -0
- package/dist/commands/main.d.ts +15 -0
- package/dist/commands/main.d.ts.map +1 -0
- package/dist/commands/main.js +15 -0
- package/dist/commands/main.js.map +1 -0
- package/dist/commands/retry.d.ts +16 -0
- package/dist/commands/retry.d.ts.map +1 -0
- package/dist/commands/retry.js +34 -0
- package/dist/commands/retry.js.map +1 -0
- package/dist/commands/runs.d.ts +17 -0
- package/dist/commands/runs.d.ts.map +1 -0
- package/dist/commands/runs.js +40 -0
- package/dist/commands/runs.js.map +1 -0
- package/dist/commands/work.d.ts +18 -0
- package/dist/commands/work.d.ts.map +1 -0
- package/dist/commands/work.js +58 -0
- package/dist/commands/work.js.map +1 -0
- package/dist/configure.d.ts +15 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +26 -0
- package/dist/configure.js.map +1 -0
- package/dist/providers/dashboard_provider.d.ts +27 -0
- package/dist/providers/dashboard_provider.d.ts.map +1 -0
- package/dist/providers/dashboard_provider.js +94 -0
- package/dist/providers/dashboard_provider.js.map +1 -0
- package/dist/providers/durable_provider.d.ts +36 -0
- package/dist/providers/durable_provider.d.ts.map +1 -0
- package/dist/providers/durable_provider.js +113 -0
- package/dist/providers/durable_provider.js.map +1 -0
- package/dist/src/admission-redis/index.d.ts +2 -0
- package/dist/src/admission-redis/index.d.ts.map +1 -0
- package/dist/src/admission-redis/index.js +2 -0
- package/dist/src/admission-redis/index.js.map +1 -0
- package/dist/src/admission-redis/redis-admission-backend.d.ts +83 -0
- package/dist/src/admission-redis/redis-admission-backend.d.ts.map +1 -0
- package/dist/src/admission-redis/redis-admission-backend.js +200 -0
- package/dist/src/admission-redis/redis-admission-backend.js.map +1 -0
- package/dist/src/admission.d.ts +49 -0
- package/dist/src/admission.d.ts.map +1 -0
- package/dist/src/admission.js +30 -0
- package/dist/src/admission.js.map +1 -0
- package/dist/src/backoff.d.ts +5 -0
- package/dist/src/backoff.d.ts.map +1 -0
- package/dist/src/backoff.js +11 -0
- package/dist/src/backoff.js.map +1 -0
- package/dist/src/checkpoints.d.ts +42 -0
- package/dist/src/checkpoints.d.ts.map +1 -0
- package/dist/src/checkpoints.js +57 -0
- package/dist/src/checkpoints.js.map +1 -0
- package/dist/src/codec-state-store.d.ts +60 -0
- package/dist/src/codec-state-store.d.ts.map +1 -0
- package/dist/src/codec-state-store.js +129 -0
- package/dist/src/codec-state-store.js.map +1 -0
- package/dist/src/commands/index.d.ts +3 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +3 -0
- package/dist/src/commands/index.js.map +1 -0
- package/dist/src/commands/runs.d.ts +24 -0
- package/dist/src/commands/runs.d.ts.map +1 -0
- package/dist/src/commands/runs.js +39 -0
- package/dist/src/commands/runs.js.map +1 -0
- package/dist/src/commands/worker.d.ts +61 -0
- package/dist/src/commands/worker.d.ts.map +1 -0
- package/dist/src/commands/worker.js +74 -0
- package/dist/src/commands/worker.js.map +1 -0
- package/dist/src/completion.d.ts +15 -0
- package/dist/src/completion.d.ts.map +1 -0
- package/dist/src/completion.js +10 -0
- package/dist/src/completion.js.map +1 -0
- package/dist/src/dashboard/define_config.d.ts +48 -0
- package/dist/src/dashboard/define_config.d.ts.map +1 -0
- package/dist/src/dashboard/define_config.js +57 -0
- package/dist/src/dashboard/define_config.js.map +1 -0
- package/dist/src/dashboard/handlers.d.ts +47 -0
- package/dist/src/dashboard/handlers.d.ts.map +1 -0
- package/dist/src/dashboard/handlers.js +163 -0
- package/dist/src/dashboard/handlers.js.map +1 -0
- package/dist/src/dashboard/html.d.ts +7 -0
- package/dist/src/dashboard/html.d.ts.map +1 -0
- package/dist/src/dashboard/html.js +24 -0
- package/dist/src/dashboard/html.js.map +1 -0
- package/dist/src/dashboard/index.d.ts +8 -0
- package/dist/src/dashboard/index.d.ts.map +1 -0
- package/dist/src/dashboard/index.js +6 -0
- package/dist/src/dashboard/index.js.map +1 -0
- package/dist/src/define_config.d.ts +72 -0
- package/dist/src/define_config.d.ts.map +1 -0
- package/dist/src/define_config.js +8 -0
- package/dist/src/define_config.js.map +1 -0
- package/dist/src/diagnostics-bridge.d.ts +22 -0
- package/dist/src/diagnostics-bridge.d.ts.map +1 -0
- package/dist/src/diagnostics-bridge.js +25 -0
- package/dist/src/diagnostics-bridge.js.map +1 -0
- package/dist/src/duration.d.ts +6 -0
- package/dist/src/duration.d.ts.map +1 -0
- package/dist/src/duration.js +39 -0
- package/dist/src/duration.js.map +1 -0
- package/dist/src/engine.d.ts +583 -0
- package/dist/src/engine.d.ts.map +1 -0
- package/dist/src/engine.js +1894 -0
- package/dist/src/engine.js.map +1 -0
- package/dist/src/entities.d.ts +44 -0
- package/dist/src/entities.d.ts.map +1 -0
- package/dist/src/entities.js +64 -0
- package/dist/src/entities.js.map +1 -0
- package/dist/src/errors.d.ts +68 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +102 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/event-accumulators.d.ts +39 -0
- package/dist/src/event-accumulators.d.ts.map +1 -0
- package/dist/src/event-accumulators.js +70 -0
- package/dist/src/event-accumulators.js.map +1 -0
- package/dist/src/events.d.ts +9 -0
- package/dist/src/events.d.ts.map +1 -0
- package/dist/src/events.js +35 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/index.d.ts +36 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +37 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interfaces.d.ts +909 -0
- package/dist/src/interfaces.d.ts.map +1 -0
- package/dist/src/interfaces.js +2 -0
- package/dist/src/interfaces.js.map +1 -0
- package/dist/src/metrics.d.ts +44 -0
- package/dist/src/metrics.d.ts.map +1 -0
- package/dist/src/metrics.js +78 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/otel/durable-metrics.d.ts +42 -0
- package/dist/src/otel/durable-metrics.d.ts.map +1 -0
- package/dist/src/otel/durable-metrics.js +75 -0
- package/dist/src/otel/durable-metrics.js.map +1 -0
- package/dist/src/otel/durable-otel.d.ts +20 -0
- package/dist/src/otel/durable-otel.d.ts.map +1 -0
- package/dist/src/otel/durable-otel.js +74 -0
- package/dist/src/otel/durable-otel.js.map +1 -0
- package/dist/src/otel/index.d.ts +4 -0
- package/dist/src/otel/index.d.ts.map +1 -0
- package/dist/src/otel/index.js +4 -0
- package/dist/src/otel/index.js.map +1 -0
- package/dist/src/otel/traceparent.d.ts +17 -0
- package/dist/src/otel/traceparent.d.ts.map +1 -0
- package/dist/src/otel/traceparent.js +21 -0
- package/dist/src/otel/traceparent.js.map +1 -0
- package/dist/src/pollers.d.ts +33 -0
- package/dist/src/pollers.d.ts.map +1 -0
- package/dist/src/pollers.js +76 -0
- package/dist/src/pollers.js.map +1 -0
- package/dist/src/protocol.d.ts +17 -0
- package/dist/src/protocol.d.ts.map +1 -0
- package/dist/src/protocol.js +47 -0
- package/dist/src/protocol.js.map +1 -0
- package/dist/src/queue.d.ts +113 -0
- package/dist/src/queue.d.ts.map +1 -0
- package/dist/src/queue.js +128 -0
- package/dist/src/queue.js.map +1 -0
- package/dist/src/remote-step-factory.d.ts +15 -0
- package/dist/src/remote-step-factory.d.ts.map +1 -0
- package/dist/src/remote-step-factory.js +12 -0
- package/dist/src/remote-step-factory.js.map +1 -0
- package/dist/src/remote-workflow-executor.d.ts +24 -0
- package/dist/src/remote-workflow-executor.d.ts.map +1 -0
- package/dist/src/remote-workflow-executor.js +70 -0
- package/dist/src/remote-workflow-executor.js.map +1 -0
- package/dist/src/scheduler.d.ts +67 -0
- package/dist/src/scheduler.d.ts.map +1 -0
- package/dist/src/scheduler.js +111 -0
- package/dist/src/scheduler.js.map +1 -0
- package/dist/src/search-attributes.d.ts +48 -0
- package/dist/src/search-attributes.d.ts.map +1 -0
- package/dist/src/search-attributes.js +98 -0
- package/dist/src/search-attributes.js.map +1 -0
- package/dist/src/singleton-gate.d.ts +44 -0
- package/dist/src/singleton-gate.d.ts.map +1 -0
- package/dist/src/singleton-gate.js +90 -0
- package/dist/src/singleton-gate.js.map +1 -0
- package/dist/src/step-logger.d.ts +9 -0
- package/dist/src/step-logger.d.ts.map +1 -0
- package/dist/src/step-logger.js +89 -0
- package/dist/src/step-logger.js.map +1 -0
- package/dist/src/stores/factory.d.ts +42 -0
- package/dist/src/stores/factory.d.ts.map +1 -0
- package/dist/src/stores/factory.js +29 -0
- package/dist/src/stores/factory.js.map +1 -0
- package/dist/src/stores/lucid-helpers.d.ts +11 -0
- package/dist/src/stores/lucid-helpers.d.ts.map +1 -0
- package/dist/src/stores/lucid-helpers.js +38 -0
- package/dist/src/stores/lucid-helpers.js.map +1 -0
- package/dist/src/stores/lucid-mappers.d.ts +58 -0
- package/dist/src/stores/lucid-mappers.d.ts.map +1 -0
- package/dist/src/stores/lucid-mappers.js +174 -0
- package/dist/src/stores/lucid-mappers.js.map +1 -0
- package/dist/src/stores/lucid-schema.d.ts +28 -0
- package/dist/src/stores/lucid-schema.d.ts.map +1 -0
- package/dist/src/stores/lucid-schema.js +115 -0
- package/dist/src/stores/lucid-schema.js.map +1 -0
- package/dist/src/stores/lucid.d.ts +69 -0
- package/dist/src/stores/lucid.d.ts.map +1 -0
- package/dist/src/stores/lucid.js +342 -0
- package/dist/src/stores/lucid.js.map +1 -0
- package/dist/src/telescope/dashboard.d.ts +15 -0
- package/dist/src/telescope/dashboard.d.ts.map +1 -0
- package/dist/src/telescope/dashboard.js +113 -0
- package/dist/src/telescope/dashboard.js.map +1 -0
- package/dist/src/telescope/data-providers.d.ts +20 -0
- package/dist/src/telescope/data-providers.d.ts.map +1 -0
- package/dist/src/telescope/data-providers.js +322 -0
- package/dist/src/telescope/data-providers.js.map +1 -0
- package/dist/src/telescope/extension.d.ts +22 -0
- package/dist/src/telescope/extension.d.ts.map +1 -0
- package/dist/src/telescope/extension.js +38 -0
- package/dist/src/telescope/extension.js.map +1 -0
- package/dist/src/telescope/index.d.ts +5 -0
- package/dist/src/telescope/index.d.ts.map +1 -0
- package/dist/src/telescope/index.js +4 -0
- package/dist/src/telescope/index.js.map +1 -0
- package/dist/src/telescope/telescope-sdk.d.ts +123 -0
- package/dist/src/telescope/telescope-sdk.d.ts.map +1 -0
- package/dist/src/telescope/telescope-sdk.js +12 -0
- package/dist/src/telescope/telescope-sdk.js.map +1 -0
- package/dist/src/test-helpers.d.ts +11 -0
- package/dist/src/test-helpers.d.ts.map +1 -0
- package/dist/src/test-helpers.js +12 -0
- package/dist/src/test-helpers.js.map +1 -0
- package/dist/src/testing/in-memory-state-store.d.ts +64 -0
- package/dist/src/testing/in-memory-state-store.d.ts.map +1 -0
- package/dist/src/testing/in-memory-state-store.js +259 -0
- package/dist/src/testing/in-memory-state-store.js.map +1 -0
- package/dist/src/testing/in-memory-transport.d.ts +25 -0
- package/dist/src/testing/in-memory-transport.d.ts.map +1 -0
- package/dist/src/testing/in-memory-transport.js +49 -0
- package/dist/src/testing/in-memory-transport.js.map +1 -0
- package/dist/src/testing-kit/admission-backend-conformance.d.ts +18 -0
- package/dist/src/testing-kit/admission-backend-conformance.d.ts.map +1 -0
- package/dist/src/testing-kit/admission-backend-conformance.js +81 -0
- package/dist/src/testing-kit/admission-backend-conformance.js.map +1 -0
- package/dist/src/testing-kit/assertions.d.ts +10 -0
- package/dist/src/testing-kit/assertions.d.ts.map +1 -0
- package/dist/src/testing-kit/assertions.js +41 -0
- package/dist/src/testing-kit/assertions.js.map +1 -0
- package/dist/src/testing-kit/harness.d.ts +28 -0
- package/dist/src/testing-kit/harness.d.ts.map +1 -0
- package/dist/src/testing-kit/harness.js +42 -0
- package/dist/src/testing-kit/harness.js.map +1 -0
- package/dist/src/testing-kit/index.d.ts +8 -0
- package/dist/src/testing-kit/index.d.ts.map +1 -0
- package/dist/src/testing-kit/index.js +8 -0
- package/dist/src/testing-kit/index.js.map +1 -0
- package/dist/src/testing-kit/replay.d.ts +22 -0
- package/dist/src/testing-kit/replay.d.ts.map +1 -0
- package/dist/src/testing-kit/replay.js +38 -0
- package/dist/src/testing-kit/replay.js.map +1 -0
- package/dist/src/testing-kit/state-store-conformance.d.ts +51 -0
- package/dist/src/testing-kit/state-store-conformance.d.ts.map +1 -0
- package/dist/src/testing-kit/state-store-conformance.js +430 -0
- package/dist/src/testing-kit/state-store-conformance.js.map +1 -0
- package/dist/src/testing-kit/steps.d.ts +5 -0
- package/dist/src/testing-kit/steps.d.ts.map +1 -0
- package/dist/src/testing-kit/steps.js +15 -0
- package/dist/src/testing-kit/steps.js.map +1 -0
- package/dist/src/testing-kit/transport-conformance.d.ts +16 -0
- package/dist/src/testing-kit/transport-conformance.d.ts.map +1 -0
- package/dist/src/testing-kit/transport-conformance.js +64 -0
- package/dist/src/testing-kit/transport-conformance.js.map +1 -0
- package/dist/src/tokens.d.ts +18 -0
- package/dist/src/tokens.d.ts.map +1 -0
- package/dist/src/tokens.js +18 -0
- package/dist/src/tokens.js.map +1 -0
- package/dist/src/transport-pool.d.ts +30 -0
- package/dist/src/transport-pool.d.ts.map +1 -0
- package/dist/src/transport-pool.js +82 -0
- package/dist/src/transport-pool.js.map +1 -0
- package/dist/src/transports/db-helpers.d.ts +10 -0
- package/dist/src/transports/db-helpers.d.ts.map +1 -0
- package/dist/src/transports/db-helpers.js +33 -0
- package/dist/src/transports/db-helpers.js.map +1 -0
- package/dist/src/transports/db-schema.d.ts +28 -0
- package/dist/src/transports/db-schema.d.ts.map +1 -0
- package/dist/src/transports/db-schema.js +98 -0
- package/dist/src/transports/db-schema.js.map +1 -0
- package/dist/src/transports/db.d.ts +81 -0
- package/dist/src/transports/db.d.ts.map +1 -0
- package/dist/src/transports/db.js +340 -0
- package/dist/src/transports/db.js.map +1 -0
- package/dist/src/transports/factory.d.ts +79 -0
- package/dist/src/transports/factory.d.ts.map +1 -0
- package/dist/src/transports/factory.js +57 -0
- package/dist/src/transports/factory.js.map +1 -0
- package/dist/src/transports/queue-mock-adapter.d.ts +39 -0
- package/dist/src/transports/queue-mock-adapter.d.ts.map +1 -0
- package/dist/src/transports/queue-mock-adapter.js +86 -0
- package/dist/src/transports/queue-mock-adapter.js.map +1 -0
- package/dist/src/transports/queue.d.ts +84 -0
- package/dist/src/transports/queue.d.ts.map +1 -0
- package/dist/src/transports/queue.js +210 -0
- package/dist/src/transports/queue.js.map +1 -0
- package/dist/src/workflow-ctx.d.ts +64 -0
- package/dist/src/workflow-ctx.d.ts.map +1 -0
- package/dist/src/workflow-ctx.js +457 -0
- package/dist/src/workflow-ctx.js.map +1 -0
- package/dist/src/workflow-ref.d.ts +34 -0
- package/dist/src/workflow-ref.d.ts.map +1 -0
- package/dist/src/workflow-ref.js +28 -0
- package/dist/src/workflow-ref.js.map +1 -0
- package/dist/stubs/config/durable.stub +49 -0
- package/dist/stubs/config/durable_dashboard.stub +17 -0
- package/dist/stubs/database/migrations/create_durable_tables.stub +87 -0
- package/dist/stubs/database/migrations/create_durable_transport_tables.stub +75 -0
- package/dist/stubs/main.d.ts +3 -0
- package/dist/stubs/main.d.ts.map +1 -0
- package/dist/stubs/main.js +4 -0
- package/dist/stubs/main.js.map +1 -0
- package/package.json +154 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type TickOptions, type TickResult, type WorkerLogger, type WorkerLoopOptions, runTick, runWorkerLoop, } from './worker.js';
|
|
2
|
+
export { type ListRunsOptions, type RunLister, listRuns, renderRunsTable, retryRun, } from './runs.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,OAAO,EACP,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,QAAQ,EACR,eAAe,EACf,QAAQ,GACT,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,OAAO,EACP,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,QAAQ,EACR,eAAe,EACf,QAAQ,GACT,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RunQuery, RunResult, RunStatus, WorkflowEngine, WorkflowRun } from '../index.js';
|
|
2
|
+
export interface ListRunsOptions {
|
|
3
|
+
/** Filter by run status (pending | running | suspended | completed | failed | cancelled | dead). */
|
|
4
|
+
status?: RunStatus | undefined;
|
|
5
|
+
/** Filter by workflow name. */
|
|
6
|
+
workflow?: string | undefined;
|
|
7
|
+
/** Max rows. Default 50. */
|
|
8
|
+
limit?: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
/** Anything that can list runs — both a {@link WorkflowEngine} and a raw `StateStore` satisfy it. */
|
|
11
|
+
export interface RunLister {
|
|
12
|
+
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
13
|
+
}
|
|
14
|
+
/** Query recent runs, newest activity first (the source returns its own order). */
|
|
15
|
+
export declare function listRuns(source: RunLister, opts: ListRunsOptions): Promise<WorkflowRun[]>;
|
|
16
|
+
/** Render a runs list as a plain-text table for the terminal. */
|
|
17
|
+
export declare function renderRunsTable(runs: WorkflowRun[]): string;
|
|
18
|
+
/**
|
|
19
|
+
* Retry a run: re-enqueue it for a worker to (re-)execute via the engine's `requeue` (the
|
|
20
|
+
* dispatch-model retry — sets it back to `pending`, clears any stale lease, replays its checkpoints).
|
|
21
|
+
* Returns the enqueued result, or null if the run is unknown.
|
|
22
|
+
*/
|
|
23
|
+
export declare function retryRun(engine: WorkflowEngine, runId: string): Promise<RunResult | null>;
|
|
24
|
+
//# sourceMappingURL=runs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../../src/commands/runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/F,MAAM,WAAW,eAAe;IAC9B,oGAAoG;IACpG,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,qGAAqG;AACrG,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CACnD;AAED,mFAAmF;AACnF,wBAAsB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAM/F;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAI3D;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAE/F"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Query recent runs, newest activity first (the source returns its own order). */
|
|
2
|
+
export async function listRuns(source, opts) {
|
|
3
|
+
return source.listRuns({
|
|
4
|
+
...(opts.status ? { status: opts.status } : {}),
|
|
5
|
+
...(opts.workflow ? { workflow: opts.workflow } : {}),
|
|
6
|
+
limit: opts.limit ?? 50,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
/** Render a runs list as a plain-text table for the terminal. */
|
|
10
|
+
export function renderRunsTable(runs) {
|
|
11
|
+
if (runs.length === 0)
|
|
12
|
+
return 'No runs.';
|
|
13
|
+
const rows = runs.map((r) => [r.id, r.workflow, r.status, relTime(r.updatedAt)]);
|
|
14
|
+
return table(['RUN', 'WORKFLOW', 'STATUS', 'UPDATED'], rows);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Retry a run: re-enqueue it for a worker to (re-)execute via the engine's `requeue` (the
|
|
18
|
+
* dispatch-model retry — sets it back to `pending`, clears any stale lease, replays its checkpoints).
|
|
19
|
+
* Returns the enqueued result, or null if the run is unknown.
|
|
20
|
+
*/
|
|
21
|
+
export async function retryRun(engine, runId) {
|
|
22
|
+
return engine.requeue(runId);
|
|
23
|
+
}
|
|
24
|
+
function table(headers, rows) {
|
|
25
|
+
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));
|
|
26
|
+
const fmt = (cells) => cells.map((c, i) => c.padEnd(widths[i] ?? 0)).join(' ');
|
|
27
|
+
return [fmt(headers), ...rows.map(fmt)].join('\n');
|
|
28
|
+
}
|
|
29
|
+
function relTime(date) {
|
|
30
|
+
const s = Math.round((Date.now() - date.getTime()) / 1000);
|
|
31
|
+
if (s < 60)
|
|
32
|
+
return `${s}s ago`;
|
|
33
|
+
if (s < 3600)
|
|
34
|
+
return `${Math.round(s / 60)}m ago`;
|
|
35
|
+
if (s < 86_400)
|
|
36
|
+
return `${Math.round(s / 3600)}h ago`;
|
|
37
|
+
return `${Math.round(s / 86_400)}d ago`;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=runs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../../src/commands/runs.ts"],"names":[],"mappings":"AAgBA,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAiB,EAAE,IAAqB;IACrE,OAAO,MAAM,CAAC,QAAQ,CAAC;QACrB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;KACxB,CAAC,CAAC;AACL,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,eAAe,CAAC,IAAmB;IACjD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACjF,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAsB,EAAE,KAAa;IAClE,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,KAAK,CAAC,OAAiB,EAAE,IAAgB;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClG,MAAM,GAAG,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,OAAO,CAAC,IAAU;IACzB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3D,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;IAClD,IAAI,CAAC,GAAG,MAAM;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IACtD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { WorkflowEngine } from '../index.js';
|
|
2
|
+
import { type ScheduledWorkflow } from '../scheduler.js';
|
|
3
|
+
/** A minimal logger the worker loop writes progress to (the ace command's `this.logger` fits). */
|
|
4
|
+
export interface WorkerLogger {
|
|
5
|
+
info(message: string): void;
|
|
6
|
+
error(message: string): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Run one tick of the worker poll loop against the engine: pick up enqueued runs, recover runs left
|
|
10
|
+
* incomplete by a crash, resume runs whose durable timers are due, cancel runs past their execution
|
|
11
|
+
* timeout, and finally fire any due `schedules` (the 5th phase — see {@link TickOptions.schedules}).
|
|
12
|
+
* Returns a per-phase count of the runs each phase touched — the unit the `durable:work` command logs
|
|
13
|
+
* and the tests assert on. Each phase is awaited independently so one phase throwing does not abort the
|
|
14
|
+
* rest of the tick (the error is collected and surfaced).
|
|
15
|
+
*/
|
|
16
|
+
export interface TickResult {
|
|
17
|
+
pending: number;
|
|
18
|
+
recovered: number;
|
|
19
|
+
timers: number;
|
|
20
|
+
/** Run ids the schedules phase started this tick (due windows fired). */
|
|
21
|
+
scheduled: number;
|
|
22
|
+
/** Phase errors caught during the tick (e.g. a transient store hiccup), keyed by phase name. */
|
|
23
|
+
errors: {
|
|
24
|
+
phase: string;
|
|
25
|
+
error: Error;
|
|
26
|
+
}[];
|
|
27
|
+
}
|
|
28
|
+
/** Per-tick inputs beyond the engine. */
|
|
29
|
+
export interface TickOptions {
|
|
30
|
+
/** Logical "now" (epoch ms) for the tick — passed to each phase. Defaults to the real clock. */
|
|
31
|
+
now?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Recurring schedules fired after timeouts are swept (the 5th phase). `engine.start` is idempotent
|
|
34
|
+
* by each schedule's time-bucket run id, so racing workers start every window exactly once. Empty
|
|
35
|
+
* or undefined skips the phase entirely.
|
|
36
|
+
*/
|
|
37
|
+
schedules?: readonly ScheduledWorkflow[];
|
|
38
|
+
}
|
|
39
|
+
/** Execute a single poll-loop tick. See {@link TickResult}. Never throws — phase errors are collected. */
|
|
40
|
+
export declare function runTick(engine: WorkflowEngine, options?: TickOptions): Promise<TickResult>;
|
|
41
|
+
/** Options for {@link runWorkerLoop}. */
|
|
42
|
+
export interface WorkerLoopOptions {
|
|
43
|
+
/** Poll interval in ms between ticks. */
|
|
44
|
+
intervalMs: number;
|
|
45
|
+
/** Resolves/rejects to stop the loop gracefully (wired to SIGINT/SIGTERM by the command). */
|
|
46
|
+
stopSignal: Promise<void>;
|
|
47
|
+
logger: WorkerLogger;
|
|
48
|
+
/** Drain timeout passed to `engine.drain` on shutdown. Default 10s. */
|
|
49
|
+
drainTimeoutMs?: number;
|
|
50
|
+
/** Injectable sleep, for tests. Default a real timer that resolves after `ms`. */
|
|
51
|
+
sleep?: (ms: number) => Promise<void>;
|
|
52
|
+
/** Recurring schedules to fire each tick (the 5th phase). See {@link TickOptions.schedules}. */
|
|
53
|
+
schedules?: readonly ScheduledWorkflow[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The long-running worker loop: tick, then wait `intervalMs` (or until `stopSignal` resolves),
|
|
57
|
+
* repeat. On stop it drains in-flight executions so a deploy hands off cleanly. Returns the number of
|
|
58
|
+
* ticks executed — testable by resolving `stopSignal` after N ticks with an injected `sleep`.
|
|
59
|
+
*/
|
|
60
|
+
export declare function runWorkerLoop(engine: WorkflowEngine, options: WorkerLoopOptions): Promise<number>;
|
|
61
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/commands/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,KAAK,iBAAiB,EAAgB,MAAM,iBAAiB,CAAC;AAEvE,kGAAkG;AAClG,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,EAAE,CAAC;CAC3C;AAED,yCAAyC;AACzC,MAAM,WAAW,WAAW;IAC1B,gGAAgG;IAChG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC1C;AAID,0GAA0G;AAC1G,wBAAsB,OAAO,CAC3B,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAkCrB;AAMD,yCAAyC;AACzC,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,gGAAgG;IAChG,SAAS,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC1C;AAQD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,MAAM,CAAC,CA2BjB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { runSchedules } from '../scheduler.js';
|
|
2
|
+
const settledCount = (results) => results.length;
|
|
3
|
+
/** Execute a single poll-loop tick. See {@link TickResult}. Never throws — phase errors are collected. */
|
|
4
|
+
export async function runTick(engine, options = {}) {
|
|
5
|
+
const now = options.now;
|
|
6
|
+
const schedules = options.schedules;
|
|
7
|
+
const result = { pending: 0, recovered: 0, timers: 0, scheduled: 0, errors: [] };
|
|
8
|
+
const phase = async (name, fn) => {
|
|
9
|
+
try {
|
|
10
|
+
return await fn();
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
result.errors.push({ phase: name, error: toError(error) });
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
result.pending = await phase('runPending', async () => settledCount(await engine.runPending(now)));
|
|
18
|
+
result.recovered = await phase('recoverIncomplete', async () => settledCount(await engine.recoverIncomplete(now)));
|
|
19
|
+
result.timers = await phase('resumeDueTimers', async () => settledCount(await engine.resumeDueTimers(now)));
|
|
20
|
+
await phase('sweepTimeouts', async () => {
|
|
21
|
+
await engine.sweepTimeouts(now);
|
|
22
|
+
return 0;
|
|
23
|
+
});
|
|
24
|
+
// 5th phase — fire any due recurring schedules (mirrors the NestJS timer poller). Skipped entirely
|
|
25
|
+
// when none are registered; idempotent by the schedule's time-bucket run id, so racing workers
|
|
26
|
+
// start each window exactly once.
|
|
27
|
+
result.scheduled = await phase('runSchedules', async () => {
|
|
28
|
+
if (!schedules || schedules.length === 0)
|
|
29
|
+
return 0;
|
|
30
|
+
const ids = await runSchedules(engine, schedules, now ?? Date.now());
|
|
31
|
+
return ids.length;
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function toError(value) {
|
|
36
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
37
|
+
}
|
|
38
|
+
const realSleep = (ms) => new Promise((resolve) => {
|
|
39
|
+
const t = setTimeout(resolve, ms);
|
|
40
|
+
t.unref?.();
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* The long-running worker loop: tick, then wait `intervalMs` (or until `stopSignal` resolves),
|
|
44
|
+
* repeat. On stop it drains in-flight executions so a deploy hands off cleanly. Returns the number of
|
|
45
|
+
* ticks executed — testable by resolving `stopSignal` after N ticks with an injected `sleep`.
|
|
46
|
+
*/
|
|
47
|
+
export async function runWorkerLoop(engine, options) {
|
|
48
|
+
const sleep = options.sleep ?? realSleep;
|
|
49
|
+
let stopped = false;
|
|
50
|
+
void options.stopSignal.then(() => {
|
|
51
|
+
stopped = true;
|
|
52
|
+
});
|
|
53
|
+
let ticks = 0;
|
|
54
|
+
while (!stopped) {
|
|
55
|
+
const result = await runTick(engine, options.schedules ? { schedules: options.schedules } : {});
|
|
56
|
+
ticks += 1;
|
|
57
|
+
const touched = result.pending + result.recovered + result.timers + result.scheduled;
|
|
58
|
+
if (touched > 0) {
|
|
59
|
+
options.logger.info(`tick: ${result.pending} pending, ${result.recovered} recovered, ${result.timers} timers, ${result.scheduled} scheduled`);
|
|
60
|
+
}
|
|
61
|
+
for (const { phase, error } of result.errors) {
|
|
62
|
+
options.logger.error(`tick phase ${phase} failed: ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
if (stopped)
|
|
65
|
+
break;
|
|
66
|
+
// Race the interval against the stop signal so shutdown is prompt, not interval-latent.
|
|
67
|
+
await Promise.race([sleep(options.intervalMs), options.stopSignal.catch(() => undefined)]);
|
|
68
|
+
}
|
|
69
|
+
options.logger.info(`draining (timeout ${options.drainTimeoutMs ?? 10_000}ms)…`);
|
|
70
|
+
await engine.drain(options.drainTimeoutMs);
|
|
71
|
+
options.logger.info(`worker stopped after ${ticks} ticks`);
|
|
72
|
+
return ticks;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/commands/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The payload an external `ctx.task` / child run delivers back on its completion signal: either a
|
|
3
|
+
* value or a failure. One typed envelope so `task` and `child` share the same unwrap (instead of
|
|
4
|
+
* sniffing ad-hoc `__error` keys).
|
|
5
|
+
*/
|
|
6
|
+
export type Completion<T> = {
|
|
7
|
+
ok: true;
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
error: string;
|
|
12
|
+
};
|
|
13
|
+
/** Read a `Completion` from a signal payload: return the value, or throw a FatalError if it failed. */
|
|
14
|
+
export declare function unwrapCompletion<T>(payload: unknown, label: string): T;
|
|
15
|
+
//# sourceMappingURL=completion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/completion.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElF,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAMtE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FatalError } from './errors.js';
|
|
2
|
+
/** Read a `Completion` from a signal payload: return the value, or throw a FatalError if it failed. */
|
|
3
|
+
export function unwrapCompletion(payload, label) {
|
|
4
|
+
const c = payload;
|
|
5
|
+
if (c && typeof c === 'object' && 'ok' in c && c.ok === false) {
|
|
6
|
+
throw new FatalError(`${label} failed: ${c.error}`);
|
|
7
|
+
}
|
|
8
|
+
return c?.value;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.js","sourceRoot":"","sources":["../../src/completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC,uGAAuG;AACvG,MAAM,UAAU,gBAAgB,CAAI,OAAgB,EAAE,KAAa;IACjE,MAAM,CAAC,GAAG,OAA+B,CAAC;IAC1C,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC9D,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,OAAQ,CAAyB,EAAE,KAAU,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
/**
|
|
3
|
+
* Authorization guard for the dashboard. Runs before every dashboard route
|
|
4
|
+
* (API + HTML). Return `true` to allow the request, `false` to deny it (the
|
|
5
|
+
* provider replies `403`). May be async (e.g. an auth lookup).
|
|
6
|
+
*
|
|
7
|
+
* It receives the AdonisJS {@link HttpContext}, so it can read the session,
|
|
8
|
+
* a bearer token, an IP allow-list, etc.
|
|
9
|
+
*/
|
|
10
|
+
export type AuthorizeHook = (ctx: HttpContext) => boolean | Promise<boolean>;
|
|
11
|
+
/** Shape of `config/durable_dashboard.ts`. */
|
|
12
|
+
export interface DurableDashboardConfig {
|
|
13
|
+
/**
|
|
14
|
+
* Master switch. When `false`, the provider registers no routes at all — the
|
|
15
|
+
* dashboard is completely absent. Defaults to `true`.
|
|
16
|
+
*/
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* URL prefix the dashboard + its API mount under. Defaults to `/durable`.
|
|
20
|
+
* The HTML is served at the prefix root; the JSON API lives under
|
|
21
|
+
* `<path>/api`.
|
|
22
|
+
*/
|
|
23
|
+
path?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Per-request authorization guard. Defaults to {@link defaultAuthorize}:
|
|
26
|
+
* allow everything OUTSIDE production, and in production require a bearer
|
|
27
|
+
* token matching the `DURABLE_DASHBOARD_TOKEN` env var (deny if it is unset).
|
|
28
|
+
*/
|
|
29
|
+
authorize?: AuthorizeHook;
|
|
30
|
+
}
|
|
31
|
+
/** A fully-resolved config — every field present (defaults applied). */
|
|
32
|
+
export interface ResolvedDurableDashboardConfig {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
path: string;
|
|
35
|
+
authorize: AuthorizeHook;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The default guard: open outside production; in production it requires a
|
|
39
|
+
* bearer token equal to `DURABLE_DASHBOARD_TOKEN`. If that env var is unset in
|
|
40
|
+
* production the dashboard is denied entirely (fail-closed) — you must opt in
|
|
41
|
+
* by setting a token or supplying your own {@link AuthorizeHook}.
|
|
42
|
+
*/
|
|
43
|
+
export declare function defaultAuthorize(ctx: HttpContext): boolean;
|
|
44
|
+
/** Apply defaults to a partial config, producing a fully-resolved one. */
|
|
45
|
+
export declare function resolveConfig(config?: DurableDashboardConfig): ResolvedDurableDashboardConfig;
|
|
46
|
+
/** Identity helper giving `config/durable_dashboard.ts` full type-checking. */
|
|
47
|
+
export declare function defineConfig(config?: DurableDashboardConfig): DurableDashboardConfig;
|
|
48
|
+
//# sourceMappingURL=define_config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../../src/dashboard/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7E,8CAA8C;AAC9C,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AAED,wEAAwE;AACxE,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,aAAa,CAAC;CAC1B;AA4BD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAK1D;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,MAAM,GAAE,sBAA2B,GAAG,8BAA8B,CASjG;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,MAAM,GAAE,sBAA2B,GAAG,sBAAsB,CAExF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the process is running in production. Mirrors how AdonisJS reads the
|
|
3
|
+
* environment without taking a hard dependency on its env service.
|
|
4
|
+
*/
|
|
5
|
+
function isProduction() {
|
|
6
|
+
return (process.env.NODE_ENV ?? '').toLowerCase() === 'production';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Extract a bearer token from an `Authorization: Bearer <token>` header, a
|
|
10
|
+
* `token` query-string param, or an `x-durable-token` header — whichever is
|
|
11
|
+
* present. Returns `undefined` when none is supplied.
|
|
12
|
+
*/
|
|
13
|
+
function readToken(ctx) {
|
|
14
|
+
const header = ctx.request.header('authorization');
|
|
15
|
+
if (header) {
|
|
16
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
17
|
+
if (match?.[1])
|
|
18
|
+
return match[1].trim();
|
|
19
|
+
}
|
|
20
|
+
const xHeader = ctx.request.header('x-durable-token');
|
|
21
|
+
if (xHeader)
|
|
22
|
+
return xHeader.trim();
|
|
23
|
+
const qs = ctx.request.qs().token;
|
|
24
|
+
if (typeof qs === 'string' && qs.length > 0)
|
|
25
|
+
return qs;
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The default guard: open outside production; in production it requires a
|
|
30
|
+
* bearer token equal to `DURABLE_DASHBOARD_TOKEN`. If that env var is unset in
|
|
31
|
+
* production the dashboard is denied entirely (fail-closed) — you must opt in
|
|
32
|
+
* by setting a token or supplying your own {@link AuthorizeHook}.
|
|
33
|
+
*/
|
|
34
|
+
export function defaultAuthorize(ctx) {
|
|
35
|
+
if (!isProduction())
|
|
36
|
+
return true;
|
|
37
|
+
const expected = process.env.DURABLE_DASHBOARD_TOKEN;
|
|
38
|
+
if (!expected)
|
|
39
|
+
return false;
|
|
40
|
+
return readToken(ctx) === expected;
|
|
41
|
+
}
|
|
42
|
+
/** Apply defaults to a partial config, producing a fully-resolved one. */
|
|
43
|
+
export function resolveConfig(config = {}) {
|
|
44
|
+
const rawPath = config.path ?? '/durable';
|
|
45
|
+
// Normalize: ensure a single leading slash and no trailing slash (root stays '/').
|
|
46
|
+
const trimmed = `/${rawPath.replace(/^\/+/, '').replace(/\/+$/, '')}`;
|
|
47
|
+
return {
|
|
48
|
+
enabled: config.enabled ?? true,
|
|
49
|
+
path: trimmed === '/' ? '' : trimmed,
|
|
50
|
+
authorize: config.authorize ?? defaultAuthorize,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Identity helper giving `config/durable_dashboard.ts` full type-checking. */
|
|
54
|
+
export function defineConfig(config = {}) {
|
|
55
|
+
return config;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=define_config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../../src/dashboard/define_config.ts"],"names":[],"mappings":"AAwCA;;;GAGG;AACH,SAAS,YAAY;IACnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,GAAgB;IACjC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACnD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACtD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC;IAClC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACvD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAgB;IAC/C,IAAI,CAAC,YAAY,EAAE;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;IACrD,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,OAAO,SAAS,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AACrC,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,SAAiC,EAAE;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC;IAC1C,mFAAmF;IACnF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;IACtE,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;QAC/B,IAAI,EAAE,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;QACpC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,gBAAgB;KAChD,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,SAAiC,EAAE;IAC9D,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { WorkflowEngine } from '../index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Framework-light JSON handlers over a {@link WorkflowEngine}.
|
|
4
|
+
*
|
|
5
|
+
* Each handler takes a {@link Deps} bundle (just the engine — runs and
|
|
6
|
+
* checkpoints are read through the engine's own read API, {@link
|
|
7
|
+
* WorkflowEngine.listRuns} / {@link WorkflowEngine.listCheckpoints}, so the
|
|
8
|
+
* dashboard never reaches for the engine's private store) plus a plain {@link
|
|
9
|
+
* ApiRequest} (a thin view of the parts of an HTTP request it needs), and
|
|
10
|
+
* returns a plain {@link ApiResponse} (status + JSON body). No AdonisJS types
|
|
11
|
+
* leak in, so the handlers are unit-testable against a real in-memory engine
|
|
12
|
+
* with no HTTP server. The provider adapts an AdonisJS `HttpContext` to these
|
|
13
|
+
* shapes.
|
|
14
|
+
*/
|
|
15
|
+
/** The engine the handlers operate over. */
|
|
16
|
+
export interface Deps {
|
|
17
|
+
engine: WorkflowEngine;
|
|
18
|
+
}
|
|
19
|
+
/** The subset of an HTTP request the handlers read. */
|
|
20
|
+
export interface ApiRequest {
|
|
21
|
+
/** Route params, e.g. `{ id: 'run-1' }`. */
|
|
22
|
+
params: Record<string, string | undefined>;
|
|
23
|
+
/** Parsed query string, e.g. `{ status: 'failed', limit: '20' }`. */
|
|
24
|
+
query: Record<string, string | string[] | undefined>;
|
|
25
|
+
/** Parsed JSON body (for POST actions). */
|
|
26
|
+
body?: unknown;
|
|
27
|
+
}
|
|
28
|
+
/** A plain JSON response: an HTTP status and a serializable body. */
|
|
29
|
+
export interface ApiResponse {
|
|
30
|
+
status: number;
|
|
31
|
+
body: unknown;
|
|
32
|
+
}
|
|
33
|
+
/** `GET /runs` — list runs filtered by status/workflow/tag, paginated. */
|
|
34
|
+
export declare function listRuns(deps: Deps, req: ApiRequest): Promise<ApiResponse>;
|
|
35
|
+
/** `GET /runs/:id` — a run's detail: the run, its step timeline, and child run ids. */
|
|
36
|
+
export declare function getRun(deps: Deps, req: ApiRequest): Promise<ApiResponse>;
|
|
37
|
+
/**
|
|
38
|
+
* `POST /runs/:id/retry` — re-enqueue a failed/incomplete run for a worker to
|
|
39
|
+
* resume (completed steps replay from their checkpoints). Returns the enqueued
|
|
40
|
+
* state immediately; never blocks on execution.
|
|
41
|
+
*/
|
|
42
|
+
export declare function retryRun(deps: Deps, req: ApiRequest): Promise<ApiResponse>;
|
|
43
|
+
/** `POST /runs/:id/cancel` — cancel a run. Pass `{ compensate: true }` to undo the saga first. */
|
|
44
|
+
export declare function cancelRun(deps: Deps, req: ApiRequest): Promise<ApiResponse>;
|
|
45
|
+
/** `GET /health` — per-group worker health (queue backlog + live worker heartbeats). */
|
|
46
|
+
export declare function health(deps: Deps): Promise<ApiResponse>;
|
|
47
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/dashboard/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,cAAc,EAEf,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;GAYG;AAEH,4CAA4C;AAC5C,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3C,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACrD,2CAA2C;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAuCD,0EAA0E;AAC1E,wBAAsB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAqBhF;AAED,uFAAuF;AACvF,wBAAsB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAe9E;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAMhF;AAED,kGAAkG;AAClG,wBAAsB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAUjF;AAED,wFAAwF;AACxF,wBAAsB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAW7D"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const ok = (body) => ({ status: 200, body });
|
|
2
|
+
const notFound = (message) => ({
|
|
3
|
+
status: 404,
|
|
4
|
+
body: { error: message },
|
|
5
|
+
});
|
|
6
|
+
const RUN_STATUSES = [
|
|
7
|
+
'pending',
|
|
8
|
+
'running',
|
|
9
|
+
'suspended',
|
|
10
|
+
'completed',
|
|
11
|
+
'failed',
|
|
12
|
+
'cancelled',
|
|
13
|
+
'dead',
|
|
14
|
+
];
|
|
15
|
+
function firstQuery(value) {
|
|
16
|
+
if (Array.isArray(value))
|
|
17
|
+
return value[0];
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
/** Parse a positive integer query param, falling back to `fallback` when absent/invalid. */
|
|
21
|
+
function intQuery(value, fallback) {
|
|
22
|
+
const raw = firstQuery(value);
|
|
23
|
+
if (raw === undefined)
|
|
24
|
+
return fallback;
|
|
25
|
+
const n = Number.parseInt(raw, 10);
|
|
26
|
+
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
27
|
+
}
|
|
28
|
+
/** Validate that a string is a known {@link RunStatus}, else `undefined`. */
|
|
29
|
+
function parseStatus(value) {
|
|
30
|
+
if (value && RUN_STATUSES.includes(value)) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/** `GET /runs` — list runs filtered by status/workflow/tag, paginated. */
|
|
36
|
+
export async function listRuns(deps, req) {
|
|
37
|
+
const { engine } = deps;
|
|
38
|
+
const limit = Math.min(intQuery(req.query.limit, 50), 200);
|
|
39
|
+
const offset = intQuery(req.query.offset, 0);
|
|
40
|
+
const status = parseStatus(firstQuery(req.query.status));
|
|
41
|
+
const workflow = firstQuery(req.query.workflow);
|
|
42
|
+
const tag = firstQuery(req.query.tag);
|
|
43
|
+
// Build the query with only the predicates that are set — exactOptionalPropertyTypes
|
|
44
|
+
// forbids passing an explicit `undefined`.
|
|
45
|
+
const query = { limit, offset };
|
|
46
|
+
if (status)
|
|
47
|
+
query.status = status;
|
|
48
|
+
if (workflow)
|
|
49
|
+
query.workflow = workflow;
|
|
50
|
+
if (tag)
|
|
51
|
+
query.tag = tag;
|
|
52
|
+
const runs = await engine.listRuns(query);
|
|
53
|
+
return ok({
|
|
54
|
+
runs: runs.map(summarizeRun),
|
|
55
|
+
page: { limit, offset, count: runs.length },
|
|
56
|
+
statuses: RUN_STATUSES,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** `GET /runs/:id` — a run's detail: the run, its step timeline, and child run ids. */
|
|
60
|
+
export async function getRun(deps, req) {
|
|
61
|
+
const { engine } = deps;
|
|
62
|
+
const id = req.params.id;
|
|
63
|
+
if (!id)
|
|
64
|
+
return notFound('run id is required');
|
|
65
|
+
const run = await engine.getRun(id);
|
|
66
|
+
if (!run)
|
|
67
|
+
return notFound(`run ${id} not found`);
|
|
68
|
+
const [timeline, children] = await Promise.all([
|
|
69
|
+
engine.listCheckpoints(id),
|
|
70
|
+
engine.getRunChildren(id),
|
|
71
|
+
]);
|
|
72
|
+
return ok({
|
|
73
|
+
run: detailRun(run),
|
|
74
|
+
timeline: timeline.map(summarizeCheckpoint),
|
|
75
|
+
children,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* `POST /runs/:id/retry` — re-enqueue a failed/incomplete run for a worker to
|
|
80
|
+
* resume (completed steps replay from their checkpoints). Returns the enqueued
|
|
81
|
+
* state immediately; never blocks on execution.
|
|
82
|
+
*/
|
|
83
|
+
export async function retryRun(deps, req) {
|
|
84
|
+
const id = req.params.id;
|
|
85
|
+
if (!id)
|
|
86
|
+
return notFound('run id is required');
|
|
87
|
+
const result = await deps.engine.requeue(id);
|
|
88
|
+
if (!result)
|
|
89
|
+
return notFound(`run ${id} not found`);
|
|
90
|
+
return ok({ result });
|
|
91
|
+
}
|
|
92
|
+
/** `POST /runs/:id/cancel` — cancel a run. Pass `{ compensate: true }` to undo the saga first. */
|
|
93
|
+
export async function cancelRun(deps, req) {
|
|
94
|
+
const id = req.params.id;
|
|
95
|
+
if (!id)
|
|
96
|
+
return notFound('run id is required');
|
|
97
|
+
const compensate = typeof req.body === 'object' &&
|
|
98
|
+
req.body !== null &&
|
|
99
|
+
req.body.compensate === true;
|
|
100
|
+
const result = await deps.engine.cancel(id, compensate ? { compensate: true } : undefined);
|
|
101
|
+
if (!result)
|
|
102
|
+
return notFound(`run ${id} not found`);
|
|
103
|
+
return ok({ result });
|
|
104
|
+
}
|
|
105
|
+
/** `GET /health` — per-group worker health (queue backlog + live worker heartbeats). */
|
|
106
|
+
export async function health(deps) {
|
|
107
|
+
const groups = await deps.engine.workerHealth();
|
|
108
|
+
return ok({
|
|
109
|
+
groups: groups.map((g) => ({
|
|
110
|
+
group: g.group,
|
|
111
|
+
depth: g.depth,
|
|
112
|
+
liveWorkers: g.liveWorkers.length,
|
|
113
|
+
// The actionable alert state: work piling up with no consumer.
|
|
114
|
+
stalled: g.depth > 0 && g.liveWorkers.length === 0,
|
|
115
|
+
})),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/** Compact run shape for the list view. */
|
|
119
|
+
function summarizeRun(run) {
|
|
120
|
+
return {
|
|
121
|
+
id: run.id,
|
|
122
|
+
workflow: run.workflow,
|
|
123
|
+
workflowVersion: run.workflowVersion,
|
|
124
|
+
status: run.status,
|
|
125
|
+
tags: run.tags ?? [],
|
|
126
|
+
createdAt: run.createdAt.toISOString(),
|
|
127
|
+
updatedAt: run.updatedAt.toISOString(),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Fuller run shape for the detail view. */
|
|
131
|
+
function detailRun(run) {
|
|
132
|
+
return {
|
|
133
|
+
...summarizeRun(run),
|
|
134
|
+
input: run.input,
|
|
135
|
+
output: run.output,
|
|
136
|
+
error: run.error,
|
|
137
|
+
searchAttributes: run.searchAttributes,
|
|
138
|
+
wakeAt: run.wakeAt,
|
|
139
|
+
recoveryAttempts: run.recoveryAttempts,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/** Compact checkpoint shape for the timeline. */
|
|
143
|
+
function summarizeCheckpoint(cp) {
|
|
144
|
+
const durationMs = cp.finishedAt.getTime() - cp.startedAt.getTime();
|
|
145
|
+
const queueMs = cp.startedAt.getTime() - cp.enqueuedAt.getTime();
|
|
146
|
+
return {
|
|
147
|
+
seq: cp.seq,
|
|
148
|
+
name: cp.name,
|
|
149
|
+
kind: cp.kind,
|
|
150
|
+
status: cp.status,
|
|
151
|
+
attempts: cp.attempts,
|
|
152
|
+
workerGroup: cp.workerGroup,
|
|
153
|
+
output: cp.output,
|
|
154
|
+
error: cp.error,
|
|
155
|
+
events: cp.events ?? [],
|
|
156
|
+
enqueuedAt: cp.enqueuedAt.toISOString(),
|
|
157
|
+
startedAt: cp.startedAt.toISOString(),
|
|
158
|
+
finishedAt: cp.finishedAt.toISOString(),
|
|
159
|
+
durationMs: durationMs >= 0 ? durationMs : 0,
|
|
160
|
+
queueMs: queueMs >= 0 ? queueMs : 0,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/dashboard/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render the dashboard HTML with the JSON API base path injected, so the
|
|
3
|
+
* single-page client knows where to fetch from regardless of the configured
|
|
4
|
+
* mount prefix.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderDashboard(apiBase: string): string;
|
|
7
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/dashboard/html.ts"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|