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,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsers for human-friendly durations and sizes used in YAML config
|
|
3
|
+
* (e.g. `polling_interval: 30s`, `max_log_size_per_run: 100MB`).
|
|
4
|
+
*/
|
|
5
|
+
import { ValidationError } from './errors.js';
|
|
6
|
+
const DURATION_UNITS = {
|
|
7
|
+
ms: 1,
|
|
8
|
+
s: 1_000,
|
|
9
|
+
m: 60_000,
|
|
10
|
+
h: 3_600_000,
|
|
11
|
+
d: 86_400_000,
|
|
12
|
+
};
|
|
13
|
+
const DURATION_PATTERN = /^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/;
|
|
14
|
+
/**
|
|
15
|
+
* Parse a duration string into milliseconds.
|
|
16
|
+
*
|
|
17
|
+
* Grammar: `<number><unit>` with unit `ms | s | m | h | d`, e.g. `100ms`, `30s`,
|
|
18
|
+
* `45m`, `6h`, `30d`, `1.5h`. Surrounding whitespace is ignored. Compound forms
|
|
19
|
+
* (`1h30m`), negative values, missing units and non-integer millisecond
|
|
20
|
+
* results are rejected with {@link ValidationError}.
|
|
21
|
+
*/
|
|
22
|
+
export function parseDuration(input) {
|
|
23
|
+
if (typeof input !== 'string')
|
|
24
|
+
throw new ValidationError(`Duration must be a string, got ${typeof input}`);
|
|
25
|
+
const match = DURATION_PATTERN.exec(input.trim());
|
|
26
|
+
if (!match) {
|
|
27
|
+
throw new ValidationError(`Invalid duration "${input}" (expected e.g. 100ms, 30s, 45m, 6h, 30d)`, { input });
|
|
28
|
+
}
|
|
29
|
+
const value = Number(match[1]);
|
|
30
|
+
const unit = DURATION_UNITS[match[2]];
|
|
31
|
+
const ms = value * unit;
|
|
32
|
+
if (!Number.isFinite(ms) || !Number.isSafeInteger(Math.round(ms)) || Math.abs(ms - Math.round(ms)) > 1e-9) {
|
|
33
|
+
throw new ValidationError(`Duration "${input}" does not resolve to whole milliseconds`, { input });
|
|
34
|
+
}
|
|
35
|
+
return Math.round(ms);
|
|
36
|
+
}
|
|
37
|
+
/** Like {@link parseDuration}, but returns `undefined` instead of throwing. */
|
|
38
|
+
export function tryParseDuration(input) {
|
|
39
|
+
try {
|
|
40
|
+
return parseDuration(input);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Format milliseconds with the largest unit that divides it exactly (e.g. `90000` → `90s`). */
|
|
47
|
+
export function formatDuration(ms) {
|
|
48
|
+
if (!Number.isSafeInteger(ms) || ms < 0)
|
|
49
|
+
throw new ValidationError(`Cannot format duration ${ms}`);
|
|
50
|
+
if (ms === 0)
|
|
51
|
+
return '0s';
|
|
52
|
+
for (const unit of ['d', 'h', 'm', 's']) {
|
|
53
|
+
const factor = DURATION_UNITS[unit];
|
|
54
|
+
if (ms % factor === 0)
|
|
55
|
+
return `${ms / factor}${unit}`;
|
|
56
|
+
}
|
|
57
|
+
return `${ms}ms`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Size units. Decimal-looking units (`KB`, `MB`, `GB`) are interpreted as
|
|
61
|
+
* binary multiples (1 KB = 1024 B), matching common log-size conventions;
|
|
62
|
+
* `KiB`, `MiB`, `GiB` are accepted as explicit aliases.
|
|
63
|
+
*/
|
|
64
|
+
const SIZE_UNITS = {
|
|
65
|
+
b: 1,
|
|
66
|
+
kb: 1024,
|
|
67
|
+
kib: 1024,
|
|
68
|
+
mb: 1024 ** 2,
|
|
69
|
+
mib: 1024 ** 2,
|
|
70
|
+
gb: 1024 ** 3,
|
|
71
|
+
gib: 1024 ** 3,
|
|
72
|
+
};
|
|
73
|
+
const SIZE_PATTERN = /^(\d+(?:\.\d+)?)\s*([a-z]+)$/i;
|
|
74
|
+
/**
|
|
75
|
+
* Parse a size string into bytes: `<number><unit>` with unit
|
|
76
|
+
* `B | KB | MB | GB | KiB | MiB | GiB` (case-insensitive), e.g. `100MB` →
|
|
77
|
+
* 104857600. Throws {@link ValidationError} on missing/unknown units.
|
|
78
|
+
*/
|
|
79
|
+
export function parseSize(input) {
|
|
80
|
+
if (typeof input !== 'string')
|
|
81
|
+
throw new ValidationError(`Size must be a string, got ${typeof input}`);
|
|
82
|
+
const match = SIZE_PATTERN.exec(input.trim());
|
|
83
|
+
const unit = match ? SIZE_UNITS[match[2].toLowerCase()] : undefined;
|
|
84
|
+
if (!match || unit === undefined) {
|
|
85
|
+
throw new ValidationError(`Invalid size "${input}" (expected e.g. 512KB, 100MB, 1GB)`, { input });
|
|
86
|
+
}
|
|
87
|
+
const bytes = Number(match[1]) * unit;
|
|
88
|
+
if (!Number.isFinite(bytes) || !Number.isSafeInteger(Math.floor(bytes))) {
|
|
89
|
+
throw new ValidationError(`Size "${input}" is out of range`, { input });
|
|
90
|
+
}
|
|
91
|
+
return Math.floor(bytes);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=duration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.js","sourceRoot":"","sources":["../../src/core/duration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared error classes. Components throw these (or subclasses) so that callers
|
|
3
|
+
* can react on a stable `code` instead of parsing messages. Messages must
|
|
4
|
+
* never contain secrets (Spec §20.4).
|
|
5
|
+
*/
|
|
6
|
+
/** Base class for all expected orchestrator errors. */
|
|
7
|
+
export declare class OrchestratorError extends Error {
|
|
8
|
+
/** Stable machine-readable code, e.g. `template_unknown_placeholder`. */
|
|
9
|
+
readonly code: string;
|
|
10
|
+
/** Optional JSON-serialisable diagnostic details (no secrets). */
|
|
11
|
+
readonly details: Record<string, unknown> | undefined;
|
|
12
|
+
constructor(code: string, message: string, options?: {
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
details?: Record<string, unknown>;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/** Invalid input to a pure helper (duration, size, id, ...). */
|
|
18
|
+
export declare class ValidationError extends OrchestratorError {
|
|
19
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
20
|
+
}
|
|
21
|
+
/** A path would escape its permitted base directory or is otherwise unsafe. */
|
|
22
|
+
export declare class PathTraversalError extends OrchestratorError {
|
|
23
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Classification of failures talking to an external source.
|
|
27
|
+
* - `auth`: credentials invalid/expired
|
|
28
|
+
* - `forbidden`: authenticated but not permitted (fail-closed, Spec §20.7)
|
|
29
|
+
* - `not_found`: item/resource does not exist (or is invisible)
|
|
30
|
+
* - `rate_limited`: retry after `retryAfterMs`
|
|
31
|
+
* - `transient`: network/5xx; retrying may help
|
|
32
|
+
* - `invalid`: request rejected as invalid (4xx other than above)
|
|
33
|
+
*/
|
|
34
|
+
export type SourceErrorKind = 'auth' | 'forbidden' | 'not_found' | 'rate_limited' | 'transient' | 'invalid';
|
|
35
|
+
/** Error raised by {@link SourceAdapter} / {@link CredentialProvider} implementations. */
|
|
36
|
+
export declare class SourceError extends OrchestratorError {
|
|
37
|
+
readonly kind: SourceErrorKind;
|
|
38
|
+
/** Whether repeating the same call may succeed. */
|
|
39
|
+
readonly retryable: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* True when a mutating call may have taken effect although it failed
|
|
42
|
+
* (e.g. timeout after the request was sent). Lifecycle retries must then
|
|
43
|
+
* reconcile (e.g. `findCommentByMarker`) instead of blindly repeating (Spec §10).
|
|
44
|
+
*/
|
|
45
|
+
readonly outcomeUnknown: boolean;
|
|
46
|
+
/** Suggested wait before retrying, if known. */
|
|
47
|
+
readonly retryAfterMs: number | undefined;
|
|
48
|
+
/** HTTP status, if the error originated from an HTTP response. */
|
|
49
|
+
readonly status: number | undefined;
|
|
50
|
+
constructor(kind: SourceErrorKind, message: string, options?: {
|
|
51
|
+
cause?: unknown;
|
|
52
|
+
details?: Record<string, unknown>;
|
|
53
|
+
retryable?: boolean;
|
|
54
|
+
outcomeUnknown?: boolean;
|
|
55
|
+
retryAfterMs?: number;
|
|
56
|
+
status?: number;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** Narrowing helper for {@link OrchestratorError} with an optional code check. */
|
|
60
|
+
export declare function isOrchestratorError(err: unknown, code?: string): err is OrchestratorError;
|
|
61
|
+
/** Render any thrown value as a short message string (for persisting `error_json`). */
|
|
62
|
+
export declare function errorMessage(err: unknown): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared error classes. Components throw these (or subclasses) so that callers
|
|
3
|
+
* can react on a stable `code` instead of parsing messages. Messages must
|
|
4
|
+
* never contain secrets (Spec §20.4).
|
|
5
|
+
*/
|
|
6
|
+
/** Base class for all expected orchestrator errors. */
|
|
7
|
+
export class OrchestratorError extends Error {
|
|
8
|
+
/** Stable machine-readable code, e.g. `template_unknown_placeholder`. */
|
|
9
|
+
code;
|
|
10
|
+
/** Optional JSON-serialisable diagnostic details (no secrets). */
|
|
11
|
+
details;
|
|
12
|
+
constructor(code, message, options = {}) {
|
|
13
|
+
super(message, options.cause !== undefined ? { cause: options.cause } : undefined);
|
|
14
|
+
this.name = new.target.name;
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.details = options.details;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Invalid input to a pure helper (duration, size, id, ...). */
|
|
20
|
+
export class ValidationError extends OrchestratorError {
|
|
21
|
+
constructor(message, details) {
|
|
22
|
+
super('validation_error', message, details ? { details } : {});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** A path would escape its permitted base directory or is otherwise unsafe. */
|
|
26
|
+
export class PathTraversalError extends OrchestratorError {
|
|
27
|
+
constructor(message, details) {
|
|
28
|
+
super('path_traversal', message, details ? { details } : {});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Error raised by {@link SourceAdapter} / {@link CredentialProvider} implementations. */
|
|
32
|
+
export class SourceError extends OrchestratorError {
|
|
33
|
+
kind;
|
|
34
|
+
/** Whether repeating the same call may succeed. */
|
|
35
|
+
retryable;
|
|
36
|
+
/**
|
|
37
|
+
* True when a mutating call may have taken effect although it failed
|
|
38
|
+
* (e.g. timeout after the request was sent). Lifecycle retries must then
|
|
39
|
+
* reconcile (e.g. `findCommentByMarker`) instead of blindly repeating (Spec §10).
|
|
40
|
+
*/
|
|
41
|
+
outcomeUnknown;
|
|
42
|
+
/** Suggested wait before retrying, if known. */
|
|
43
|
+
retryAfterMs;
|
|
44
|
+
/** HTTP status, if the error originated from an HTTP response. */
|
|
45
|
+
status;
|
|
46
|
+
constructor(kind, message, options = {}) {
|
|
47
|
+
super(`source_${kind}`, message, options);
|
|
48
|
+
this.kind = kind;
|
|
49
|
+
this.retryable = options.retryable ?? (kind === 'transient' || kind === 'rate_limited');
|
|
50
|
+
this.outcomeUnknown = options.outcomeUnknown ?? false;
|
|
51
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
52
|
+
this.status = options.status;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Narrowing helper for {@link OrchestratorError} with an optional code check. */
|
|
56
|
+
export function isOrchestratorError(err, code) {
|
|
57
|
+
return err instanceof OrchestratorError && (code === undefined || err.code === code);
|
|
58
|
+
}
|
|
59
|
+
/** Render any thrown value as a short message string (for persisting `error_json`). */
|
|
60
|
+
export function errorMessage(err) {
|
|
61
|
+
if (err instanceof Error)
|
|
62
|
+
return err.message;
|
|
63
|
+
if (typeof err === 'string')
|
|
64
|
+
return err;
|
|
65
|
+
try {
|
|
66
|
+
return JSON.stringify(err);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return String(err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,uDAAuD;AACvD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,yEAAyE;IAChE,IAAI,CAAS;IACtB,kEAAkE;IACzD,OAAO,CAAsC;IAEtD,YAAY,IAAY,EAAE,OAAe,EAAE,OAAO,GAA2D,EAAE;QAC7G,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACjC,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,OAAO,eAAgB,SAAQ,iBAAiB;IACpD,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,kBAAkB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,OAAO,kBAAmB,SAAQ,iBAAiB;IACvD,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,gBAAgB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC;CACF;AAaD,0FAA0F;AAC1F,MAAM,OAAO,WAAY,SAAQ,iBAAiB;IACvC,IAAI,CAAkB;IAC/B,mDAAmD;IAC1C,SAAS,CAAU;IAC5B;;;;OAIG;IACM,cAAc,CAAU;IACjC,gDAAgD;IACvC,YAAY,CAAqB;IAC1C,kEAAkE;IACzD,MAAM,CAAqB;IAEpC,YACE,IAAqB,EACrB,OAAe,EACf,OAAO,GAOH,EAAE;QAEN,KAAK,CAAC,UAAU,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,cAAc,CAAC,CAAC;QACxF,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,KAAK,CAAC;QACtD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;CACF;AAED,kFAAkF;AAClF,MAAM,UAAU,mBAAmB,CAAC,GAAY,EAAE,IAAa;IAC7D,OAAO,GAAG,YAAY,iBAAiB,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACvF,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type Clock } from './clock.js';
|
|
2
|
+
/**
|
|
3
|
+
* Allowed pattern for IDs declared in YAML (workflow, source, identity, view
|
|
4
|
+
* IDs): starts with a letter or digit, then letters, digits, `_`, `-`; max 64
|
|
5
|
+
* characters. Such IDs are safe as path segments and as key prefixes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CONFIG_ID_PATTERN: RegExp;
|
|
8
|
+
/** True if `id` matches {@link CONFIG_ID_PATTERN}. */
|
|
9
|
+
export declare function isValidConfigId(id: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Format a timestamp as compact, lexicographically sortable, path-safe UTC
|
|
12
|
+
* string: `YYYYMMDDTHHMMSSZ` (or with milliseconds `YYYYMMDDTHHMMSSmmmZ`).
|
|
13
|
+
* Used for `{timestamp}` and in run IDs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatCompactTimestamp(date: Date, withMillis?: boolean): string;
|
|
16
|
+
/** Pattern of run IDs produced by {@link createRunId}. */
|
|
17
|
+
export declare const RUN_ID_PATTERN: RegExp;
|
|
18
|
+
/** Options for {@link createRunId}. */
|
|
19
|
+
export interface RunIdOptions {
|
|
20
|
+
clock?: Clock;
|
|
21
|
+
/** Source of random bytes (injectable for deterministic tests). */
|
|
22
|
+
randomBytes?: (size: number) => Uint8Array;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create a new run ID: `run-<YYYYMMDDTHHMMSSmmmZ>-<8 hex>`, e.g.
|
|
26
|
+
* `run-20261016T190000123Z-3fa2c91b`. IDs are unique (32 random bits per
|
|
27
|
+
* millisecond), sort chronologically as strings, and are safe as path segments
|
|
28
|
+
* and in URLs.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createRunId(options?: RunIdOptions): string;
|
|
31
|
+
/** True if `id` has the run ID format (see {@link createRunId}). */
|
|
32
|
+
export declare function isValidRunId(id: string): boolean;
|
|
33
|
+
/** Separator between source ID and item ID in a {@link sourceItemKey}. */
|
|
34
|
+
export declare const SOURCE_ITEM_KEY_SEPARATOR = ":";
|
|
35
|
+
/**
|
|
36
|
+
* Globally unique key of an external item across all sources (Spec §12, §17):
|
|
37
|
+
* `<sourceId>:<itemId>`, e.g. `project_a:123`. `sourceId` must be a valid
|
|
38
|
+
* config ID (therefore contains no `:`); `itemId` is adapter-defined, stable,
|
|
39
|
+
* non-empty and must not contain NUL or newlines.
|
|
40
|
+
*
|
|
41
|
+
* This key is used for locks, blocks, run history and view enrichment.
|
|
42
|
+
*/
|
|
43
|
+
export declare function sourceItemKey(sourceId: string, itemId: string): string;
|
|
44
|
+
/** Inverse of {@link sourceItemKey}. Throws {@link ValidationError} for malformed keys. */
|
|
45
|
+
export declare function parseSourceItemKey(key: string): {
|
|
46
|
+
sourceId: string;
|
|
47
|
+
itemId: string;
|
|
48
|
+
};
|
|
49
|
+
/** Prefix of comment idempotency markers. */
|
|
50
|
+
export declare const COMMENT_MARKER_PREFIX = "adispatchd";
|
|
51
|
+
/**
|
|
52
|
+
* Stable, unobtrusive idempotency marker for a lifecycle action, e.g.
|
|
53
|
+
* `adispatchd:run-20261016T190000123Z-3fa2c91b:a12`. The source adapter decides how
|
|
54
|
+
* to embed it (GitHub: HTML comment) and finds it again via
|
|
55
|
+
* `SourceAdapter.findCommentByMarker` (Spec §10).
|
|
56
|
+
*/
|
|
57
|
+
export declare function commentMarker(runId: string, actionId: string | number): string;
|
package/dist/core/ids.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifier helpers: run IDs (Spec §9), global source item keys (Spec §17),
|
|
3
|
+
* config IDs and idempotency markers for comments (Spec §10).
|
|
4
|
+
*/
|
|
5
|
+
import { randomBytes } from 'node:crypto';
|
|
6
|
+
import { systemClock } from './clock.js';
|
|
7
|
+
import { ValidationError } from './errors.js';
|
|
8
|
+
/**
|
|
9
|
+
* Allowed pattern for IDs declared in YAML (workflow, source, identity, view
|
|
10
|
+
* IDs): starts with a letter or digit, then letters, digits, `_`, `-`; max 64
|
|
11
|
+
* characters. Such IDs are safe as path segments and as key prefixes.
|
|
12
|
+
*/
|
|
13
|
+
export const CONFIG_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
14
|
+
/** True if `id` matches {@link CONFIG_ID_PATTERN}. */
|
|
15
|
+
export function isValidConfigId(id) {
|
|
16
|
+
return CONFIG_ID_PATTERN.test(id);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Format a timestamp as compact, lexicographically sortable, path-safe UTC
|
|
20
|
+
* string: `YYYYMMDDTHHMMSSZ` (or with milliseconds `YYYYMMDDTHHMMSSmmmZ`).
|
|
21
|
+
* Used for `{timestamp}` and in run IDs.
|
|
22
|
+
*/
|
|
23
|
+
export function formatCompactTimestamp(date, withMillis = false) {
|
|
24
|
+
const iso = date.toISOString(); // 2026-10-16T19:00:00.123Z
|
|
25
|
+
const base = `${iso.slice(0, 4)}${iso.slice(5, 7)}${iso.slice(8, 10)}T${iso.slice(11, 13)}${iso.slice(14, 16)}${iso.slice(17, 19)}`;
|
|
26
|
+
return withMillis ? `${base}${iso.slice(20, 23)}Z` : `${base}Z`;
|
|
27
|
+
}
|
|
28
|
+
/** Pattern of run IDs produced by {@link createRunId}. */
|
|
29
|
+
export const RUN_ID_PATTERN = /^run-\d{8}T\d{9}Z-[0-9a-f]{8}$/;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new run ID: `run-<YYYYMMDDTHHMMSSmmmZ>-<8 hex>`, e.g.
|
|
32
|
+
* `run-20261016T190000123Z-3fa2c91b`. IDs are unique (32 random bits per
|
|
33
|
+
* millisecond), sort chronologically as strings, and are safe as path segments
|
|
34
|
+
* and in URLs.
|
|
35
|
+
*/
|
|
36
|
+
export function createRunId(options = {}) {
|
|
37
|
+
const clock = options.clock ?? systemClock;
|
|
38
|
+
const rnd = (options.randomBytes ?? randomBytes)(4);
|
|
39
|
+
const hex = Buffer.from(rnd).toString('hex').padStart(8, '0').slice(0, 8);
|
|
40
|
+
return `run-${formatCompactTimestamp(clock.now(), true)}-${hex}`;
|
|
41
|
+
}
|
|
42
|
+
/** True if `id` has the run ID format (see {@link createRunId}). */
|
|
43
|
+
export function isValidRunId(id) {
|
|
44
|
+
return RUN_ID_PATTERN.test(id);
|
|
45
|
+
}
|
|
46
|
+
/** Separator between source ID and item ID in a {@link sourceItemKey}. */
|
|
47
|
+
export const SOURCE_ITEM_KEY_SEPARATOR = ':';
|
|
48
|
+
/**
|
|
49
|
+
* Globally unique key of an external item across all sources (Spec §12, §17):
|
|
50
|
+
* `<sourceId>:<itemId>`, e.g. `project_a:123`. `sourceId` must be a valid
|
|
51
|
+
* config ID (therefore contains no `:`); `itemId` is adapter-defined, stable,
|
|
52
|
+
* non-empty and must not contain NUL or newlines.
|
|
53
|
+
*
|
|
54
|
+
* This key is used for locks, blocks, run history and view enrichment.
|
|
55
|
+
*/
|
|
56
|
+
export function sourceItemKey(sourceId, itemId) {
|
|
57
|
+
if (!isValidConfigId(sourceId))
|
|
58
|
+
throw new ValidationError(`Invalid source id "${sourceId}"`, { sourceId });
|
|
59
|
+
if (itemId === '' || /[\0\r\n]/.test(itemId))
|
|
60
|
+
throw new ValidationError(`Invalid item id "${itemId}"`, { itemId });
|
|
61
|
+
return `${sourceId}${SOURCE_ITEM_KEY_SEPARATOR}${itemId}`;
|
|
62
|
+
}
|
|
63
|
+
/** Inverse of {@link sourceItemKey}. Throws {@link ValidationError} for malformed keys. */
|
|
64
|
+
export function parseSourceItemKey(key) {
|
|
65
|
+
const idx = key.indexOf(SOURCE_ITEM_KEY_SEPARATOR);
|
|
66
|
+
if (idx <= 0 || idx === key.length - 1)
|
|
67
|
+
throw new ValidationError(`Invalid source item key "${key}"`, { key });
|
|
68
|
+
const sourceId = key.slice(0, idx);
|
|
69
|
+
const itemId = key.slice(idx + 1);
|
|
70
|
+
sourceItemKey(sourceId, itemId); // validates both parts
|
|
71
|
+
return { sourceId, itemId };
|
|
72
|
+
}
|
|
73
|
+
/** Prefix of comment idempotency markers. */
|
|
74
|
+
export const COMMENT_MARKER_PREFIX = 'adispatchd';
|
|
75
|
+
/**
|
|
76
|
+
* Stable, unobtrusive idempotency marker for a lifecycle action, e.g.
|
|
77
|
+
* `adispatchd:run-20261016T190000123Z-3fa2c91b:a12`. The source adapter decides how
|
|
78
|
+
* to embed it (GitHub: HTML comment) and finds it again via
|
|
79
|
+
* `SourceAdapter.findCommentByMarker` (Spec §10).
|
|
80
|
+
*/
|
|
81
|
+
export function commentMarker(runId, actionId) {
|
|
82
|
+
const action = String(actionId);
|
|
83
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(runId) || !/^[A-Za-z0-9_.-]+$/.test(action)) {
|
|
84
|
+
throw new ValidationError('Marker parts must match [A-Za-z0-9_.-]+', { runId, actionId: action });
|
|
85
|
+
}
|
|
86
|
+
return `${COMMENT_MARKER_PREFIX}:${runId}:${action}`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/core/ids.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contracts of the orchestrator: domain types, component interfaces and
|
|
3
|
+
* small pure helpers. Other components import core only via this module.
|
|
4
|
+
*/
|
|
5
|
+
export * from './clock.js';
|
|
6
|
+
export * from './duration.js';
|
|
7
|
+
export * from './errors.js';
|
|
8
|
+
export * from './ids.js';
|
|
9
|
+
export * from './logger.js';
|
|
10
|
+
export * from './paths.js';
|
|
11
|
+
export * from './template.js';
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export * from './worker-protocol.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contracts of the orchestrator: domain types, component interfaces and
|
|
3
|
+
* small pure helpers. Other components import core only via this module.
|
|
4
|
+
*/
|
|
5
|
+
export * from './clock.js';
|
|
6
|
+
export * from './duration.js';
|
|
7
|
+
export * from './errors.js';
|
|
8
|
+
export * from './ids.js';
|
|
9
|
+
export * from './logger.js';
|
|
10
|
+
export * from './paths.js';
|
|
11
|
+
export * from './template.js';
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export * from './worker-protocol.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal structured logging with secret redaction (Spec §20.4).
|
|
3
|
+
*
|
|
4
|
+
* Log records are JSON lines: `{ time, level, msg, ...bindings, ...fields }`.
|
|
5
|
+
* Every record passes through a redaction hook before it is written, so known
|
|
6
|
+
* secret values and secret-looking keys never reach the sink.
|
|
7
|
+
*/
|
|
8
|
+
import { type Clock } from './clock.js';
|
|
9
|
+
/** Supported log levels in ascending severity. */
|
|
10
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
11
|
+
/** Structured, JSON-serialisable context attached to a log record. */
|
|
12
|
+
export type LogFields = Record<string, unknown>;
|
|
13
|
+
/** Structured logger used by all components (injected, never global). */
|
|
14
|
+
export interface Logger {
|
|
15
|
+
debug(msg: string, fields?: LogFields): void;
|
|
16
|
+
info(msg: string, fields?: LogFields): void;
|
|
17
|
+
warn(msg: string, fields?: LogFields): void;
|
|
18
|
+
error(msg: string, fields?: LogFields): void;
|
|
19
|
+
/** Derive a logger that adds `bindings` to every record (e.g. `{ component: 'scheduler' }`). */
|
|
20
|
+
child(bindings: LogFields): Logger;
|
|
21
|
+
}
|
|
22
|
+
/** Hook that removes secrets from a string. Must be pure and cheap. */
|
|
23
|
+
export type Redactor = (text: string) => string;
|
|
24
|
+
/** Replacement text for redacted values. */
|
|
25
|
+
export declare const REDACTED = "[REDACTED]";
|
|
26
|
+
/** True if values under `key` must always be redacted. */
|
|
27
|
+
export declare function isSecretKey(key: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Registry of known secret values (tokens, keys) that are replaced by
|
|
30
|
+
* {@link REDACTED} in any text passed through {@link SecretRedactor.redact}.
|
|
31
|
+
* Best-effort only: a secret that is transformed (e.g. base64) is not detected (Spec §24.8).
|
|
32
|
+
*/
|
|
33
|
+
export declare class SecretRedactor {
|
|
34
|
+
private readonly secrets;
|
|
35
|
+
/** Register a secret value. Values shorter than 4 characters are ignored. */
|
|
36
|
+
add(secret: string | undefined | null): void;
|
|
37
|
+
/** Forget a secret value (e.g. after token expiry). */
|
|
38
|
+
remove(secret: string): void;
|
|
39
|
+
/** Number of registered secrets. */
|
|
40
|
+
get size(): number;
|
|
41
|
+
/** Replace every registered secret occurring in `text`. Longest secrets are replaced first. */
|
|
42
|
+
redact(text: string): string;
|
|
43
|
+
/** The redactor as a plain function, suitable for {@link ConsoleLoggerOptions.redact}. */
|
|
44
|
+
readonly asRedactor: Redactor;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Deep-copy `value`, replacing values under secret-looking keys and applying
|
|
48
|
+
* `redact` to every string. Handles cycles and Error objects.
|
|
49
|
+
*/
|
|
50
|
+
export declare function redactValue(value: unknown, redact?: Redactor, seen?: WeakSet<object>): unknown;
|
|
51
|
+
/** Options for {@link ConsoleLogger}. */
|
|
52
|
+
export interface ConsoleLoggerOptions {
|
|
53
|
+
/** Minimum level written. Default `info`. */
|
|
54
|
+
level?: LogLevel;
|
|
55
|
+
/** Time source for the `time` field. Default {@link systemClock}. */
|
|
56
|
+
clock?: Clock;
|
|
57
|
+
/** Secret redaction hook applied to every string in the record. */
|
|
58
|
+
redact?: Redactor;
|
|
59
|
+
/** Line sink. Default writes to `process.stderr`. */
|
|
60
|
+
sink?: (line: string) => void;
|
|
61
|
+
/** Fields added to every record. */
|
|
62
|
+
bindings?: LogFields;
|
|
63
|
+
}
|
|
64
|
+
/** Logger writing one JSON object per line (default: stderr). */
|
|
65
|
+
export declare class ConsoleLogger implements Logger {
|
|
66
|
+
private readonly level;
|
|
67
|
+
private readonly clock;
|
|
68
|
+
private readonly redact;
|
|
69
|
+
private readonly sink;
|
|
70
|
+
private readonly bindings;
|
|
71
|
+
constructor(options?: ConsoleLoggerOptions);
|
|
72
|
+
debug(msg: string, fields?: LogFields): void;
|
|
73
|
+
info(msg: string, fields?: LogFields): void;
|
|
74
|
+
warn(msg: string, fields?: LogFields): void;
|
|
75
|
+
error(msg: string, fields?: LogFields): void;
|
|
76
|
+
child(bindings: LogFields): Logger;
|
|
77
|
+
private write;
|
|
78
|
+
}
|
|
79
|
+
/** A log record captured by {@link MemoryLogger}. */
|
|
80
|
+
export interface CapturedLogRecord {
|
|
81
|
+
level: LogLevel;
|
|
82
|
+
msg: string;
|
|
83
|
+
fields: LogFields;
|
|
84
|
+
}
|
|
85
|
+
/** Logger that keeps (redacted) records in memory; intended for tests. */
|
|
86
|
+
export declare class MemoryLogger implements Logger {
|
|
87
|
+
private readonly redact;
|
|
88
|
+
private readonly bindings;
|
|
89
|
+
/** Shared record list (children append to the root's list). */
|
|
90
|
+
readonly records: CapturedLogRecord[];
|
|
91
|
+
constructor(redact?: Redactor, bindings?: LogFields, records?: CapturedLogRecord[]);
|
|
92
|
+
debug(msg: string, fields?: LogFields): void;
|
|
93
|
+
info(msg: string, fields?: LogFields): void;
|
|
94
|
+
warn(msg: string, fields?: LogFields): void;
|
|
95
|
+
error(msg: string, fields?: LogFields): void;
|
|
96
|
+
child(bindings: LogFields): Logger;
|
|
97
|
+
private push;
|
|
98
|
+
}
|
|
99
|
+
/** Logger that discards everything. */
|
|
100
|
+
export declare const noopLogger: Logger;
|