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,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic validation across files (Spec §19): references, unique IDs,
|
|
3
|
+
* allowed placeholders per context, contradictions, cron/time zone and
|
|
4
|
+
* parameter defaults. Runs on the normalized model; paths in issues use the
|
|
5
|
+
* YAML key names.
|
|
6
|
+
*/
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { Cron } from 'croner';
|
|
9
|
+
import { extractPlaceholders, HOOK_NAMES, isSecretKey, validateTemplate, } from '../core/index.js';
|
|
10
|
+
import { checkFieldName, checkFilterFields } from './field-catalog.js';
|
|
11
|
+
/** Files of the top-level documents. */
|
|
12
|
+
export const CONFIG_FILE = 'config.yaml';
|
|
13
|
+
export const SOURCES_FILE = 'sources.yaml';
|
|
14
|
+
export const IDENTITIES_FILE = 'identities.yaml';
|
|
15
|
+
/** Env variable prefix reserved for the orchestrator (Spec §9.1). */
|
|
16
|
+
export const RESERVED_ENV_PREFIX = 'ADISPATCH_';
|
|
17
|
+
/** True if `tz` is a valid IANA time zone for this runtime. */
|
|
18
|
+
export function isValidTimeZone(tz) {
|
|
19
|
+
try {
|
|
20
|
+
new Intl.DateTimeFormat('en-US', { timeZone: tz });
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Validate a cron expression (croner syntax); returns an error message or `undefined`. */
|
|
28
|
+
export function cronError(expression, timezone) {
|
|
29
|
+
try {
|
|
30
|
+
const job = new Cron(expression, { paused: true, ...(timezone ? { timezone } : {}) });
|
|
31
|
+
const next = job.nextRun();
|
|
32
|
+
job.stop();
|
|
33
|
+
if (next === null)
|
|
34
|
+
return `Cron expression "${expression}" never fires`;
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return `Invalid cron expression "${expression}": ${err.message}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Run all semantic checks and add problems to `issues`. */
|
|
42
|
+
export function validateSemantics(input, issues) {
|
|
43
|
+
validateGlobal(input.global, issues);
|
|
44
|
+
validateSources(input, issues);
|
|
45
|
+
const seenWorkflows = new Map();
|
|
46
|
+
for (const entry of input.workflows) {
|
|
47
|
+
const { workflow } = entry;
|
|
48
|
+
const previous = seenWorkflows.get(workflow.id);
|
|
49
|
+
if (previous !== undefined) {
|
|
50
|
+
issues.error(workflow.file, ['id'], `Duplicate workflow ID "${workflow.id}" (already defined in ${previous})`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
seenWorkflows.set(workflow.id, workflow.file);
|
|
54
|
+
validateWorkflow(entry, input, issues);
|
|
55
|
+
}
|
|
56
|
+
const seenViews = new Map();
|
|
57
|
+
for (const entry of input.views) {
|
|
58
|
+
const previous = seenViews.get(entry.view.id);
|
|
59
|
+
if (previous !== undefined) {
|
|
60
|
+
issues.error(entry.view.file, ['id'], `Duplicate view ID "${entry.view.id}" (already defined in ${previous})`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
seenViews.set(entry.view.id, entry.view.file);
|
|
64
|
+
validateView(entry, input, issues);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function validateGlobal(global, issues) {
|
|
68
|
+
const ids = new Set();
|
|
69
|
+
global.notifications.channels.forEach((channel, i) => {
|
|
70
|
+
const at = ['notifications', 'channels', i];
|
|
71
|
+
if (ids.has(channel.id))
|
|
72
|
+
issues.error(CONFIG_FILE, [...at, 'id'], `Duplicate channel ID "${channel.id}"`);
|
|
73
|
+
ids.add(channel.id);
|
|
74
|
+
if ((channel.url === null) === (channel.urlEnv === null)) {
|
|
75
|
+
issues.error(CONFIG_FILE, at, 'Webhook channel needs exactly one of "url" or "url_env"');
|
|
76
|
+
}
|
|
77
|
+
else if (channel.url !== null && !isHttpUrl(channel.url)) {
|
|
78
|
+
// Never echo the URL: it may contain a token (Spec §18).
|
|
79
|
+
issues.error(CONFIG_FILE, [...at, 'url'], 'Webhook "url" must be an absolute http(s) URL');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function isHttpUrl(value) {
|
|
84
|
+
try {
|
|
85
|
+
const url = new URL(value);
|
|
86
|
+
return url.protocol === 'https:' || url.protocol === 'http:';
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function validateSources(input, issues) {
|
|
93
|
+
for (const source of Object.values(input.sources)) {
|
|
94
|
+
if (!input.identities[source.identity]) {
|
|
95
|
+
issues.error(SOURCES_FILE, ['sources', source.id, 'identity'], `Unknown identity "${source.identity}"`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function checkIdentity(id, input, issues, file, at) {
|
|
100
|
+
if (id && !input.identities[id])
|
|
101
|
+
issues.error(file, at, `Unknown identity "${id}"`);
|
|
102
|
+
}
|
|
103
|
+
function checkTemplate(template, mode, scope, issues, file, at) {
|
|
104
|
+
for (const issue of validateTemplate(template, { mode, scope })) {
|
|
105
|
+
issues.error(file, at, issue.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function checkEnvNames(names, issues, file, at) {
|
|
109
|
+
for (const name of names) {
|
|
110
|
+
if (name.toUpperCase().startsWith(RESERVED_ENV_PREFIX)) {
|
|
111
|
+
issues.error(file, [...at, name], `Environment variables with prefix "${RESERVED_ENV_PREFIX}" are reserved`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function checkLiteralSecrets(env, issues, file, at) {
|
|
116
|
+
for (const [name, value] of Object.entries(env)) {
|
|
117
|
+
if (value !== '' && isSecretKey(name)) {
|
|
118
|
+
issues.warning(file, [...at, name], 'Looks like a secret stored literally in YAML; use "secrets" with an identity or an environment of the service instead');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function validateWorkflow(entry, input, issues) {
|
|
123
|
+
const { workflow: wf } = entry;
|
|
124
|
+
const file = wf.file;
|
|
125
|
+
const stem = path.basename(file, path.extname(file));
|
|
126
|
+
if (stem !== wf.id) {
|
|
127
|
+
issues.warning(file, ['id'], `Workflow ID "${wf.id}" differs from file name "${path.basename(file)}"`);
|
|
128
|
+
}
|
|
129
|
+
checkIdentity(wf.identity, input, issues, file, ['identity']);
|
|
130
|
+
const isSource = wf.trigger.type === 'source';
|
|
131
|
+
if (wf.trigger.type === 'source' && !input.sources[wf.trigger.source]) {
|
|
132
|
+
issues.error(file, ['trigger', 'source'], `Unknown source "${wf.trigger.source}"`);
|
|
133
|
+
}
|
|
134
|
+
if (wf.trigger.type === 'schedule') {
|
|
135
|
+
const tzOk = isValidTimeZone(wf.trigger.timezone);
|
|
136
|
+
if (!tzOk)
|
|
137
|
+
issues.error(file, ['trigger', 'timezone'], `Invalid time zone "${wf.trigger.timezone}"`);
|
|
138
|
+
const err = cronError(wf.trigger.cron, tzOk ? wf.trigger.timezone : undefined);
|
|
139
|
+
if (err)
|
|
140
|
+
issues.error(file, ['trigger', 'cron'], err);
|
|
141
|
+
}
|
|
142
|
+
if (wf.trigger.type === 'source') {
|
|
143
|
+
const source = input.sources[wf.trigger.source];
|
|
144
|
+
if (source) {
|
|
145
|
+
const ctx = { sourceType: source.type, view: false };
|
|
146
|
+
if (wf.filter)
|
|
147
|
+
addFieldIssues(checkFilterFields(wf.filter, ctx, { listing: true }), issues, file, ['filter']);
|
|
148
|
+
wf.itemPriority?.rules.forEach((rule, i) => addFieldIssues(checkFilterFields(rule.when, ctx, { listing: false }), issues, file, ['item_priority', 'rules', i, 'when']));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!isSource) {
|
|
152
|
+
const why = `is only allowed for workflows with a source trigger (trigger is "${wf.trigger.type}")`;
|
|
153
|
+
if (wf.filter)
|
|
154
|
+
issues.error(file, ['filter'], `"filter" ${why}`);
|
|
155
|
+
if (wf.shellFilter)
|
|
156
|
+
issues.error(file, ['shell_filter'], `"shell_filter" ${why}`);
|
|
157
|
+
if (wf.itemPriority)
|
|
158
|
+
issues.error(file, ['item_priority'], `"item_priority" ${why}`);
|
|
159
|
+
if (wf.conditions.item.length > 0)
|
|
160
|
+
issues.error(file, ['conditions', 'item'], `Item conditions ${why}`);
|
|
161
|
+
}
|
|
162
|
+
// Parameters
|
|
163
|
+
const automatic = wf.trigger.type !== 'manual';
|
|
164
|
+
for (const [name, raw] of Object.entries(entry.rawParameters)) {
|
|
165
|
+
validateParameter(name, raw, automatic, issues, file);
|
|
166
|
+
}
|
|
167
|
+
const parameterNames = Object.keys(wf.parameters);
|
|
168
|
+
// Conditions: evaluated before a run exists, without manual parameters.
|
|
169
|
+
wf.conditions.workflow.forEach((c, i) => c.args.forEach((arg, j) => checkTemplate(arg, 'text', {}, issues, file, ['conditions', 'workflow', i, 'args', j])));
|
|
170
|
+
wf.conditions.item.forEach((c, i) => c.args.forEach((arg, j) => checkTemplate(arg, 'text', { source: true }, issues, file, ['conditions', 'item', i, 'args', j])));
|
|
171
|
+
wf.conditions.item.forEach((c, i) => {
|
|
172
|
+
if (c.cacheMs !== null) {
|
|
173
|
+
issues.error(file, ['conditions', 'item', i, 'cache'], '"cache" is only supported for workflow conditions');
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
// Execute
|
|
177
|
+
const exec = wf.execute;
|
|
178
|
+
const wdIssues = issues.items.length;
|
|
179
|
+
checkTemplate(exec.workingDirectory, 'path', { run: true, source: isSource, parameters: parameterNames }, issues, file, [
|
|
180
|
+
'execute',
|
|
181
|
+
'working_directory',
|
|
182
|
+
]);
|
|
183
|
+
// In path mode a parameter must always have a value: required or with default.
|
|
184
|
+
const wdPlaceholders = safePlaceholders(exec.workingDirectory);
|
|
185
|
+
for (const [name, def] of Object.entries(wf.parameters)) {
|
|
186
|
+
if (!def.required && def.default === null && wdPlaceholders.includes(`parameters.${name}`)) {
|
|
187
|
+
issues.error(file, ['execute', 'working_directory'], `Parameter "${name}" is optional without default and cannot be used in a path`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (issues.items.length === wdIssues &&
|
|
191
|
+
!exec.workingDirectory.startsWith('/') &&
|
|
192
|
+
!exec.workingDirectory.startsWith('{workspace.base_dir}')) {
|
|
193
|
+
issues.error(file, ['execute', 'working_directory'], 'Must be absolute: start with "/" or "{workspace.base_dir}"');
|
|
194
|
+
}
|
|
195
|
+
const runScope = { run: true, workspace: true, source: isSource, parameters: parameterNames };
|
|
196
|
+
exec.args.forEach((arg, i) => checkTemplate(arg, 'text', runScope, issues, file, ['execute', 'args', i]));
|
|
197
|
+
for (const [name, value] of Object.entries(exec.env)) {
|
|
198
|
+
checkTemplate(value, 'text', runScope, issues, file, ['execute', 'env', name]);
|
|
199
|
+
}
|
|
200
|
+
checkEnvNames(Object.keys(exec.env), issues, file, ['execute', 'env']);
|
|
201
|
+
checkEnvNames(Object.keys(exec.secrets), issues, file, ['execute', 'secrets']);
|
|
202
|
+
checkLiteralSecrets(exec.env, issues, file, ['execute', 'env']);
|
|
203
|
+
for (const [name, ref] of Object.entries(exec.secrets)) {
|
|
204
|
+
checkIdentity(ref.identity, input, issues, file, ['execute', 'secrets', name, 'identity']);
|
|
205
|
+
if (name in exec.env) {
|
|
206
|
+
issues.error(file, ['execute', 'secrets', name], `"${name}" is defined both in "env" and "secrets"`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const { maxDurationMs, idleTimeoutMs } = exec.timeout;
|
|
210
|
+
if (maxDurationMs !== null && idleTimeoutMs !== null && idleTimeoutMs > maxDurationMs) {
|
|
211
|
+
issues.warning(file, ['execute', 'timeout', 'idle_timeout'], '"idle_timeout" is longer than "max_duration"');
|
|
212
|
+
}
|
|
213
|
+
// Hooks
|
|
214
|
+
const actionIds = new Map();
|
|
215
|
+
for (const hook of HOOK_NAMES) {
|
|
216
|
+
wf.hooks[hook].forEach((action, i) => {
|
|
217
|
+
const at = [hook, i];
|
|
218
|
+
const where = `${hook}[${i}]`;
|
|
219
|
+
const previous = actionIds.get(action.id);
|
|
220
|
+
if (previous !== undefined) {
|
|
221
|
+
issues.error(file, [...at, 'id'], `Duplicate action ID "${action.id}" (also used at ${previous})`);
|
|
222
|
+
}
|
|
223
|
+
actionIds.set(action.id, where);
|
|
224
|
+
validateAction(action, hook, at, isSource, parameterNames, input, issues, file);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function safePlaceholders(template) {
|
|
229
|
+
try {
|
|
230
|
+
return extractPlaceholders(template);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return []; // syntax errors are reported by checkTemplate
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function validateAction(action, hook, at, isSource, parameterNames, input, issues, file) {
|
|
237
|
+
const scope = {
|
|
238
|
+
run: true,
|
|
239
|
+
workspace: true,
|
|
240
|
+
source: isSource,
|
|
241
|
+
result: hook !== 'on_start',
|
|
242
|
+
parameters: parameterNames,
|
|
243
|
+
};
|
|
244
|
+
if ((action.type === 'source.update' || action.type === 'source.comment') && !isSource) {
|
|
245
|
+
issues.error(file, [...at, 'type'], `"${action.type}" needs a source item; the workflow has no source trigger`);
|
|
246
|
+
}
|
|
247
|
+
switch (action.type) {
|
|
248
|
+
case 'source.update':
|
|
249
|
+
if (action.labels.add.length === 0 && action.labels.remove.length === 0) {
|
|
250
|
+
issues.error(file, [...at, 'labels'], '"source.update" must add or remove at least one label');
|
|
251
|
+
}
|
|
252
|
+
// Labels compare case-insensitively (GitHub, adapter): `Ready` and `ready` are the same label.
|
|
253
|
+
for (const label of action.labels.add) {
|
|
254
|
+
if (action.labels.remove.some((r) => r.toLowerCase() === label.toLowerCase())) {
|
|
255
|
+
issues.error(file, [...at, 'labels'], `Label "${label}" is both added and removed`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
case 'source.comment':
|
|
260
|
+
checkIdentity(action.identity, input, issues, file, [...at, 'identity']);
|
|
261
|
+
checkTemplate(action.message, 'text', scope, issues, file, [...at, 'message']);
|
|
262
|
+
break;
|
|
263
|
+
case 'shell':
|
|
264
|
+
action.args.forEach((arg, j) => checkTemplate(arg, 'text', scope, issues, file, [...at, 'args', j]));
|
|
265
|
+
for (const [name, value] of Object.entries(action.env)) {
|
|
266
|
+
checkTemplate(value, 'text', scope, issues, file, [...at, 'env', name]);
|
|
267
|
+
}
|
|
268
|
+
checkEnvNames(Object.keys(action.env), issues, file, [...at, 'env']);
|
|
269
|
+
checkLiteralSecrets(action.env, issues, file, [...at, 'env']);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function validateParameter(name, raw, automatic, issues, file) {
|
|
274
|
+
const at = ['parameters', name];
|
|
275
|
+
if (raw.type === 'enum' && new Set(raw.values).size !== raw.values.length) {
|
|
276
|
+
issues.error(file, [...at, 'values'], 'Enum values must be unique');
|
|
277
|
+
}
|
|
278
|
+
if (raw.default !== undefined) {
|
|
279
|
+
const def = raw.default;
|
|
280
|
+
let ok;
|
|
281
|
+
switch (raw.type) {
|
|
282
|
+
case 'string':
|
|
283
|
+
ok = typeof def === 'string';
|
|
284
|
+
break;
|
|
285
|
+
case 'number':
|
|
286
|
+
ok = typeof def === 'number' && Number.isFinite(def);
|
|
287
|
+
break;
|
|
288
|
+
case 'boolean':
|
|
289
|
+
ok = typeof def === 'boolean';
|
|
290
|
+
break;
|
|
291
|
+
case 'enum':
|
|
292
|
+
ok = typeof def === 'string' && raw.values.includes(def);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
if (!ok) {
|
|
296
|
+
const expected = raw.type === 'enum' ? `one of ${raw.values.map((v) => `"${v}"`).join(', ')}` : `a ${raw.type}`;
|
|
297
|
+
issues.error(file, [...at, 'default'], `Default does not match parameter type: expected ${expected}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else if (raw.required && automatic) {
|
|
301
|
+
issues.error(file, [...at, 'required'], 'Required parameter without default in an automatically triggered workflow: automatic runs could never supply it');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function validateView(entry, input, issues) {
|
|
305
|
+
const { view } = entry;
|
|
306
|
+
const file = view.file;
|
|
307
|
+
if (entry.hasShellFilter) {
|
|
308
|
+
issues.error(file, ['shell_filter'], 'Views do not support "shell_filter"; views never run shell scripts (Spec §17)');
|
|
309
|
+
}
|
|
310
|
+
const types = new Set();
|
|
311
|
+
view.sources.forEach((id, i) => {
|
|
312
|
+
const source = input.sources[id];
|
|
313
|
+
if (!source)
|
|
314
|
+
issues.error(file, ['sources', i], `Unknown source "${id}"`);
|
|
315
|
+
else
|
|
316
|
+
types.add(source.type);
|
|
317
|
+
});
|
|
318
|
+
if (new Set(view.sources).size !== view.sources.length) {
|
|
319
|
+
issues.error(file, ['sources'], 'Sources of a view must be unique');
|
|
320
|
+
}
|
|
321
|
+
if (types.size > 1) {
|
|
322
|
+
issues.error(file, ['sources'], `All sources of a view must have the same adapter type (found: ${[...types].join(', ')})`);
|
|
323
|
+
}
|
|
324
|
+
if (types.size === 1) {
|
|
325
|
+
const ctx = { sourceType: [...types][0], view: true };
|
|
326
|
+
if (view.filter)
|
|
327
|
+
addFieldIssues(checkFilterFields(view.filter, ctx, { listing: true }), issues, file, ['filter']);
|
|
328
|
+
const checkName = (field, at) => {
|
|
329
|
+
const message = checkFieldName(field, ctx);
|
|
330
|
+
if (message)
|
|
331
|
+
issues.error(file, at, message);
|
|
332
|
+
};
|
|
333
|
+
view.fields.forEach((f, i) => {
|
|
334
|
+
checkName(f.field, ['fields', i, 'field']);
|
|
335
|
+
if (f.link)
|
|
336
|
+
checkName(f.link, ['fields', i, 'link']);
|
|
337
|
+
});
|
|
338
|
+
if (view.sort)
|
|
339
|
+
checkName(view.sort.field, ['sort', 'field']);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function addFieldIssues(found, issues, file, at) {
|
|
343
|
+
for (const issue of found)
|
|
344
|
+
issues.error(file, [...at, ...issue.path], issue.message);
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/config/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time abstractions. All logic that must be testable reads time through a
|
|
3
|
+
* {@link Clock} and schedules delays through {@link Timers}, never via
|
|
4
|
+
* `Date.now()` / global `setTimeout` directly.
|
|
5
|
+
*/
|
|
6
|
+
/** Source of the current wall-clock time. */
|
|
7
|
+
export interface Clock {
|
|
8
|
+
/** Current time. Implementations must return a fresh `Date` instance. */
|
|
9
|
+
now(): Date;
|
|
10
|
+
}
|
|
11
|
+
/** Opaque handle returned by {@link Timers.setTimeout}. */
|
|
12
|
+
export type TimerHandle = object;
|
|
13
|
+
/** Minimal timer scheduling abstraction (injectable for tests). */
|
|
14
|
+
export interface Timers {
|
|
15
|
+
/** Schedule `callback` once after `ms` milliseconds. */
|
|
16
|
+
setTimeout(callback: () => void, ms: number): TimerHandle;
|
|
17
|
+
/** Cancel a timer; unknown or already-fired handles are ignored. */
|
|
18
|
+
clearTimeout(handle: TimerHandle): void;
|
|
19
|
+
}
|
|
20
|
+
/** Clock backed by the real system time. */
|
|
21
|
+
export declare const systemClock: Clock;
|
|
22
|
+
/** Timers backed by the Node.js event loop. */
|
|
23
|
+
export declare const systemTimers: Timers;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve after `ms` milliseconds using the given timers. Rejects with the
|
|
26
|
+
* signal's reason when `signal` is aborted before the delay elapses.
|
|
27
|
+
*/
|
|
28
|
+
export declare function sleep(timers: Timers, ms: number, signal?: AbortSignal): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Deterministic clock + timers for tests. Time only moves through
|
|
31
|
+
* {@link FakeClock.advance} / {@link FakeClock.set}; due timers fire in
|
|
32
|
+
* chronological order while advancing.
|
|
33
|
+
*/
|
|
34
|
+
export declare class FakeClock implements Clock, Timers {
|
|
35
|
+
private current;
|
|
36
|
+
private nextId;
|
|
37
|
+
private timers;
|
|
38
|
+
/** @param start initial time (Date, epoch ms or ISO string); default 2026-01-01T00:00:00Z */
|
|
39
|
+
constructor(start?: Date | number | string);
|
|
40
|
+
now(): Date;
|
|
41
|
+
/** Current time in epoch milliseconds. */
|
|
42
|
+
nowMs(): number;
|
|
43
|
+
setTimeout(callback: () => void, ms: number): TimerHandle;
|
|
44
|
+
clearTimeout(handle: TimerHandle): void;
|
|
45
|
+
/** Number of timers that have not fired yet. */
|
|
46
|
+
pendingTimers(): number;
|
|
47
|
+
/** Move time forward by `ms`, firing every timer that becomes due (in order). */
|
|
48
|
+
advance(ms: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Like {@link advance}, but yields to the microtask queue after each fired
|
|
51
|
+
* timer so that promise continuations (e.g. after {@link sleep}) can run.
|
|
52
|
+
*/
|
|
53
|
+
advanceAsync(ms: number): Promise<void>;
|
|
54
|
+
/** Jump to an absolute time. Moving backwards does not fire timers. */
|
|
55
|
+
set(time: Date | number | string): void;
|
|
56
|
+
private runUntil;
|
|
57
|
+
private nextDue;
|
|
58
|
+
private fire;
|
|
59
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time abstractions. All logic that must be testable reads time through a
|
|
3
|
+
* {@link Clock} and schedules delays through {@link Timers}, never via
|
|
4
|
+
* `Date.now()` / global `setTimeout` directly.
|
|
5
|
+
*/
|
|
6
|
+
/** Clock backed by the real system time. */
|
|
7
|
+
export const systemClock = {
|
|
8
|
+
now: () => new Date(),
|
|
9
|
+
};
|
|
10
|
+
/** Timers backed by the Node.js event loop. */
|
|
11
|
+
export const systemTimers = {
|
|
12
|
+
setTimeout: (callback, ms) => setTimeout(callback, ms),
|
|
13
|
+
clearTimeout: (handle) => clearTimeout(handle),
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Resolve after `ms` milliseconds using the given timers. Rejects with the
|
|
17
|
+
* signal's reason when `signal` is aborted before the delay elapses.
|
|
18
|
+
*/
|
|
19
|
+
export function sleep(timers, ms, signal) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
if (signal?.aborted) {
|
|
22
|
+
reject(signal.reason ?? new Error('aborted'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const onAbort = () => {
|
|
26
|
+
timers.clearTimeout(handle);
|
|
27
|
+
reject(signal?.reason ?? new Error('aborted'));
|
|
28
|
+
};
|
|
29
|
+
const handle = timers.setTimeout(() => {
|
|
30
|
+
signal?.removeEventListener('abort', onAbort);
|
|
31
|
+
resolve();
|
|
32
|
+
}, Math.max(0, ms));
|
|
33
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Deterministic clock + timers for tests. Time only moves through
|
|
38
|
+
* {@link FakeClock.advance} / {@link FakeClock.set}; due timers fire in
|
|
39
|
+
* chronological order while advancing.
|
|
40
|
+
*/
|
|
41
|
+
export class FakeClock {
|
|
42
|
+
current;
|
|
43
|
+
nextId = 1;
|
|
44
|
+
timers = [];
|
|
45
|
+
/** @param start initial time (Date, epoch ms or ISO string); default 2026-01-01T00:00:00Z */
|
|
46
|
+
constructor(start = '2026-01-01T00:00:00.000Z') {
|
|
47
|
+
this.current = new Date(start).getTime();
|
|
48
|
+
if (Number.isNaN(this.current))
|
|
49
|
+
throw new TypeError(`Invalid FakeClock start: ${String(start)}`);
|
|
50
|
+
}
|
|
51
|
+
now() {
|
|
52
|
+
return new Date(this.current);
|
|
53
|
+
}
|
|
54
|
+
/** Current time in epoch milliseconds. */
|
|
55
|
+
nowMs() {
|
|
56
|
+
return this.current;
|
|
57
|
+
}
|
|
58
|
+
setTimeout(callback, ms) {
|
|
59
|
+
const timer = { id: this.nextId++, dueAt: this.current + Math.max(0, ms), callback };
|
|
60
|
+
this.timers.push(timer);
|
|
61
|
+
return { id: timer.id };
|
|
62
|
+
}
|
|
63
|
+
clearTimeout(handle) {
|
|
64
|
+
const id = handle.id;
|
|
65
|
+
this.timers = this.timers.filter((t) => t.id !== id);
|
|
66
|
+
}
|
|
67
|
+
/** Number of timers that have not fired yet. */
|
|
68
|
+
pendingTimers() {
|
|
69
|
+
return this.timers.length;
|
|
70
|
+
}
|
|
71
|
+
/** Move time forward by `ms`, firing every timer that becomes due (in order). */
|
|
72
|
+
advance(ms) {
|
|
73
|
+
if (ms < 0)
|
|
74
|
+
throw new RangeError('FakeClock cannot move backwards via advance()');
|
|
75
|
+
this.runUntil(this.current + ms);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Like {@link advance}, but yields to the microtask queue after each fired
|
|
79
|
+
* timer so that promise continuations (e.g. after {@link sleep}) can run.
|
|
80
|
+
*/
|
|
81
|
+
async advanceAsync(ms) {
|
|
82
|
+
if (ms < 0)
|
|
83
|
+
throw new RangeError('FakeClock cannot move backwards via advanceAsync()');
|
|
84
|
+
const target = this.current + ms;
|
|
85
|
+
for (;;) {
|
|
86
|
+
const next = this.nextDue(target);
|
|
87
|
+
if (!next)
|
|
88
|
+
break;
|
|
89
|
+
this.fire(next);
|
|
90
|
+
await flushMicrotasks();
|
|
91
|
+
}
|
|
92
|
+
this.current = target;
|
|
93
|
+
await flushMicrotasks();
|
|
94
|
+
}
|
|
95
|
+
/** Jump to an absolute time. Moving backwards does not fire timers. */
|
|
96
|
+
set(time) {
|
|
97
|
+
const target = new Date(time).getTime();
|
|
98
|
+
if (Number.isNaN(target))
|
|
99
|
+
throw new TypeError(`Invalid time: ${String(time)}`);
|
|
100
|
+
if (target >= this.current)
|
|
101
|
+
this.runUntil(target);
|
|
102
|
+
else
|
|
103
|
+
this.current = target;
|
|
104
|
+
}
|
|
105
|
+
runUntil(target) {
|
|
106
|
+
for (;;) {
|
|
107
|
+
const next = this.nextDue(target);
|
|
108
|
+
if (!next)
|
|
109
|
+
break;
|
|
110
|
+
this.fire(next);
|
|
111
|
+
}
|
|
112
|
+
this.current = target;
|
|
113
|
+
}
|
|
114
|
+
nextDue(target) {
|
|
115
|
+
let next;
|
|
116
|
+
for (const t of this.timers) {
|
|
117
|
+
if (t.dueAt <= target && (!next || t.dueAt < next.dueAt || (t.dueAt === next.dueAt && t.id < next.id))) {
|
|
118
|
+
next = t;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return next;
|
|
122
|
+
}
|
|
123
|
+
fire(timer) {
|
|
124
|
+
this.timers = this.timers.filter((t) => t.id !== timer.id);
|
|
125
|
+
this.current = Math.max(this.current, timer.dueAt);
|
|
126
|
+
timer.callback();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function flushMicrotasks() {
|
|
130
|
+
for (let i = 0; i < 10; i++)
|
|
131
|
+
await Promise.resolve();
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=clock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.js","sourceRoot":"","sources":["../../src/core/clock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a duration string into milliseconds.
|
|
3
|
+
*
|
|
4
|
+
* Grammar: `<number><unit>` with unit `ms | s | m | h | d`, e.g. `100ms`, `30s`,
|
|
5
|
+
* `45m`, `6h`, `30d`, `1.5h`. Surrounding whitespace is ignored. Compound forms
|
|
6
|
+
* (`1h30m`), negative values, missing units and non-integer millisecond
|
|
7
|
+
* results are rejected with {@link ValidationError}.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseDuration(input: string): number;
|
|
10
|
+
/** Like {@link parseDuration}, but returns `undefined` instead of throwing. */
|
|
11
|
+
export declare function tryParseDuration(input: string): number | undefined;
|
|
12
|
+
/** Format milliseconds with the largest unit that divides it exactly (e.g. `90000` → `90s`). */
|
|
13
|
+
export declare function formatDuration(ms: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* Parse a size string into bytes: `<number><unit>` with unit
|
|
16
|
+
* `B | KB | MB | GB | KiB | MiB | GiB` (case-insensitive), e.g. `100MB` →
|
|
17
|
+
* 104857600. Throws {@link ValidationError} on missing/unknown units.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseSize(input: string): number;
|