adispatchd 0.0.0-stage → 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 +195 -2
- package/dist/api/errors.d.ts +27 -0
- package/dist/api/errors.js +80 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +11 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/logs.d.ts +30 -0
- package/dist/api/logs.js +88 -0
- package/dist/api/logs.js.map +1 -0
- package/dist/api/serialize.d.ts +65 -0
- package/dist/api/serialize.js +135 -0
- package/dist/api/serialize.js.map +1 -0
- package/dist/api/server.d.ts +89 -0
- package/dist/api/server.js +751 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/sse.d.ts +90 -0
- package/dist/api/sse.js +225 -0
- package/dist/api/sse.js.map +1 -0
- package/dist/app.d.ts +173 -0
- package/dist/app.js +488 -0
- package/dist/app.js.map +1 -0
- package/dist/cli/config-validate.d.ts +6 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/config-validate.js.map +1 -0
- package/dist/cli/control.d.ts +31 -0
- package/dist/cli/control.js +186 -0
- package/dist/cli/control.js.map +1 -0
- package/dist/cli/http-client.d.ts +57 -0
- package/dist/cli/http-client.js +174 -0
- package/dist/cli/http-client.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +20 -0
- package/dist/cli/init-templates.js +275 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +107 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +25 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +102 -0
- package/dist/cli/program.js +133 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/service.d.ts +27 -0
- package/dist/cli/service.js +252 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/start.d.ts +22 -0
- package/dist/cli/start.js +133 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/workflow-dry-run.d.ts +13 -0
- package/dist/cli/workflow-dry-run.js +144 -0
- package/dist/cli/workflow-dry-run.js.map +1 -0
- package/dist/config/field-catalog.d.ts +33 -0
- package/dist/config/field-catalog.js +172 -0
- package/dist/config/field-catalog.js.map +1 -0
- package/dist/config/filter-schema.d.ts +15 -0
- package/dist/config/filter-schema.js +110 -0
- package/dist/config/filter-schema.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.js +16 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/issues.d.ts +27 -0
- package/dist/config/issues.js +37 -0
- package/dist/config/issues.js.map +1 -0
- package/dist/config/loader.d.ts +32 -0
- package/dist/config/loader.js +250 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +153 -0
- package/dist/config/manager.js +276 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/model.d.ts +334 -0
- package/dist/config/model.js +2 -0
- package/dist/config/model.js.map +1 -0
- package/dist/config/normalize.d.ts +20 -0
- package/dist/config/normalize.js +200 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/config/parameters.d.ts +37 -0
- package/dist/config/parameters.js +71 -0
- package/dist/config/parameters.js.map +1 -0
- package/dist/config/public.d.ts +6 -0
- package/dist/config/public.js +18 -0
- package/dist/config/public.js.map +1 -0
- package/dist/config/schemas.d.ts +538 -0
- package/dist/config/schemas.js +321 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/snapshot.d.ts +38 -0
- package/dist/config/snapshot.js +57 -0
- package/dist/config/snapshot.js.map +1 -0
- package/dist/config/validate.d.ts +33 -0
- package/dist/config/validate.js +346 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/clock.d.ts +59 -0
- package/dist/core/clock.js +133 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/duration.d.ts +19 -0
- package/dist/core/duration.js +93 -0
- package/dist/core/duration.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.js +72 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/ids.d.ts +57 -0
- package/dist/core/ids.js +88 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +100 -0
- package/dist/core/logger.js +207 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/paths.d.ts +84 -0
- package/dist/core/paths.js +138 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/template.d.ts +136 -0
- package/dist/core/template.js +261 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/types.d.ts +544 -0
- package/dist/core/types.js +172 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/worker-protocol.d.ts +102 -0
- package/dist/core/worker-protocol.js +75 -0
- package/dist/core/worker-protocol.js.map +1 -0
- package/dist/executors/classify.d.ts +25 -0
- package/dist/executors/classify.js +54 -0
- package/dist/executors/classify.js.map +1 -0
- package/dist/executors/dispatcher.d.ts +35 -0
- package/dist/executors/dispatcher.js +68 -0
- package/dist/executors/dispatcher.js.map +1 -0
- package/dist/executors/env.d.ts +43 -0
- package/dist/executors/env.js +66 -0
- package/dist/executors/env.js.map +1 -0
- package/dist/executors/event-parser.d.ts +41 -0
- package/dist/executors/event-parser.js +106 -0
- package/dist/executors/event-parser.js.map +1 -0
- package/dist/executors/index.d.ts +12 -0
- package/dist/executors/index.js +13 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/log-capture.d.ts +57 -0
- package/dist/executors/log-capture.js +155 -0
- package/dist/executors/log-capture.js.map +1 -0
- package/dist/executors/process-identity.d.ts +124 -0
- package/dist/executors/process-identity.js +283 -0
- package/dist/executors/process-identity.js.map +1 -0
- package/dist/executors/shell-executor.d.ts +35 -0
- package/dist/executors/shell-executor.js +478 -0
- package/dist/executors/shell-executor.js.map +1 -0
- package/dist/executors/stream-redactor.d.ts +40 -0
- package/dist/executors/stream-redactor.js +89 -0
- package/dist/executors/stream-redactor.js.map +1 -0
- package/dist/executors/workspace.d.ts +10 -0
- package/dist/executors/workspace.js +47 -0
- package/dist/executors/workspace.js.map +1 -0
- package/dist/filters/evaluate.d.ts +77 -0
- package/dist/filters/evaluate.js +187 -0
- package/dist/filters/evaluate.js.map +1 -0
- package/dist/filters/fields.d.ts +35 -0
- package/dist/filters/fields.js +75 -0
- package/dist/filters/fields.js.map +1 -0
- package/dist/filters/index.d.ts +11 -0
- package/dist/filters/index.js +12 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/iso-date.d.ts +10 -0
- package/dist/filters/iso-date.js +42 -0
- package/dist/filters/iso-date.js.map +1 -0
- package/dist/filters/predicate.d.ts +24 -0
- package/dist/filters/predicate.js +178 -0
- package/dist/filters/predicate.js.map +1 -0
- package/dist/filters/priority.d.ts +51 -0
- package/dist/filters/priority.js +91 -0
- package/dist/filters/priority.js.map +1 -0
- package/dist/filters/pushdown.d.ts +12 -0
- package/dist/filters/pushdown.js +52 -0
- package/dist/filters/pushdown.js.map +1 -0
- package/dist/filters/shell-check.d.ts +110 -0
- package/dist/filters/shell-check.js +304 -0
- package/dist/filters/shell-check.js.map +1 -0
- package/dist/identities/github-app.d.ts +55 -0
- package/dist/identities/github-app.js +160 -0
- package/dist/identities/github-app.js.map +1 -0
- package/dist/identities/index.d.ts +6 -0
- package/dist/identities/index.js +7 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/identities/jwt.d.ts +24 -0
- package/dist/identities/jwt.js +56 -0
- package/dist/identities/jwt.js.map +1 -0
- package/dist/lifecycle/context.d.ts +106 -0
- package/dist/lifecycle/context.js +170 -0
- package/dist/lifecycle/context.js.map +1 -0
- package/dist/lifecycle/engine.d.ts +185 -0
- package/dist/lifecycle/engine.js +551 -0
- package/dist/lifecycle/engine.js.map +1 -0
- package/dist/lifecycle/errors.d.ts +48 -0
- package/dist/lifecycle/errors.js +71 -0
- package/dist/lifecycle/errors.js.map +1 -0
- package/dist/lifecycle/index.d.ts +9 -0
- package/dist/lifecycle/index.js +9 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/performers.d.ts +66 -0
- package/dist/lifecycle/performers.js +179 -0
- package/dist/lifecycle/performers.js.map +1 -0
- package/dist/notifications/index.d.ts +6 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/service.d.ts +115 -0
- package/dist/notifications/service.js +364 -0
- package/dist/notifications/service.js.map +1 -0
- package/dist/persistence/actions.d.ts +101 -0
- package/dist/persistence/actions.js +196 -0
- package/dist/persistence/actions.js.map +1 -0
- package/dist/persistence/blocks.d.ts +85 -0
- package/dist/persistence/blocks.js +140 -0
- package/dist/persistence/blocks.js.map +1 -0
- package/dist/persistence/cron-firings.d.ts +55 -0
- package/dist/persistence/cron-firings.js +70 -0
- package/dist/persistence/cron-firings.js.map +1 -0
- package/dist/persistence/database.d.ts +60 -0
- package/dist/persistence/database.js +124 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/persistence/errors.d.ts +39 -0
- package/dist/persistence/errors.js +67 -0
- package/dist/persistence/errors.js.map +1 -0
- package/dist/persistence/events.d.ts +72 -0
- package/dist/persistence/events.js +83 -0
- package/dist/persistence/events.js.map +1 -0
- package/dist/persistence/index.d.ts +18 -0
- package/dist/persistence/index.js +19 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/instance-lock.d.ts +26 -0
- package/dist/persistence/instance-lock.js +117 -0
- package/dist/persistence/instance-lock.js.map +1 -0
- package/dist/persistence/lock-keys.d.ts +16 -0
- package/dist/persistence/lock-keys.js +41 -0
- package/dist/persistence/lock-keys.js.map +1 -0
- package/dist/persistence/notifications.d.ts +113 -0
- package/dist/persistence/notifications.js +213 -0
- package/dist/persistence/notifications.js.map +1 -0
- package/dist/persistence/persistence.d.ts +46 -0
- package/dist/persistence/persistence.js +42 -0
- package/dist/persistence/persistence.js.map +1 -0
- package/dist/persistence/retention.d.ts +46 -0
- package/dist/persistence/retention.js +68 -0
- package/dist/persistence/retention.js.map +1 -0
- package/dist/persistence/runs.d.ts +215 -0
- package/dist/persistence/runs.js +417 -0
- package/dist/persistence/runs.js.map +1 -0
- package/dist/persistence/schema.d.ts +16 -0
- package/dist/persistence/schema.js +183 -0
- package/dist/persistence/schema.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +49 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/runs/controller.d.ts +307 -0
- package/dist/runs/controller.js +1078 -0
- package/dist/runs/controller.js.map +1 -0
- package/dist/runs/errors.d.ts +20 -0
- package/dist/runs/errors.js +26 -0
- package/dist/runs/errors.js.map +1 -0
- package/dist/runs/event-bus.d.ts +106 -0
- package/dist/runs/event-bus.js +105 -0
- package/dist/runs/event-bus.js.map +1 -0
- package/dist/runs/execution.d.ts +39 -0
- package/dist/runs/execution.js +146 -0
- package/dist/runs/execution.js.map +1 -0
- package/dist/runs/index.d.ts +12 -0
- package/dist/runs/index.js +13 -0
- package/dist/runs/index.js.map +1 -0
- package/dist/runs/retention.d.ts +64 -0
- package/dist/runs/retention.js +232 -0
- package/dist/runs/retention.js.map +1 -0
- package/dist/runs/workspace.d.ts +20 -0
- package/dist/runs/workspace.js +51 -0
- package/dist/runs/workspace.js.map +1 -0
- package/dist/scheduler/checks.d.ts +41 -0
- package/dist/scheduler/checks.js +111 -0
- package/dist/scheduler/checks.js.map +1 -0
- package/dist/scheduler/cron.d.ts +32 -0
- package/dist/scheduler/cron.js +83 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/dry-run.d.ts +42 -0
- package/dist/scheduler/dry-run.js +167 -0
- package/dist/scheduler/dry-run.js.map +1 -0
- package/dist/scheduler/errors.d.ts +22 -0
- package/dist/scheduler/errors.js +22 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/format.d.ts +3 -0
- package/dist/scheduler/format.js +73 -0
- package/dist/scheduler/format.js.map +1 -0
- package/dist/scheduler/index.d.ts +13 -0
- package/dist/scheduler/index.js +14 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/planner.d.ts +88 -0
- package/dist/scheduler/planner.js +255 -0
- package/dist/scheduler/planner.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +160 -0
- package/dist/scheduler/scheduler.js +680 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/state.d.ts +26 -0
- package/dist/scheduler/state.js +25 -0
- package/dist/scheduler/state.js.map +1 -0
- package/dist/scheduler/types.d.ts +197 -0
- package/dist/scheduler/types.js +3 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service/index.d.ts +6 -0
- package/dist/service/index.js +7 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install.d.ts +93 -0
- package/dist/service/install.js +250 -0
- package/dist/service/install.js.map +1 -0
- package/dist/service/unit.d.ts +50 -0
- package/dist/service/unit.js +171 -0
- package/dist/service/unit.js.map +1 -0
- package/dist/sources/github/adapter.d.ts +99 -0
- package/dist/sources/github/adapter.js +336 -0
- package/dist/sources/github/adapter.js.map +1 -0
- package/dist/sources/github/fields.d.ts +8 -0
- package/dist/sources/github/fields.js +72 -0
- package/dist/sources/github/fields.js.map +1 -0
- package/dist/sources/github/http.d.ts +100 -0
- package/dist/sources/github/http.js +288 -0
- package/dist/sources/github/http.js.map +1 -0
- package/dist/sources/github/index.d.ts +6 -0
- package/dist/sources/github/index.js +7 -0
- package/dist/sources/github/index.js.map +1 -0
- package/dist/sources/github/pushdown.d.ts +14 -0
- package/dist/sources/github/pushdown.js +47 -0
- package/dist/sources/github/pushdown.js.map +1 -0
- package/dist/sources/github/refs.d.ts +17 -0
- package/dist/sources/github/refs.js +61 -0
- package/dist/sources/github/refs.js.map +1 -0
- package/dist/sources/index.d.ts +6 -0
- package/dist/sources/index.js +7 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +28 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/public/app.css +239 -0
- package/dist/ui/public/favicon.svg +1 -0
- package/dist/ui/public/index.html +27 -0
- package/dist/ui/public/js/client/api.js +68 -0
- package/dist/ui/public/js/client/app.js +146 -0
- package/dist/ui/public/js/client/dom.js +34 -0
- package/dist/ui/public/js/client/page.js +9 -0
- package/dist/ui/public/js/client/pages/actions.js +35 -0
- package/dist/ui/public/js/client/pages/blocked.js +58 -0
- package/dist/ui/public/js/client/pages/config.js +126 -0
- package/dist/ui/public/js/client/pages/dashboard.js +175 -0
- package/dist/ui/public/js/client/pages/run.js +367 -0
- package/dist/ui/public/js/client/pages/runs.js +72 -0
- package/dist/ui/public/js/client/pages/views.js +80 -0
- package/dist/ui/public/js/client/pages/workflows.js +291 -0
- package/dist/ui/public/js/client/types.js +1 -0
- package/dist/ui/public/js/client/ui.js +152 -0
- package/dist/ui/public/js/shared/dom.js +77 -0
- package/dist/ui/public/js/shared/events.js +88 -0
- package/dist/ui/public/js/shared/format.js +213 -0
- package/dist/ui/public/js/shared/logs.js +136 -0
- package/dist/ui/public/js/shared/params.js +90 -0
- package/dist/ui/public/js/shared/route.js +36 -0
- package/dist/ui/public/js/shared/sort.js +70 -0
- package/dist/ui/public/js/shared/sse.js +193 -0
- package/dist/ui/public/js/shared/throttle.js +65 -0
- package/dist/views/index.d.ts +6 -0
- package/dist/views/index.js +7 -0
- package/dist/views/index.js.map +1 -0
- package/dist/views/service.d.ts +131 -0
- package/dist/views/service.js +264 -0
- package/dist/views/service.js.map +1 -0
- package/docs/api.md +239 -0
- package/docs/configuration-reference.md +1785 -0
- package/docs/cron-semantics.md +96 -0
- package/docs/manual-tests/github-fixture/config.yaml +30 -0
- package/docs/manual-tests/github-fixture/helpers.sh +93 -0
- package/docs/manual-tests/github-fixture/identities.yaml +18 -0
- package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
- package/docs/manual-tests/github-fixture/sources.yaml +13 -0
- package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
- package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
- package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
- package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
- package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
- package/docs/manual-tests/github.md +1308 -0
- package/docs/manual-tests/process-supervision.md +64 -0
- package/docs/manual-tests/systemd.md +68 -0
- package/docs/operations.md +271 -0
- package/docs/worker-protocol.md +145 -0
- package/examples/config/config.yaml +35 -0
- package/examples/config/identities.yaml +18 -0
- package/examples/config/sources.yaml +13 -0
- package/examples/config/views/needs-maintainer.yaml +15 -0
- package/examples/config/workflows/coder-project-a.yaml +86 -0
- package/examples/config/workflows/deploy.yaml +15 -0
- package/examples/config/workflows/nightly-maintenance.yaml +13 -0
- package/package.json +75 -4
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Clock } from '../core/index.js';
|
|
2
|
+
import type { ConfigIssue, LoadedConfig } from './model.js';
|
|
3
|
+
/** Sub-directory with one file per workflow. */
|
|
4
|
+
export declare const WORKFLOWS_DIR = "workflows";
|
|
5
|
+
/** Sub-directory with one file per view. */
|
|
6
|
+
export declare const VIEWS_DIR = "views";
|
|
7
|
+
/** Maximum accepted size of a single YAML file. */
|
|
8
|
+
export declare const MAX_CONFIG_FILE_BYTES: number;
|
|
9
|
+
/** Options for {@link loadConfig}. */
|
|
10
|
+
export interface LoadConfigOptions {
|
|
11
|
+
/** Data directory; used for the default `workspace.base_dir` (`${dataDir}/workspaces`). */
|
|
12
|
+
dataDir: string;
|
|
13
|
+
/** Version number stored in the result (default 1). */
|
|
14
|
+
version?: number;
|
|
15
|
+
clock?: Clock;
|
|
16
|
+
}
|
|
17
|
+
/** Result of {@link loadConfig}. Warnings never prevent loading. */
|
|
18
|
+
export type LoadConfigResult = {
|
|
19
|
+
ok: true;
|
|
20
|
+
config: LoadedConfig;
|
|
21
|
+
warnings: ConfigIssue[];
|
|
22
|
+
} | {
|
|
23
|
+
ok: false;
|
|
24
|
+
errors: ConfigIssue[];
|
|
25
|
+
warnings: ConfigIssue[];
|
|
26
|
+
};
|
|
27
|
+
/** Load and validate the configuration in `configDir`. Never throws for config problems. */
|
|
28
|
+
export declare function loadConfig(configDir: string, options: LoadConfigOptions): Promise<LoadConfigResult>;
|
|
29
|
+
/** Canonical JSON (sorted object keys) for hashing. */
|
|
30
|
+
export declare function canonicalJson(value: unknown): string;
|
|
31
|
+
/** Recursively freeze an object graph. */
|
|
32
|
+
export declare function deepFreeze<T>(value: T): T;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config loader (Spec §19): reads the config directory, parses YAML,
|
|
3
|
+
* validates schemas and cross-file semantics, collects **all** problems with
|
|
4
|
+
* file and path, and produces an immutable {@link LoadedConfig}.
|
|
5
|
+
*
|
|
6
|
+
* The loader never reads environment variables, so no secret value can end
|
|
7
|
+
* up in the loaded model or in issue messages.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { isMap, isSeq, LineCounter, parseDocument } from 'yaml';
|
|
13
|
+
import { systemClock, toAbsolutePath } from '../core/index.js';
|
|
14
|
+
import { formatIssuePath, IssueCollector, sortIssues } from './issues.js';
|
|
15
|
+
import { normalizeGlobal, normalizeIdentities, normalizeSources, normalizeView, normalizeWorkflow, } from './normalize.js';
|
|
16
|
+
import { globalConfigSchema, identitiesFileSchema, sourcesFileSchema, viewSchema, workflowSchema, } from './schemas.js';
|
|
17
|
+
import { CONFIG_FILE, IDENTITIES_FILE, SOURCES_FILE, validateSemantics, } from './validate.js';
|
|
18
|
+
/** Sub-directory with one file per workflow. */
|
|
19
|
+
export const WORKFLOWS_DIR = 'workflows';
|
|
20
|
+
/** Sub-directory with one file per view. */
|
|
21
|
+
export const VIEWS_DIR = 'views';
|
|
22
|
+
/** Maximum accepted size of a single YAML file. */
|
|
23
|
+
export const MAX_CONFIG_FILE_BYTES = 1024 * 1024;
|
|
24
|
+
/** Load and validate the configuration in `configDir`. Never throws for config problems. */
|
|
25
|
+
export async function loadConfig(configDir, options) {
|
|
26
|
+
const dir = toAbsolutePath(configDir);
|
|
27
|
+
const issues = new IssueCollector();
|
|
28
|
+
const files = new Map();
|
|
29
|
+
const clock = options.clock ?? systemClock;
|
|
30
|
+
try {
|
|
31
|
+
const st = await stat(dir);
|
|
32
|
+
if (!st.isDirectory())
|
|
33
|
+
issues.error('.', [], `Config path "${dir}" is not a directory`);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
issues.error('.', [], `Config directory "${dir}" does not exist or is not readable`);
|
|
37
|
+
}
|
|
38
|
+
if (issues.hasErrors)
|
|
39
|
+
return finish(issues, files);
|
|
40
|
+
const readTop = async (name, warnIfMissing) => {
|
|
41
|
+
const parsed = await readYaml(dir, name, issues);
|
|
42
|
+
if (parsed === null) {
|
|
43
|
+
if (warnIfMissing)
|
|
44
|
+
issues.warning(name, [], `${name} not found, using defaults`);
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
if (parsed)
|
|
48
|
+
files.set(name, parsed);
|
|
49
|
+
return parsed;
|
|
50
|
+
};
|
|
51
|
+
const configFile = await readTop(CONFIG_FILE, true);
|
|
52
|
+
const sourcesFile = await readTop(SOURCES_FILE, false);
|
|
53
|
+
const identitiesFile = await readTop(IDENTITIES_FILE, false);
|
|
54
|
+
const workflowFiles = await readDir(dir, WORKFLOWS_DIR, issues, files);
|
|
55
|
+
const viewFiles = await readDir(dir, VIEWS_DIR, issues, files);
|
|
56
|
+
const rawGlobal = parseWith(globalConfigSchema, configFile, CONFIG_FILE, issues);
|
|
57
|
+
const rawSources = parseWith(sourcesFileSchema, sourcesFile, SOURCES_FILE, issues);
|
|
58
|
+
const rawIdentities = parseWith(identitiesFileSchema, identitiesFile, IDENTITIES_FILE, issues);
|
|
59
|
+
// Without valid global settings, workflows can still be checked against defaults.
|
|
60
|
+
const global = normalizeGlobal(rawGlobal ?? globalConfigSchema.parse({}), dir, options.dataDir);
|
|
61
|
+
const sources = rawSources ? normalizeSources(rawSources) : {};
|
|
62
|
+
const identities = rawIdentities ? normalizeIdentities(rawIdentities) : {};
|
|
63
|
+
const workflowEntries = [];
|
|
64
|
+
for (const parsed of workflowFiles) {
|
|
65
|
+
const raw = parseWith(workflowSchema, parsed, parsed.file, issues);
|
|
66
|
+
if (raw) {
|
|
67
|
+
workflowEntries.push({ workflow: normalizeWorkflow(raw, parsed.file, global, dir), rawParameters: raw.parameters });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const viewEntries = [];
|
|
71
|
+
for (const parsed of viewFiles) {
|
|
72
|
+
const raw = parseWith(viewSchema, parsed, parsed.file, issues);
|
|
73
|
+
if (raw)
|
|
74
|
+
viewEntries.push({ view: normalizeView(raw, parsed.file), hasShellFilter: raw.shell_filter !== undefined });
|
|
75
|
+
}
|
|
76
|
+
validateSemantics({ global, sources, identities, workflows: workflowEntries, views: viewEntries }, issues);
|
|
77
|
+
if (issues.hasErrors)
|
|
78
|
+
return finish(issues, files);
|
|
79
|
+
const workflows = {};
|
|
80
|
+
const workflowHashes = {};
|
|
81
|
+
for (const { workflow } of workflowEntries) {
|
|
82
|
+
workflows[workflow.id] = workflow;
|
|
83
|
+
workflowHashes[workflow.id] = hashOf(workflow);
|
|
84
|
+
}
|
|
85
|
+
const views = {};
|
|
86
|
+
for (const { view } of viewEntries)
|
|
87
|
+
views[view.id] = view;
|
|
88
|
+
const content = { global, sources, identities, workflows, views };
|
|
89
|
+
const config = {
|
|
90
|
+
configDir: dir,
|
|
91
|
+
version: options.version ?? 1,
|
|
92
|
+
hash: hashOf(content),
|
|
93
|
+
loadedAt: new Date(clock.now()).toISOString(),
|
|
94
|
+
...content,
|
|
95
|
+
workflowHashes,
|
|
96
|
+
};
|
|
97
|
+
const result = finish(issues, files);
|
|
98
|
+
return { ok: true, config: deepFreeze(config), warnings: result.warnings };
|
|
99
|
+
}
|
|
100
|
+
function finish(issues, files) {
|
|
101
|
+
const resolved = issues.items.map((item) => {
|
|
102
|
+
const line = item.line ?? lineOf(files.get(item.file), item.path);
|
|
103
|
+
return {
|
|
104
|
+
severity: item.severity,
|
|
105
|
+
file: item.file,
|
|
106
|
+
path: formatIssuePath(item.path),
|
|
107
|
+
message: item.message,
|
|
108
|
+
...(line !== undefined ? { line } : {}),
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
const sorted = sortIssues(resolved);
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
errors: sorted.filter((i) => i.severity === 'error'),
|
|
115
|
+
warnings: sorted.filter((i) => i.severity === 'warning'),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read and parse one YAML file. Returns `null` if the file does not exist,
|
|
120
|
+
* `undefined` if it exists but is unusable (issue recorded).
|
|
121
|
+
*/
|
|
122
|
+
async function readYaml(dir, file, issues) {
|
|
123
|
+
const full = path.join(dir, file);
|
|
124
|
+
let text;
|
|
125
|
+
try {
|
|
126
|
+
const st = await stat(full);
|
|
127
|
+
if (!st.isFile()) {
|
|
128
|
+
issues.error(file, [], 'Not a regular file');
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
if (st.size > MAX_CONFIG_FILE_BYTES) {
|
|
132
|
+
issues.error(file, [], `File is larger than ${MAX_CONFIG_FILE_BYTES} bytes`);
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
text = await readFile(full, 'utf8');
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
if (err.code === 'ENOENT')
|
|
139
|
+
return null;
|
|
140
|
+
issues.error(file, [], `Cannot read file: ${err.code ?? 'error'}`);
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const lineCounter = new LineCounter();
|
|
144
|
+
const doc = parseDocument(text, { lineCounter, prettyErrors: false, uniqueKeys: true });
|
|
145
|
+
for (const err of doc.errors) {
|
|
146
|
+
issues.error(file, [], `YAML syntax error: ${firstLine(err.message)}`, lineCounter.linePos(err.pos[0]).line);
|
|
147
|
+
}
|
|
148
|
+
if (doc.errors.length > 0)
|
|
149
|
+
return undefined;
|
|
150
|
+
for (const warn of doc.warnings) {
|
|
151
|
+
issues.warning(file, [], `YAML: ${firstLine(warn.message)}`, lineCounter.linePos(warn.pos[0]).line);
|
|
152
|
+
}
|
|
153
|
+
let data;
|
|
154
|
+
try {
|
|
155
|
+
data = doc.toJS({ maxAliasCount: 100 });
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
issues.error(file, [], `YAML error: ${firstLine(err.message)}`);
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
return { file, doc, lineCounter, data: data ?? {} };
|
|
162
|
+
}
|
|
163
|
+
function firstLine(message) {
|
|
164
|
+
return message.split('\n')[0] ?? message;
|
|
165
|
+
}
|
|
166
|
+
async function readDir(dir, sub, issues, files) {
|
|
167
|
+
let names;
|
|
168
|
+
try {
|
|
169
|
+
names = await readdir(path.join(dir, sub));
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
if (err.code === 'ENOENT')
|
|
173
|
+
return [];
|
|
174
|
+
issues.error(sub, [], `Cannot read directory: ${err.code ?? 'error'}`);
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
const out = [];
|
|
178
|
+
for (const name of names.filter((n) => /\.ya?ml$/.test(n) && !n.startsWith('.')).sort()) {
|
|
179
|
+
const file = `${sub}/${name}`;
|
|
180
|
+
const parsed = await readYaml(dir, file, issues);
|
|
181
|
+
if (parsed) {
|
|
182
|
+
files.set(file, parsed);
|
|
183
|
+
out.push(parsed);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return out;
|
|
187
|
+
}
|
|
188
|
+
function parseWith(schema, parsed, file, issues) {
|
|
189
|
+
const data = parsed ? parsed.data : {};
|
|
190
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
191
|
+
issues.error(file, [], 'Top level must be a mapping');
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
const result = schema.safeParse(data);
|
|
195
|
+
if (result.success)
|
|
196
|
+
return result.data;
|
|
197
|
+
for (const issue of result.error.issues) {
|
|
198
|
+
const at = issue.path.filter((p) => typeof p !== 'symbol');
|
|
199
|
+
let message = issue.message;
|
|
200
|
+
if (issue.code === 'unrecognized_keys') {
|
|
201
|
+
message = `Unknown key(s): ${issue.keys.map((k) => `"${k}"`).join(', ')}`;
|
|
202
|
+
}
|
|
203
|
+
issues.error(file, at, message);
|
|
204
|
+
}
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
/** Find the 1-based line of the deepest existing node along `issuePath`. */
|
|
208
|
+
function lineOf(parsed, issuePath) {
|
|
209
|
+
if (!parsed?.doc)
|
|
210
|
+
return undefined;
|
|
211
|
+
let node = parsed.doc.contents;
|
|
212
|
+
let found = node;
|
|
213
|
+
for (const segment of issuePath) {
|
|
214
|
+
if (isMap(node))
|
|
215
|
+
node = node.get(segment, true);
|
|
216
|
+
else if (isSeq(node) && typeof segment === 'number')
|
|
217
|
+
node = node.get(segment, true);
|
|
218
|
+
else
|
|
219
|
+
break;
|
|
220
|
+
if (node === undefined || node === null)
|
|
221
|
+
break;
|
|
222
|
+
found = node;
|
|
223
|
+
}
|
|
224
|
+
const range = found?.range;
|
|
225
|
+
if (!range)
|
|
226
|
+
return undefined;
|
|
227
|
+
return parsed.lineCounter.linePos(range[0]).line;
|
|
228
|
+
}
|
|
229
|
+
/** Canonical JSON (sorted object keys) for hashing. */
|
|
230
|
+
export function canonicalJson(value) {
|
|
231
|
+
return JSON.stringify(value, (_key, v) => {
|
|
232
|
+
if (v && typeof v === 'object' && !Array.isArray(v)) {
|
|
233
|
+
return Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));
|
|
234
|
+
}
|
|
235
|
+
return v;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function hashOf(value) {
|
|
239
|
+
return createHash('sha256').update(canonicalJson(value)).digest('hex');
|
|
240
|
+
}
|
|
241
|
+
/** Recursively freeze an object graph. */
|
|
242
|
+
export function deepFreeze(value) {
|
|
243
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
244
|
+
Object.freeze(value);
|
|
245
|
+
for (const child of Object.values(value))
|
|
246
|
+
deepFreeze(child);
|
|
247
|
+
}
|
|
248
|
+
return value;
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigManager (Spec §19): holds the active configuration, reloads it
|
|
3
|
+
* atomically (all-or-nothing) and manages non-persistent runtime overrides.
|
|
4
|
+
*/
|
|
5
|
+
import { OrchestratorError, type Clock, type Logger, type Unsubscribe } from '../core/index.js';
|
|
6
|
+
import { type LoadConfigOptions, type LoadConfigResult } from './loader.js';
|
|
7
|
+
import type { ConfigIssue, LoadedConfig, WorkflowConfig } from './model.js';
|
|
8
|
+
import { type ParameterValidationResult } from './parameters.js';
|
|
9
|
+
import { type WorkflowSnapshot } from './snapshot.js';
|
|
10
|
+
/** Runtime overrides of one workflow (not persisted, Spec §19). */
|
|
11
|
+
export interface WorkflowOverrides {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
priority?: number;
|
|
14
|
+
maxConcurrent?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Runtime overrides of global settings. */
|
|
17
|
+
export interface GlobalOverrides {
|
|
18
|
+
maxConcurrent?: number;
|
|
19
|
+
}
|
|
20
|
+
/** A workflow with its effective (override-applied) scheduling values. */
|
|
21
|
+
export interface EffectiveWorkflow {
|
|
22
|
+
config: WorkflowConfig;
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
priority: number;
|
|
25
|
+
maxConcurrent: number;
|
|
26
|
+
/** Currently active overrides (empty object if none). */
|
|
27
|
+
overrides: Readonly<WorkflowOverrides>;
|
|
28
|
+
}
|
|
29
|
+
/** Changes detected by a successful reload. */
|
|
30
|
+
export interface ConfigDiff {
|
|
31
|
+
addedWorkflows: string[];
|
|
32
|
+
removedWorkflows: string[];
|
|
33
|
+
changedWorkflows: string[];
|
|
34
|
+
}
|
|
35
|
+
/** Result of {@link ConfigManager.reload}. */
|
|
36
|
+
export type ReloadResult = {
|
|
37
|
+
ok: true;
|
|
38
|
+
config: LoadedConfig;
|
|
39
|
+
previous: LoadedConfig;
|
|
40
|
+
/** False if the content hash is unchanged (the version still increases). */
|
|
41
|
+
changed: boolean;
|
|
42
|
+
diff: ConfigDiff;
|
|
43
|
+
/**
|
|
44
|
+
* Workflows with at least one reset override (a field is reset when its
|
|
45
|
+
* configured value changed or the workflow was removed), plus `"*"` if the
|
|
46
|
+
* global override was reset.
|
|
47
|
+
*/
|
|
48
|
+
resetOverrides: string[];
|
|
49
|
+
warnings: ConfigIssue[];
|
|
50
|
+
} | {
|
|
51
|
+
ok: false;
|
|
52
|
+
errors: ConfigIssue[];
|
|
53
|
+
warnings: ConfigIssue[];
|
|
54
|
+
};
|
|
55
|
+
/** Event delivered to {@link ConfigManager.onChange} listeners. */
|
|
56
|
+
export type ConfigChangeEvent = {
|
|
57
|
+
kind: 'reload';
|
|
58
|
+
config: LoadedConfig;
|
|
59
|
+
previous: LoadedConfig;
|
|
60
|
+
diff: ConfigDiff;
|
|
61
|
+
resetOverrides: string[];
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'overrides';
|
|
64
|
+
workflowId: string | null;
|
|
65
|
+
};
|
|
66
|
+
/** Listener for configuration changes. Must not throw (errors are logged). */
|
|
67
|
+
export type ConfigChangeListener = (event: ConfigChangeEvent) => void;
|
|
68
|
+
/** Thrown by {@link ConfigManager.create} when the initial configuration is invalid. */
|
|
69
|
+
export declare class ConfigLoadError extends OrchestratorError {
|
|
70
|
+
readonly errors: ConfigIssue[];
|
|
71
|
+
readonly warnings: ConfigIssue[];
|
|
72
|
+
constructor(errors: ConfigIssue[], warnings: ConfigIssue[]);
|
|
73
|
+
}
|
|
74
|
+
/** Loader signature (injectable for tests). */
|
|
75
|
+
export type ConfigLoader = (configDir: string, options: LoadConfigOptions) => Promise<LoadConfigResult>;
|
|
76
|
+
/** Options for {@link ConfigManager}. */
|
|
77
|
+
export interface ConfigManagerOptions {
|
|
78
|
+
configDir: string;
|
|
79
|
+
dataDir: string;
|
|
80
|
+
clock?: Clock;
|
|
81
|
+
logger?: Logger;
|
|
82
|
+
loader?: ConfigLoader;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Holds the active {@link LoadedConfig}. Use {@link ConfigManager.create} to
|
|
86
|
+
* load the initial configuration.
|
|
87
|
+
*/
|
|
88
|
+
export declare class ConfigManager {
|
|
89
|
+
private readonly options;
|
|
90
|
+
private active;
|
|
91
|
+
private workflowOverrides;
|
|
92
|
+
private globalOverrides;
|
|
93
|
+
private readonly listeners;
|
|
94
|
+
private reloadChain;
|
|
95
|
+
private readonly clock;
|
|
96
|
+
private readonly logger;
|
|
97
|
+
private readonly loader;
|
|
98
|
+
/** Use {@link ConfigManager.create} unless you already have a loaded config. */
|
|
99
|
+
constructor(initial: LoadedConfig, options: ConfigManagerOptions);
|
|
100
|
+
/**
|
|
101
|
+
* Load the configuration and create a manager.
|
|
102
|
+
* @throws ConfigLoadError if the configuration is invalid.
|
|
103
|
+
*/
|
|
104
|
+
static create(options: ConfigManagerOptions): Promise<ConfigManager>;
|
|
105
|
+
/** The active configuration (immutable). */
|
|
106
|
+
get current(): LoadedConfig;
|
|
107
|
+
/**
|
|
108
|
+
* Reload the whole configuration. Only if loading and validation succeed
|
|
109
|
+
* completely is the new configuration activated (atomically); otherwise the
|
|
110
|
+
* active configuration stays untouched and the errors are returned.
|
|
111
|
+
* Concurrent calls are serialized.
|
|
112
|
+
*/
|
|
113
|
+
reload(): Promise<ReloadResult>;
|
|
114
|
+
private doReload;
|
|
115
|
+
/** Register a change listener. */
|
|
116
|
+
onChange(listener: ConfigChangeListener): Unsubscribe;
|
|
117
|
+
private emit;
|
|
118
|
+
private requireWorkflow;
|
|
119
|
+
/** Workflow with effective values, or `undefined` if unknown. */
|
|
120
|
+
getWorkflow(workflowId: string): EffectiveWorkflow | undefined;
|
|
121
|
+
/** All workflows with effective values, sorted by ID. */
|
|
122
|
+
listWorkflows(): EffectiveWorkflow[];
|
|
123
|
+
private effective;
|
|
124
|
+
/** Effective global limit for automatic starts. */
|
|
125
|
+
get maxConcurrent(): number;
|
|
126
|
+
/** Current overrides (copies). */
|
|
127
|
+
getOverrides(): {
|
|
128
|
+
global: GlobalOverrides;
|
|
129
|
+
workflows: Record<string, WorkflowOverrides>;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Merge runtime overrides into the workflow's existing overrides. A key
|
|
133
|
+
* with value `undefined` removes that override.
|
|
134
|
+
* @throws UnknownWorkflowError, ValidationError
|
|
135
|
+
*/
|
|
136
|
+
setWorkflowOverrides(workflowId: string, overrides: WorkflowOverrides): EffectiveWorkflow;
|
|
137
|
+
/** Remove all overrides of a workflow. */
|
|
138
|
+
clearWorkflowOverrides(workflowId: string): void;
|
|
139
|
+
/**
|
|
140
|
+
* Override (number) or reset (`undefined`) the global `max_concurrent`.
|
|
141
|
+
* @throws ValidationError
|
|
142
|
+
*/
|
|
143
|
+
setGlobalMaxConcurrent(value: number | undefined): void;
|
|
144
|
+
/** Snapshot of a workflow of the active configuration (see {@link snapshotWorkflow}). */
|
|
145
|
+
snapshotWorkflow(workflowId: string): WorkflowSnapshot;
|
|
146
|
+
/**
|
|
147
|
+
* Validate manual-start parameters against the workflow's parameter schema.
|
|
148
|
+
* @throws UnknownWorkflowError
|
|
149
|
+
*/
|
|
150
|
+
validateParameters(workflowId: string, input: Readonly<Record<string, unknown>> | undefined): ParameterValidationResult;
|
|
151
|
+
}
|
|
152
|
+
/** Compare the workflows of two configurations by their hashes. */
|
|
153
|
+
export declare function diffWorkflows(previous: LoadedConfig, next: LoadedConfig): ConfigDiff;
|