@kici-dev/orchestrator 0.0.0 → 0.1.2
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 +661 -0
- package/README.md +1 -6
- package/dist/__test-helpers__/mock-db.d.ts +103 -0
- package/dist/__test-helpers__/mock-ws.d.ts +13 -0
- package/dist/agent/dispatcher.d.ts +231 -0
- package/dist/agent/ownership-tracker.d.ts +46 -0
- package/dist/agent/registry.d.ts +255 -0
- package/dist/agent/token-store.d.ts +96 -0
- package/dist/app.d.ts +234 -0
- package/dist/audit/access-log.d.ts +92 -0
- package/dist/audit/sampling-rate-limiter.d.ts +41 -0
- package/dist/cache/build-coordinator.d.ts +42 -0
- package/dist/cache/dep-cache.d.ts +51 -0
- package/dist/cache/index.d.ts +16 -0
- package/dist/cache/pending-builds.d.ts +14 -0
- package/dist/cache/pending-dynamics.d.ts +15 -0
- package/dist/cache/pending-inits.d.ts +19 -0
- package/dist/cache/pending-tracker.d.ts +65 -0
- package/dist/cache/source-cache.d.ts +30 -0
- package/dist/cli/api-client.d.ts +411 -0
- package/dist/cli/commands/access-log.d.ts +30 -0
- package/dist/cli/commands/agent-service/index.d.ts +15 -0
- package/dist/cli/commands/agent-service/install.d.ts +9 -0
- package/dist/cli/commands/agent-service/logs.d.ts +9 -0
- package/dist/cli/commands/agent-service/restart.d.ts +8 -0
- package/dist/cli/commands/agent-service/start.d.ts +8 -0
- package/dist/cli/commands/agent-service/status.d.ts +10 -0
- package/dist/cli/commands/agent-service/stop.d.ts +8 -0
- package/dist/cli/commands/agent-service/uninstall.d.ts +9 -0
- package/dist/cli/commands/agent-service/upgrade.d.ts +11 -0
- package/dist/cli/commands/agent.d.ts +10 -0
- package/dist/cli/commands/api-key.d.ts +12 -0
- package/dist/cli/commands/audit.d.ts +9 -0
- package/dist/cli/commands/backend.d.ts +17 -0
- package/dist/cli/commands/cold-store-impl.d.ts +101 -0
- package/dist/cli/commands/cold-store.d.ts +30 -0
- package/dist/cli/commands/config.d.ts +16 -0
- package/dist/cli/commands/db.d.ts +19 -0
- package/dist/cli/commands/debug-bundle.d.ts +16 -0
- package/dist/cli/commands/diagnose.d.ts +15 -0
- package/dist/cli/commands/environment.d.ts +24 -0
- package/dist/cli/commands/event-dlq.d.ts +19 -0
- package/dist/cli/commands/event-log.d.ts +27 -0
- package/dist/cli/commands/event.d.ts +4 -0
- package/dist/cli/commands/execution.d.ts +17 -0
- package/dist/cli/commands/inspect-bundle.d.ts +16 -0
- package/dist/cli/commands/maintenance.d.ts +4 -0
- package/dist/cli/commands/orchestrator-service/index.d.ts +12 -0
- package/dist/cli/commands/orchestrator-service/install.d.ts +10 -0
- package/dist/cli/commands/orchestrator-service/logs.d.ts +10 -0
- package/dist/cli/commands/orchestrator-service/restart.d.ts +8 -0
- package/dist/cli/commands/orchestrator-service/start.d.ts +8 -0
- package/dist/cli/commands/orchestrator-service/status.d.ts +10 -0
- package/dist/cli/commands/orchestrator-service/stop.d.ts +8 -0
- package/dist/cli/commands/orchestrator-service/uninstall.d.ts +9 -0
- package/dist/cli/commands/orchestrator-service/upgrade.d.ts +12 -0
- package/dist/cli/commands/org-settings.d.ts +17 -0
- package/dist/cli/commands/peer.d.ts +13 -0
- package/dist/cli/commands/queue.d.ts +16 -0
- package/dist/cli/commands/registration.d.ts +18 -0
- package/dist/cli/commands/rotate.d.ts +9 -0
- package/dist/cli/commands/runs.d.ts +34 -0
- package/dist/cli/commands/secret.d.ts +12 -0
- package/dist/cli/commands/shared/db.d.ts +16 -0
- package/dist/cli/commands/shared/versioned-upgrade.d.ts +38 -0
- package/dist/cli/commands/source.d.ts +24 -0
- package/dist/cli/commands/token.d.ts +10 -0
- package/dist/cli/commands/workflow.d.ts +31 -0
- package/dist/cli/join.d.ts +14 -0
- package/dist/cli/kici-admin.d.ts +13 -0
- package/dist/cli/lazy-deps/cache.d.ts +17 -0
- package/dist/cli/lazy-deps/downloader.d.ts +33 -0
- package/dist/cli/lazy-deps/registry.d.ts +43 -0
- package/dist/cli/service/compose.d.ts +25 -0
- package/dist/cli/service/index.d.ts +24 -0
- package/dist/cli/service/launchd.d.ts +34 -0
- package/dist/cli/service/platform-detect.d.ts +59 -0
- package/dist/cli/service/systemd.d.ts +41 -0
- package/dist/cli/service/types.d.ts +91 -0
- package/dist/cli/service/windows.d.ts +20 -0
- package/dist/cli/wizard/agent-wizard.d.ts +24 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +38 -0
- package/dist/cli/wizard/prompts.d.ts +23 -0
- package/dist/cli.js +11435 -0
- package/dist/cluster/cluster-identity.d.ts +59 -0
- package/dist/cluster/coordinator.d.ts +204 -0
- package/dist/cluster/health-api.d.ts +30 -0
- package/dist/cluster/index.d.ts +24 -0
- package/dist/cluster/join-client.d.ts +75 -0
- package/dist/cluster/join-handler.d.ts +58 -0
- package/dist/cluster/join-token.d.ts +94 -0
- package/dist/cluster/orphan-recovery.d.ts +67 -0
- package/dist/cluster/peer-client.d.ts +190 -0
- package/dist/cluster/peer-credentials.d.ts +108 -0
- package/dist/cluster/peer-crypto.d.ts +57 -0
- package/dist/cluster/peer-handler.d.ts +97 -0
- package/dist/cluster/peer-registry.d.ts +186 -0
- package/dist/cluster/raft-state.d.ts +36 -0
- package/dist/cluster/raft.d.ts +140 -0
- package/dist/cold-store/load-access-log-range.d.ts +73 -0
- package/dist/cold-store/load-event-log-range.d.ts +62 -0
- package/dist/cold-store/load-secret-audit-log-range.d.ts +38 -0
- package/dist/cold-store/orchestrator-cold-store.d.ts +58 -0
- package/dist/cold-store/tables/access-log.d.ts +80 -0
- package/dist/cold-store/tables/event-log.d.ts +70 -0
- package/dist/cold-store/tables/execution-jobs.d.ts +63 -0
- package/dist/cold-store/tables/execution-runs.d.ts +81 -0
- package/dist/cold-store/tables/execution-steps.d.ts +65 -0
- package/dist/cold-store/tables/secret-audit-log.d.ts +77 -0
- package/dist/concurrency/dispatch-next-queued.d.ts +63 -0
- package/dist/concurrency/group-tracker.d.ts +51 -0
- package/dist/concurrency/index.d.ts +3 -0
- package/dist/concurrency/queue-manager.d.ts +68 -0
- package/dist/concurrency/waiters.d.ts +58 -0
- package/dist/config/encryption.d.ts +82 -0
- package/dist/config/env-overlay.d.ts +45 -0
- package/dist/config/index.d.ts +16 -0
- package/dist/config/loader.d.ts +26 -0
- package/dist/config/reload.d.ts +113 -0
- package/dist/config/resolver.d.ts +47 -0
- package/dist/config/schema.d.ts +210 -0
- package/dist/config/shared-store.d.ts +142 -0
- package/dist/config/types.d.ts +218 -0
- package/dist/config.d.ts +249 -0
- package/dist/cron/cron-scheduler.d.ts +78 -0
- package/dist/cron/cron-store.d.ts +38 -0
- package/dist/dashboard/handler.d.ts +243 -0
- package/dist/db/client.d.ts +13 -0
- package/dist/db/migration-provider.d.ts +9 -0
- package/dist/db/migrations/001_initial.d.ts +8 -0
- package/dist/db/migrations/002_config_versions_key_version.d.ts +16 -0
- package/dist/db/migrations/003_access_log.d.ts +26 -0
- package/dist/db/migrations/004_rename_bundle_to_source.d.ts +19 -0
- package/dist/db/migrations/005_cold_store_chunk_counter.d.ts +19 -0
- package/dist/db/migrations/006_runs_jobs_steps_archived_at.d.ts +38 -0
- package/dist/db/migrations/007_audit_logs_archived_at.d.ts +42 -0
- package/dist/db/migrations/008_event_log_archived_at.d.ts +40 -0
- package/dist/db/migrations/009_access_log_trigram.d.ts +15 -0
- package/dist/db/migrations/010_cold_store_chunks.d.ts +34 -0
- package/dist/db/migrations/011_drop_source_secrets_notify.d.ts +21 -0
- package/dist/db/migrations/012_peer_credentials_active_uniq.d.ts +28 -0
- package/dist/db/migrations/013_execution_log_bytes.d.ts +21 -0
- package/dist/db/migrations/014_kici_events_lease_retry.d.ts +36 -0
- package/dist/db/migrations/015_org_settings_customer_scoped.d.ts +30 -0
- package/dist/db/migrations/016_org_settings_allow_http_npm.d.ts +15 -0
- package/dist/db/migrations/017_org_id_widen.d.ts +4 -0
- package/dist/db/migrations/018_org_id_prefix_backfill.d.ts +4 -0
- package/dist/db/migrator.d.ts +32 -0
- package/dist/db/types.d.ts +1266 -0
- package/dist/diagnostics/bundle-reader.d.ts +48 -0
- package/dist/diagnostics/bundle-writer.d.ts +57 -0
- package/dist/diagnostics/checks/agents.d.ts +10 -0
- package/dist/diagnostics/checks/certs.d.ts +9 -0
- package/dist/diagnostics/checks/config.d.ts +10 -0
- package/dist/diagnostics/checks/db.d.ts +9 -0
- package/dist/diagnostics/checks/disk.d.ts +9 -0
- package/dist/diagnostics/checks/index.d.ts +17 -0
- package/dist/diagnostics/checks/ws.d.ts +9 -0
- package/dist/diagnostics/index.d.ts +13 -0
- package/dist/diagnostics/runner.d.ts +23 -0
- package/dist/diagnostics/types.d.ts +38 -0
- package/dist/entry-helpers.d.ts +93 -0
- package/dist/environments/binding-store.d.ts +27 -0
- package/dist/environments/environment-store.d.ts +74 -0
- package/dist/environments/held-runs.d.ts +64 -0
- package/dist/environments/index.d.ts +10 -0
- package/dist/environments/protection/branch-gate.d.ts +5 -0
- package/dist/environments/protection/concurrency-gate.d.ts +7 -0
- package/dist/environments/protection/pipeline.d.ts +18 -0
- package/dist/environments/protection/reviewer-gate.d.ts +7 -0
- package/dist/environments/protection/trust-gate.d.ts +7 -0
- package/dist/environments/protection/wait-timer-gate.d.ts +7 -0
- package/dist/environments/variable-store.d.ts +39 -0
- package/dist/events/circuit-breaker.d.ts +33 -0
- package/dist/events/event-emitter.d.ts +55 -0
- package/dist/events/event-retry-scanner.d.ts +52 -0
- package/dist/events/event-router.d.ts +183 -0
- package/dist/events/event-store.d.ts +157 -0
- package/dist/events/trust-store.d.ts +54 -0
- package/dist/events/types.d.ts +61 -0
- package/dist/helpers/ip-extraction.d.ts +29 -0
- package/dist/helpers/rate-limiter.d.ts +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +772 -0
- package/dist/lockfile-cache.d.ts +39 -0
- package/dist/metrics/agent-metrics-aggregator.d.ts +116 -0
- package/dist/metrics/metrics-reporter.d.ts +40 -0
- package/dist/metrics/prometheus.d.ts +261 -0
- package/dist/metrics/scheduled-jobs.d.ts +20 -0
- package/dist/orchestrator-core.d.ts +193 -0
- package/dist/pipeline/dispatch-matched-workflow.d.ts +102 -0
- package/dist/pipeline/inline-eval.d.ts +28 -0
- package/dist/pipeline/install-secrets-resolver.d.ts +73 -0
- package/dist/pipeline/manual-schedule.d.ts +21 -0
- package/dist/pipeline/needs-scheduler.d.ts +85 -0
- package/dist/pipeline/process-webhook.d.ts +38 -0
- package/dist/pipeline/processor.d.ts +326 -0
- package/dist/pipeline/rerun.d.ts +79 -0
- package/dist/pipeline/test-pipeline.d.ts +110 -0
- package/dist/provider-registry.d.ts +122 -0
- package/dist/providers/generic/index.d.ts +23 -0
- package/dist/providers/generic/normalizer.d.ts +112 -0
- package/dist/providers/generic/verification.d.ts +47 -0
- package/dist/providers/github/auth.d.ts +60 -0
- package/dist/providers/github/changed-files.d.ts +51 -0
- package/dist/providers/github/check-status-poster.d.ts +35 -0
- package/dist/providers/github/contributor-resolver.d.ts +30 -0
- package/dist/providers/github/index.d.ts +20 -0
- package/dist/providers/github/lock-file.d.ts +32 -0
- package/dist/providers/github/normalizer.d.ts +103 -0
- package/dist/providers/github/repo-url.d.ts +35 -0
- package/dist/providers/internal/index.d.ts +32 -0
- package/dist/providers/internal/lock-file-fetcher.d.ts +34 -0
- package/dist/providers/internal/normalizer.d.ts +89 -0
- package/dist/providers/internal/repo-url-builder.d.ts +42 -0
- package/dist/providers/universal-git/changed-files.d.ts +42 -0
- package/dist/providers/universal-git/clone-token.d.ts +83 -0
- package/dist/providers/universal-git/config.d.ts +192 -0
- package/dist/providers/universal-git/index.d.ts +55 -0
- package/dist/providers/universal-git/lock-file.d.ts +71 -0
- package/dist/providers/universal-git/normalizer.d.ts +90 -0
- package/dist/providers/universal-git/repo-url.d.ts +50 -0
- package/dist/providers/universal-git/ssh-auth.d.ts +94 -0
- package/dist/queue/bootstrap.d.ts +50 -0
- package/dist/queue/cleanup.d.ts +41 -0
- package/dist/queue/depth-refresher.d.ts +65 -0
- package/dist/queue/job-queue.d.ts +343 -0
- package/dist/queue/scheduled-job.d.ts +91 -0
- package/dist/registration/extractor.d.ts +44 -0
- package/dist/registration/registration-index.d.ts +162 -0
- package/dist/registration/registration-store.d.ts +111 -0
- package/dist/reporting/check-run-summary.d.ts +102 -0
- package/dist/reporting/commit-status.d.ts +382 -0
- package/dist/reporting/execution-tracker.d.ts +538 -0
- package/dist/reporting/fs-log-storage.d.ts +41 -0
- package/dist/reporting/log-pull-handler.d.ts +35 -0
- package/dist/reporting/log-storage.d.ts +70 -0
- package/dist/reporting/log-writer.d.ts +45 -0
- package/dist/reporting/s3-log-storage.d.ts +42 -0
- package/dist/reporting/step-log-buffer.d.ts +57 -0
- package/dist/routes/admin-access-log.d.ts +34 -0
- package/dist/routes/admin-backends.d.ts +28 -0
- package/dist/routes/admin-config.d.ts +57 -0
- package/dist/routes/admin-db.d.ts +20 -0
- package/dist/routes/admin-environments.d.ts +42 -0
- package/dist/routes/admin-errors.d.ts +4 -0
- package/dist/routes/admin-event-dlq.d.ts +39 -0
- package/dist/routes/admin-event-log.d.ts +42 -0
- package/dist/routes/admin-events.d.ts +46 -0
- package/dist/routes/admin-maintenance.d.ts +22 -0
- package/dist/routes/admin-org-settings.d.ts +29 -0
- package/dist/routes/admin-queue-execution.d.ts +27 -0
- package/dist/routes/admin-registrations.d.ts +37 -0
- package/dist/routes/admin-runs.d.ts +57 -0
- package/dist/routes/admin-scheduled-jobs.d.ts +36 -0
- package/dist/routes/admin-sources.d.ts +18 -0
- package/dist/routes/admin.d.ts +103 -0
- package/dist/routes/capabilities.d.ts +24 -0
- package/dist/routes/diagnostics.d.ts +16 -0
- package/dist/routes/health.d.ts +20 -0
- package/dist/routes/test-trigger.d.ts +41 -0
- package/dist/routes/uploads.d.ts +38 -0
- package/dist/routes/webhooks.d.ts +36 -0
- package/dist/scaler/bare-metal-backend.d.ts +107 -0
- package/dist/scaler/config.d.ts +303 -0
- package/dist/scaler/container-backend.d.ts +125 -0
- package/dist/scaler/file-tail.d.ts +23 -0
- package/dist/scaler/firecracker-api.d.ts +100 -0
- package/dist/scaler/firecracker-backend.d.ts +263 -0
- package/dist/scaler/index.d.ts +24 -0
- package/dist/scaler/ip-allocator.d.ts +177 -0
- package/dist/scaler/label-matcher.d.ts +73 -0
- package/dist/scaler/log-forwarder.d.ts +54 -0
- package/dist/scaler/machine-ledger.d.ts +160 -0
- package/dist/scaler/manager.d.ts +338 -0
- package/dist/scaler/nftables.d.ts +85 -0
- package/dist/scaler/types.d.ts +388 -0
- package/dist/scaler/warm-pool.d.ts +81 -0
- package/dist/secrets/audit-logger.d.ts +65 -0
- package/dist/secrets/backend-health.d.ts +60 -0
- package/dist/secrets/backend-registry.d.ts +68 -0
- package/dist/secrets/backend-sync.d.ts +40 -0
- package/dist/secrets/cleanup.d.ts +40 -0
- package/dist/secrets/config.d.ts +51 -0
- package/dist/secrets/crypto.d.ts +49 -0
- package/dist/secrets/ephemeral-keys.d.ts +49 -0
- package/dist/secrets/index.d.ts +17 -0
- package/dist/secrets/pg-secret-store.d.ts +105 -0
- package/dist/secrets/rbac.d.ts +47 -0
- package/dist/secrets/secret-output-store.d.ts +46 -0
- package/dist/secrets/secret-resolver.d.ts +137 -0
- package/dist/secrets/source-credentials.d.ts +61 -0
- package/dist/secrets/token-manager.d.ts +63 -0
- package/dist/secrets/vault-secret-store.d.ts +85 -0
- package/dist/security/comment-handler.d.ts +67 -0
- package/dist/security/contributor-cache.d.ts +75 -0
- package/dist/security/global-workflow-policy.d.ts +72 -0
- package/dist/security/lock-source.d.ts +34 -0
- package/dist/security/trust-resolver.d.ts +108 -0
- package/dist/security/workflow-diff.d.ts +26 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +48055 -0
- package/dist/sources/index.d.ts +10 -0
- package/dist/sources/source-manager.d.ts +63 -0
- package/dist/sources/source-store.d.ts +79 -0
- package/dist/sources/source-validator.d.ts +16 -0
- package/dist/stale-detector/stale-run-detector.d.ts +109 -0
- package/dist/standalone.d.ts +20 -0
- package/dist/standalone.js +41546 -0
- package/dist/storage/blob-routes.d.ts +20 -0
- package/dist/storage/filesystem.d.ts +60 -0
- package/dist/storage/index.d.ts +20 -0
- package/dist/storage/s3.d.ts +68 -0
- package/dist/storage/sign-url.d.ts +45 -0
- package/dist/storage/types.d.ts +98 -0
- package/dist/webhook/dedup.d.ts +44 -0
- package/dist/webhook/event-log.d.ts +83 -0
- package/dist/webhook/generic-sources.d.ts +169 -0
- package/dist/webhook/handler.d.ts +23 -0
- package/dist/webhook/relay-buffer.d.ts +96 -0
- package/dist/webhook/verify-inbound.d.ts +78 -0
- package/dist/worker/in-memory-execution-tracker.d.ts +94 -0
- package/dist/worker/in-memory-job-queue.d.ts +74 -0
- package/dist/worker/static-agent-token-store.d.ts +58 -0
- package/dist/worker/worker-status.d.ts +36 -0
- package/dist/worker-core.d.ts +74 -0
- package/dist/ws/agent-api-registry.d.ts +49 -0
- package/dist/ws/agent-handler.d.ts +176 -0
- package/dist/ws/agent-heartbeat.d.ts +45 -0
- package/dist/ws/dashboard-backends-handler.d.ts +51 -0
- package/dist/ws/dashboard-diagnostics-handler.d.ts +56 -0
- package/dist/ws/dashboard-env-handler.d.ts +107 -0
- package/dist/ws/dashboard-global-workflows-handler.d.ts +72 -0
- package/dist/ws/dashboard-registrations-handler.d.ts +84 -0
- package/dist/ws/event-buffer.d.ts +16 -0
- package/dist/ws/observer-handler.d.ts +42 -0
- package/dist/ws/observer-registry.d.ts +88 -0
- package/dist/ws/platform-client.d.ts +270 -0
- package/dist/ws/server-options.d.ts +15 -0
- package/package.json +87 -7
- package/sbom.spdx.json +14370 -0
- package/index.js +0 -3
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared mock Kysely database builder for orchestrator tests.
|
|
3
|
+
*
|
|
4
|
+
* Provides a configurable `createMockDb()` that constructs a chainable
|
|
5
|
+
* mock supporting the common query patterns used by the orchestrator:
|
|
6
|
+
*
|
|
7
|
+
* - selectFrom().selectAll().where()...execute() / executeTakeFirst()
|
|
8
|
+
* - selectFrom().select().where()...execute() / executeTakeFirst() / executeTakeFirstOrThrow()
|
|
9
|
+
* - insertInto().values().execute() / returning().executeTakeFirstOrThrow()
|
|
10
|
+
* - insertInto().values().onConflict(cb).execute()
|
|
11
|
+
* - insertInto().values().returningAll().executeTakeFirstOrThrow()
|
|
12
|
+
* - updateTable().set().where()...execute() / executeTakeFirst()
|
|
13
|
+
* - deleteFrom().where()...execute() / executeTakeFirst()
|
|
14
|
+
* - transaction().execute(async (trx) => { ... })
|
|
15
|
+
*
|
|
16
|
+
* Each test can configure return values via options and access the
|
|
17
|
+
* underlying vi.fn() mocks for assertions via the `mocks` property.
|
|
18
|
+
*/
|
|
19
|
+
import { vi } from 'vitest';
|
|
20
|
+
export interface MockDbOptions {
|
|
21
|
+
/** Rows returned by selectAll/select chains ending in .execute(). Default: [] */
|
|
22
|
+
selectRows?: unknown[];
|
|
23
|
+
/** Row returned by select chains ending in .executeTakeFirst(). Default: undefined */
|
|
24
|
+
selectFirstRow?: unknown | undefined;
|
|
25
|
+
/** Row returned by insert chains ending in .returningAll().executeTakeFirstOrThrow(). Default: { id: 'mock-id' } */
|
|
26
|
+
insertedRow?: unknown;
|
|
27
|
+
/** Row returned by insert chains ending in .returning().executeTakeFirstOrThrow(). Default: { id: 'mock-id' } */
|
|
28
|
+
insertReturning?: unknown;
|
|
29
|
+
/** Row returned by update chains ending in .returningAll().executeTakeFirstOrThrow() or executeTakeFirst(). Default: undefined */
|
|
30
|
+
updatedRow?: unknown;
|
|
31
|
+
/** Result for update .execute() calls. Default: { numUpdatedRows: 0n } */
|
|
32
|
+
updateResult?: {
|
|
33
|
+
numUpdatedRows: bigint;
|
|
34
|
+
};
|
|
35
|
+
/** Result for delete .executeTakeFirst() calls. Default: { numDeletedRows: 0n } */
|
|
36
|
+
deleteResult?: {
|
|
37
|
+
numDeletedRows: bigint;
|
|
38
|
+
};
|
|
39
|
+
/** Result for count queries (fn.countAll). Default: { count: 0 } */
|
|
40
|
+
countResult?: {
|
|
41
|
+
count: number;
|
|
42
|
+
};
|
|
43
|
+
/** Result for insert chains ending in .executeTakeFirst(). Default: undefined */
|
|
44
|
+
insertResult?: {
|
|
45
|
+
numInsertedOrUpdatedRows: bigint;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export interface MockDb {
|
|
49
|
+
db: any;
|
|
50
|
+
mocks: MockDbMocks;
|
|
51
|
+
}
|
|
52
|
+
export interface MockDbMocks {
|
|
53
|
+
selectFrom: ReturnType<typeof vi.fn>;
|
|
54
|
+
selectAll: ReturnType<typeof vi.fn>;
|
|
55
|
+
select: ReturnType<typeof vi.fn>;
|
|
56
|
+
selectWhere: ReturnType<typeof vi.fn>;
|
|
57
|
+
selectOrderBy: ReturnType<typeof vi.fn>;
|
|
58
|
+
selectLimit: ReturnType<typeof vi.fn>;
|
|
59
|
+
selectExecute: ReturnType<typeof vi.fn>;
|
|
60
|
+
selectExecuteTakeFirst: ReturnType<typeof vi.fn>;
|
|
61
|
+
selectExecuteTakeFirstOrThrow: ReturnType<typeof vi.fn>;
|
|
62
|
+
selectForUpdate: ReturnType<typeof vi.fn>;
|
|
63
|
+
selectSkipLocked: ReturnType<typeof vi.fn>;
|
|
64
|
+
insertInto: ReturnType<typeof vi.fn>;
|
|
65
|
+
insertValues: ReturnType<typeof vi.fn>;
|
|
66
|
+
insertReturning: ReturnType<typeof vi.fn>;
|
|
67
|
+
insertReturningAll: ReturnType<typeof vi.fn>;
|
|
68
|
+
insertExecute: ReturnType<typeof vi.fn>;
|
|
69
|
+
insertExecuteTakeFirstOrThrow: ReturnType<typeof vi.fn>;
|
|
70
|
+
onConflict: ReturnType<typeof vi.fn>;
|
|
71
|
+
updateTable: ReturnType<typeof vi.fn>;
|
|
72
|
+
updateSet: ReturnType<typeof vi.fn>;
|
|
73
|
+
updateWhere: ReturnType<typeof vi.fn>;
|
|
74
|
+
updateReturningAll: ReturnType<typeof vi.fn>;
|
|
75
|
+
updateExecute: ReturnType<typeof vi.fn>;
|
|
76
|
+
updateExecuteTakeFirst: ReturnType<typeof vi.fn>;
|
|
77
|
+
updateExecuteTakeFirstOrThrow: ReturnType<typeof vi.fn>;
|
|
78
|
+
deleteFrom: ReturnType<typeof vi.fn>;
|
|
79
|
+
deleteWhere: ReturnType<typeof vi.fn>;
|
|
80
|
+
deleteExecute: ReturnType<typeof vi.fn>;
|
|
81
|
+
deleteExecuteTakeFirst: ReturnType<typeof vi.fn>;
|
|
82
|
+
transaction: ReturnType<typeof vi.fn>;
|
|
83
|
+
transactionExecute: ReturnType<typeof vi.fn>;
|
|
84
|
+
countAll: ReturnType<typeof vi.fn>;
|
|
85
|
+
countAs: ReturnType<typeof vi.fn>;
|
|
86
|
+
countExecuteTakeFirst: ReturnType<typeof vi.fn>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Create a mock Kysely DB instance for orchestrator unit tests.
|
|
90
|
+
*
|
|
91
|
+
* All query chains are fully wired and return sensible defaults.
|
|
92
|
+
* Override specific return values via the `options` parameter.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const { db, mocks } = createMockDb({ selectRows: [row1, row2] });
|
|
97
|
+
* const store = new SomeStore(db);
|
|
98
|
+
* await store.list();
|
|
99
|
+
* expect(mocks.selectFrom).toHaveBeenCalledWith('my_table');
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function createMockDb(options?: MockDbOptions): MockDb;
|
|
103
|
+
//# sourceMappingURL=mock-db.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WsLike } from '../agent/registry.js';
|
|
2
|
+
import type { ObserverWsLike } from '../ws/observer-registry.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create a mock WsLike with vi.fn() spies on send/close.
|
|
5
|
+
* Used across agent registry, dispatcher, heartbeat, and WS handler tests.
|
|
6
|
+
*/
|
|
7
|
+
export declare function mockWs(): WsLike;
|
|
8
|
+
/**
|
|
9
|
+
* Create a mock ObserverWsLike with vi.fn() spies on send/close.
|
|
10
|
+
* Used by observer-registry tests.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mockObserverWs(): ObserverWsLike;
|
|
13
|
+
//# sourceMappingURL=mock-ws.d.ts.map
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import type { AgentRegistry } from './registry.js';
|
|
2
|
+
import { type JobQueue, type QueuedJob, type QueuedJobInput } from '../queue/job-queue.js';
|
|
3
|
+
import type { ScaleResult } from '../scaler/types.js';
|
|
4
|
+
import type { ResourceRequest } from '@kici-dev/engine';
|
|
5
|
+
/**
|
|
6
|
+
* Metrics interface for dispatch operations.
|
|
7
|
+
* Allows the dispatcher to update Prometheus counters without
|
|
8
|
+
* directly importing the metrics module (dependency injection).
|
|
9
|
+
*/
|
|
10
|
+
export interface DispatchMetrics {
|
|
11
|
+
/** Increment the jobs dispatched counter by status. */
|
|
12
|
+
incJobsDispatched(status: 'dispatched' | 'queued' | 'rejected'): void;
|
|
13
|
+
/** Set the queue depth gauge. */
|
|
14
|
+
setQueueDepth(depth: number): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of a dispatch attempt.
|
|
18
|
+
*/
|
|
19
|
+
type DispatchResult = {
|
|
20
|
+
status: 'dispatched';
|
|
21
|
+
agentId: string;
|
|
22
|
+
jobId: string;
|
|
23
|
+
} | {
|
|
24
|
+
status: 'queued';
|
|
25
|
+
jobId: string;
|
|
26
|
+
} | {
|
|
27
|
+
status: 'queued-no-backend';
|
|
28
|
+
jobId: string;
|
|
29
|
+
} | {
|
|
30
|
+
status: 'rejected';
|
|
31
|
+
reason: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Dispatch coordinator connecting the agent registry and job queue.
|
|
35
|
+
*
|
|
36
|
+
* Routes incoming jobs to matching agents based on label requirements,
|
|
37
|
+
* falling back to the persistent queue when no agent is available.
|
|
38
|
+
* Handles agent lifecycle events (connect, disconnect, job completion).
|
|
39
|
+
*
|
|
40
|
+
* The dispatcher does NOT directly access WebSocket connections --
|
|
41
|
+
* it uses the onDispatch callback provided at construction. The caller
|
|
42
|
+
* (app.ts or server.ts) provides an onDispatch that looks up the agent's
|
|
43
|
+
* WS from the registry and sends the job.dispatch message.
|
|
44
|
+
*/
|
|
45
|
+
export declare class Dispatcher {
|
|
46
|
+
private readonly registry;
|
|
47
|
+
private readonly queue;
|
|
48
|
+
private readonly metrics;
|
|
49
|
+
private readonly onDispatch;
|
|
50
|
+
private readonly onNoMatchingAgent?;
|
|
51
|
+
/**
|
|
52
|
+
* Tracks which jobs are dispatched to which agents.
|
|
53
|
+
* Used for marking jobs as failed on agent disconnect.
|
|
54
|
+
*/
|
|
55
|
+
private readonly agentJobs;
|
|
56
|
+
/** Reverse map: jobId -> agentId, for cancel-run lookups. */
|
|
57
|
+
private readonly jobToAgent;
|
|
58
|
+
/**
|
|
59
|
+
* Grace window for recently completed jobs.
|
|
60
|
+
* Allows late messages (log.chunk, step.status) to be accepted for a short
|
|
61
|
+
* period after job completion, preventing false ownership violations.
|
|
62
|
+
*/
|
|
63
|
+
private readonly completedJobs;
|
|
64
|
+
/** Cap on completedJobs map to prevent unbounded growth. */
|
|
65
|
+
private static readonly COMPLETED_JOBS_CAP;
|
|
66
|
+
/** Grace window duration in milliseconds (30 seconds). */
|
|
67
|
+
private static readonly GRACE_WINDOW_MS;
|
|
68
|
+
/** Interval for cleaning up expired grace window entries (10 seconds). */
|
|
69
|
+
private static readonly GRACE_CLEANUP_INTERVAL_MS;
|
|
70
|
+
/** Timer for periodic grace cleanup. */
|
|
71
|
+
private graceCleanupTimer;
|
|
72
|
+
/** Max reconnection delay from agent config, used to derive grace period. */
|
|
73
|
+
private readonly maxReconnectDelayMs;
|
|
74
|
+
/** Callback when a recovery timer expires and the job is permanently failed. */
|
|
75
|
+
private readonly onRecoveryTimeout?;
|
|
76
|
+
/** Callback when a job enters recovery (starts timer). */
|
|
77
|
+
private readonly onRecoveryStarted?;
|
|
78
|
+
/**
|
|
79
|
+
* Per-job recovery timers for jobs in 'recovering' state.
|
|
80
|
+
* When an agent disconnects with in-flight jobs, each job gets a timer.
|
|
81
|
+
* If the agent reconnects before the timer fires, the timer is cancelled.
|
|
82
|
+
*/
|
|
83
|
+
private readonly recoveringJobs;
|
|
84
|
+
/** Grace period = 2x max reconnection delay. */
|
|
85
|
+
private get gracePeriodMs();
|
|
86
|
+
constructor(deps: {
|
|
87
|
+
registry: AgentRegistry;
|
|
88
|
+
queue: JobQueue;
|
|
89
|
+
metrics: DispatchMetrics;
|
|
90
|
+
onDispatch: (agentId: string, job: QueuedJob) => void | Promise<void>;
|
|
91
|
+
/** Optional hook called when no agent matches the job's labels.
|
|
92
|
+
* When set, receives the per-job `resources` so the scaler can apply
|
|
93
|
+
* per-scaler / per-orchestrator / per-machine caps before spawning. */
|
|
94
|
+
onNoMatchingAgent?: (labels: string[], jobId: string, excludeLabels: string[], resources?: ResourceRequest) => Promise<ScaleResult>;
|
|
95
|
+
/** Max reconnection delay from agent config (default 60s). Used to derive grace period. */
|
|
96
|
+
maxReconnectDelayMs?: number;
|
|
97
|
+
/** Callback when a recovery timer expires and the job is permanently failed. */
|
|
98
|
+
onRecoveryTimeout?: (agentId: string, jobId: string, runId: string) => void;
|
|
99
|
+
/** Callback when a job enters recovery (starts timer). */
|
|
100
|
+
onRecoveryStarted?: (agentId: string, jobId: string) => void;
|
|
101
|
+
});
|
|
102
|
+
/**
|
|
103
|
+
* Dispatch a job to a matching agent, or queue it if none available.
|
|
104
|
+
*
|
|
105
|
+
* Flow:
|
|
106
|
+
* 1. Find available agents matching job's runsOnLabels.
|
|
107
|
+
* 2. If agent found: increment activeJobs, call onDispatch, return 'dispatched'.
|
|
108
|
+
* 3. If no agent: enqueue in queue, return 'queued'.
|
|
109
|
+
* 4. If queue full: return 'rejected'.
|
|
110
|
+
*/
|
|
111
|
+
dispatch(job: QueuedJobInput): Promise<DispatchResult>;
|
|
112
|
+
/**
|
|
113
|
+
* Eagerly dispatch a specific bound job to a freshly-registered
|
|
114
|
+
* scaler-managed agent.
|
|
115
|
+
*
|
|
116
|
+
* Called by the agent-handler immediately after a scaler-managed agent
|
|
117
|
+
* registers, when the scaler had bound a queued jobId to that agent at
|
|
118
|
+
* spawn time. Atomically claims the job from the queue (validating it's
|
|
119
|
+
* still pending and the agent's labels still satisfy it), marks it
|
|
120
|
+
* dispatched, and sends it to the agent.
|
|
121
|
+
*
|
|
122
|
+
* Returns true if dispatched, false if the bound job was already claimed
|
|
123
|
+
* elsewhere, expired, or the agent isn't registered. The caller falls
|
|
124
|
+
* back to the generic onAgentAvailable() drain in either case.
|
|
125
|
+
*/
|
|
126
|
+
dispatchBoundJob(agentId: string, jobId: string): Promise<boolean>;
|
|
127
|
+
/**
|
|
128
|
+
* Try draining the queue for a specific agent.
|
|
129
|
+
* Called when an agent registers or completes a job.
|
|
130
|
+
*
|
|
131
|
+
* Dequeues matching jobs from the queue while the agent has capacity,
|
|
132
|
+
* calling onDispatch for each.
|
|
133
|
+
*/
|
|
134
|
+
onAgentAvailable(agentId: string): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Handle agent disconnect. Starts per-job recovery timers instead of
|
|
137
|
+
* immediately failing jobs, giving the agent a grace period to reconnect.
|
|
138
|
+
* If no in-flight jobs, performs a clean disconnect.
|
|
139
|
+
*
|
|
140
|
+
* Returns empty array (no immediately failed jobs -- failures happen
|
|
141
|
+
* asynchronously when recovery timers expire).
|
|
142
|
+
*/
|
|
143
|
+
onAgentDisconnect(agentId: string): Promise<string[]>;
|
|
144
|
+
/**
|
|
145
|
+
* Called when an agent completes a job (success or failure).
|
|
146
|
+
* Decrements active jobs and moves the job to the grace window
|
|
147
|
+
* (instead of immediately removing it) so that late messages
|
|
148
|
+
* (e.g. final log chunks) are still accepted.
|
|
149
|
+
*/
|
|
150
|
+
onJobComplete(agentId: string, jobId: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Check if a job is owned by the given agent.
|
|
153
|
+
* Returns true if the job is actively dispatched to the agent,
|
|
154
|
+
* in recovery (agent disconnected but within grace period),
|
|
155
|
+
* or in the grace window (completed within the last 30 seconds).
|
|
156
|
+
*/
|
|
157
|
+
isJobOwnedByAgent(agentId: string, jobId: string): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Resolve which agent a dispatched job was sent to.
|
|
160
|
+
* Used by the cancel-run API. Returns null if the job is not tracked (e.g. already completed).
|
|
161
|
+
*/
|
|
162
|
+
getAgentIdForJob(jobId: string): string | null;
|
|
163
|
+
/**
|
|
164
|
+
* Start periodic cleanup of expired grace window entries.
|
|
165
|
+
* Should be called during server startup.
|
|
166
|
+
*/
|
|
167
|
+
startGraceCleanup(): void;
|
|
168
|
+
/**
|
|
169
|
+
* Stop periodic grace cleanup.
|
|
170
|
+
* Should be called during server shutdown.
|
|
171
|
+
*/
|
|
172
|
+
stopGraceCleanup(): void;
|
|
173
|
+
/**
|
|
174
|
+
* Claim a recovering job back for a reconnected agent.
|
|
175
|
+
* Cancels the recovery timer and returns true if the job was in recovery
|
|
176
|
+
* for this agent. Returns false if the job is not recovering or belongs
|
|
177
|
+
* to a different agent.
|
|
178
|
+
*/
|
|
179
|
+
claimRecovery(jobId: string, agentId: string): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Full reconciliation of a recovering job for a reconnected agent.
|
|
182
|
+
* Claims the recovery timer, transitions DB status back to dispatched,
|
|
183
|
+
* and restores in-memory tracking. Returns true if reconciled.
|
|
184
|
+
*/
|
|
185
|
+
reconcileRecovery(jobId: string, agentId: string): Promise<boolean>;
|
|
186
|
+
/**
|
|
187
|
+
* Get recovery info for a job (for structured logging).
|
|
188
|
+
*/
|
|
189
|
+
getRecoveryInfo(jobId: string): {
|
|
190
|
+
disconnectedAt: number;
|
|
191
|
+
agentId: string;
|
|
192
|
+
} | null;
|
|
193
|
+
/**
|
|
194
|
+
* Get all recovering job IDs for a specific agent.
|
|
195
|
+
* Used during reconnection reconciliation.
|
|
196
|
+
*/
|
|
197
|
+
getRecoveringJobsForAgent(agentId: string): string[];
|
|
198
|
+
/**
|
|
199
|
+
* Restore a reconciled job into the dispatcher's in-memory tracking.
|
|
200
|
+
* Called when an agent reconnects and claims a recovering job.
|
|
201
|
+
*/
|
|
202
|
+
restoreJobForAgent(agentId: string, jobId: string): void;
|
|
203
|
+
/**
|
|
204
|
+
* Start a recovery timer for a job found in 'dispatched' state on startup.
|
|
205
|
+
* Called by server.ts/standalone.ts to create recovery timers for jobs
|
|
206
|
+
* from a previous orchestrator instance.
|
|
207
|
+
*/
|
|
208
|
+
startRecoveryTimer(jobId: string, agentId: string, runId: string): Promise<void>;
|
|
209
|
+
/**
|
|
210
|
+
* Stop all recovery timers. Called during graceful shutdown.
|
|
211
|
+
*/
|
|
212
|
+
stopRecoveryTimers(): void;
|
|
213
|
+
/**
|
|
214
|
+
* Handle recovery timer expiry for a single job.
|
|
215
|
+
* Extracted so that both onAgentDisconnect and startRecoveryTimer share the same logic,
|
|
216
|
+
* and the caller can `.catch()` to prevent unhandled rejections in setTimeout.
|
|
217
|
+
*/
|
|
218
|
+
private handleRecoveryExpiry;
|
|
219
|
+
/** Remove expired entries from the completedJobs grace window map. */
|
|
220
|
+
private cleanupExpiredGraceEntries;
|
|
221
|
+
private trackJobForAgent;
|
|
222
|
+
/**
|
|
223
|
+
* Cancel a queued job (mark as failed in the dispatch queue).
|
|
224
|
+
* Used by the coordinator to clean up local fallback entries when a peer
|
|
225
|
+
* accepts the rerouted job.
|
|
226
|
+
*/
|
|
227
|
+
cancelQueuedJob(jobId: string, reason: string): Promise<void>;
|
|
228
|
+
private updateQueueDepthMetric;
|
|
229
|
+
}
|
|
230
|
+
export {};
|
|
231
|
+
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job ownership tracker for agent message validation.
|
|
3
|
+
*
|
|
4
|
+
* Validates that agents only send messages (job.status, log.chunk, step.status,
|
|
5
|
+
* job.heartbeat, cache.upload.request, cache.upload.complete) for jobs that were
|
|
6
|
+
* actually dispatched to them.
|
|
7
|
+
*
|
|
8
|
+
* Includes:
|
|
9
|
+
* - Ownership check via dispatcher's isJobOwnedByAgent
|
|
10
|
+
* - Violation counting with sliding window (default: 5 violations in 60s)
|
|
11
|
+
* - Escalation: disconnect agent after threshold violations
|
|
12
|
+
*/
|
|
13
|
+
interface OwnershipTrackerOpts {
|
|
14
|
+
/** Check if a job is owned by the given agent (active or in grace window). */
|
|
15
|
+
isJobOwnedByAgent: (agentId: string, jobId: string) => boolean;
|
|
16
|
+
/** Callback to disconnect an agent after escalation. */
|
|
17
|
+
onDisconnect: (agentId: string, reason: string) => void;
|
|
18
|
+
/** Number of violations before escalation (default: 5). */
|
|
19
|
+
violationThreshold?: number;
|
|
20
|
+
/** Window in ms for counting violations (default: 60_000). */
|
|
21
|
+
violationWindowMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class OwnershipTracker {
|
|
24
|
+
private readonly isJobOwnedByAgent;
|
|
25
|
+
private readonly onDisconnect;
|
|
26
|
+
private readonly violationThreshold;
|
|
27
|
+
private readonly violationWindowMs;
|
|
28
|
+
private readonly violations;
|
|
29
|
+
constructor(opts: OwnershipTrackerOpts);
|
|
30
|
+
/**
|
|
31
|
+
* Check if an agent owns a job. Returns true if ownership is valid.
|
|
32
|
+
* On violation: logs warning, records violation, may escalate to disconnect.
|
|
33
|
+
*/
|
|
34
|
+
checkOwnership(agentId: string, jobId: string, messageType: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Record a violation for an agent. If threshold is exceeded within the
|
|
37
|
+
* violation window, triggers disconnect escalation.
|
|
38
|
+
*/
|
|
39
|
+
private recordViolation;
|
|
40
|
+
/**
|
|
41
|
+
* Clean up violation tracking for a disconnected agent.
|
|
42
|
+
*/
|
|
43
|
+
cleanup(agentId: string): void;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=ownership-tracker.d.ts.map
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory agent registry with label-based lookup and capacity tracking.
|
|
3
|
+
*
|
|
4
|
+
* Follows the Platform ConnectionRegistry dual-map pattern:
|
|
5
|
+
* - Primary map: agentId -> AgentEntry (direct agent lookup)
|
|
6
|
+
* - Secondary map: label -> Set<agentId> (reverse index for label-based dispatch queries)
|
|
7
|
+
* - WS reverse map: ws -> agentId (fast lookup on WS events)
|
|
8
|
+
*
|
|
9
|
+
* No persistence needed -- agents re-register on reconnect.
|
|
10
|
+
*/
|
|
11
|
+
import type { WsLike } from '@kici-dev/engine';
|
|
12
|
+
export type { WsLike } from '@kici-dev/engine';
|
|
13
|
+
/**
|
|
14
|
+
* A single tracked agent connection.
|
|
15
|
+
*/
|
|
16
|
+
export interface AgentEntry {
|
|
17
|
+
/** Unique agent identifier. */
|
|
18
|
+
agentId: string;
|
|
19
|
+
/** The underlying WebSocket (or mock). */
|
|
20
|
+
ws: WsLike;
|
|
21
|
+
/** Set of labels this agent provides (e.g., "linux", "gpu", "docker"). */
|
|
22
|
+
labels: Set<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Kubernetes-taint-style mandatory labels inherited from the scaler that
|
|
25
|
+
* spawned this agent. A job is only dispatched to this agent when every
|
|
26
|
+
* label in `mandatoryLabels` appears in `runsOnLabels` (in addition to the
|
|
27
|
+
* existing subset/exclusion checks).
|
|
28
|
+
*
|
|
29
|
+
* Empty for static agents and warm-pool replenishment spawns — those have
|
|
30
|
+
* no opt-in gate and behave exactly as before. Populated only when the
|
|
31
|
+
* spawning scaler declared a `mandatoryLabels` block; the value is a copy
|
|
32
|
+
* of the scaler's gate (the scaler-side gate in `findBackendForLabels` is
|
|
33
|
+
* not enough — once the agent registers, the queue-drain path
|
|
34
|
+
* (`onAgentAvailable` → `dequeueForLabels`) sees only the agent's labels
|
|
35
|
+
* and would otherwise pull a queued job whose `runsOn` is a subset of the
|
|
36
|
+
* agent's labels but does not satisfy the gate).
|
|
37
|
+
*/
|
|
38
|
+
mandatoryLabels: Set<string>;
|
|
39
|
+
/** Number of jobs currently executing on this agent. */
|
|
40
|
+
activeJobs: number;
|
|
41
|
+
/** Maximum concurrent jobs this agent can handle (default 1). */
|
|
42
|
+
maxConcurrency: number;
|
|
43
|
+
/** Unix epoch ms of the last heartbeat received. */
|
|
44
|
+
lastHeartbeatAt: number;
|
|
45
|
+
/** Agent platform (os.platform(), e.g. 'linux', 'darwin', 'win32'). */
|
|
46
|
+
platform: string;
|
|
47
|
+
/** Agent architecture (os.arch(), e.g. 'x64', 'arm64'). */
|
|
48
|
+
arch: string;
|
|
49
|
+
/** Unix epoch ms when the agent registered. */
|
|
50
|
+
registeredAt: number;
|
|
51
|
+
/** Self-reported agent version (e.g. "0.0.1"). Null if not reported. */
|
|
52
|
+
version: string | null;
|
|
53
|
+
/**
|
|
54
|
+
* The `agent_tokens.id` row used to authenticate this connection, or
|
|
55
|
+
* `null` when auth mode is `none`. Indexed by `tokenIdIndex` so a
|
|
56
|
+
* synchronous revocation kick can enumerate every WS authenticated by
|
|
57
|
+
* a given token. in the pentest catalog.
|
|
58
|
+
*/
|
|
59
|
+
tokenId: string | null;
|
|
60
|
+
hostname: string | null;
|
|
61
|
+
osRelease: string | null;
|
|
62
|
+
osVersion: string | null;
|
|
63
|
+
totalMemoryMb: number | null;
|
|
64
|
+
cpuCount: number | null;
|
|
65
|
+
nodeVersion: string | null;
|
|
66
|
+
runningAsUser: string | null;
|
|
67
|
+
runningAsUid: number | null;
|
|
68
|
+
memoryUsedMb: number | null;
|
|
69
|
+
memoryAvailableMb: number | null;
|
|
70
|
+
uptimeSeconds: number | null;
|
|
71
|
+
}
|
|
72
|
+
/** Optional static metadata from the agent.register message. */
|
|
73
|
+
interface AgentMetadata {
|
|
74
|
+
hostname?: string;
|
|
75
|
+
osRelease?: string;
|
|
76
|
+
osVersion?: string;
|
|
77
|
+
totalMemoryMb?: number;
|
|
78
|
+
cpuCount?: number;
|
|
79
|
+
nodeVersion?: string;
|
|
80
|
+
runningAsUser?: string;
|
|
81
|
+
runningAsUid?: number;
|
|
82
|
+
/**
|
|
83
|
+
* The `agent_tokens.id` row used to authenticate this connection.
|
|
84
|
+
* `null` when auth mode is `none` (no token-based auth applied).
|
|
85
|
+
* Indexed for `disconnectByTokenId(...)` revocation kicks.
|
|
86
|
+
*/
|
|
87
|
+
tokenId?: string | null;
|
|
88
|
+
/**
|
|
89
|
+
* Kubernetes-taint-style mandatory labels inherited from the scaler that
|
|
90
|
+
* spawned this agent. Empty / undefined for static agents (no opt-in
|
|
91
|
+
* gate). Populated by `agent-handler.ts` from the scaler manager's
|
|
92
|
+
* `onAgentRegistered(...)` return value.
|
|
93
|
+
*/
|
|
94
|
+
mandatoryLabels?: string[];
|
|
95
|
+
}
|
|
96
|
+
export declare class AgentRegistry {
|
|
97
|
+
/** Primary: agentId -> AgentEntry */
|
|
98
|
+
private readonly agents;
|
|
99
|
+
/** Secondary: label -> Set<agentId> (reverse index for label-based queries) */
|
|
100
|
+
private readonly labelIndex;
|
|
101
|
+
/** Reverse: ws -> agentId (for fast lookup on WS events) */
|
|
102
|
+
private readonly wsToAgentId;
|
|
103
|
+
/**
|
|
104
|
+
* Reverse: tokenId -> Set<agentId> (for synchronous revocation kicks).
|
|
105
|
+
*
|
|
106
|
+
* Populated when `register()` is called with a non-null `tokenId`,
|
|
107
|
+
* cleaned up by `removeFromIndexes()` on `unregister()` /
|
|
108
|
+
* re-registration. `disconnectByTokenId(tokenId)` walks the matching
|
|
109
|
+
* set, closes each WS, and unregisters the entry — closing the
|
|
110
|
+
* gap where a revoked token's in-flight WS retained data-plane
|
|
111
|
+
* authority until the agent itself disconnected.
|
|
112
|
+
*/
|
|
113
|
+
private readonly tokenIdIndex;
|
|
114
|
+
/**
|
|
115
|
+
* Per-tokenId TTL kick timer, keyed by `tokenId`. Scheduled by
|
|
116
|
+
* `scheduleExpiryKick(tokenId, expiresAt)` at agent register-time
|
|
117
|
+
* when the auth token has a non-null `expires_at`. Fires
|
|
118
|
+
* `disconnectByTokenId(tokenId)` when the token's TTL elapses, and
|
|
119
|
+
* is cleared when (a) the timer fires, (b) `disconnectByTokenId` is
|
|
120
|
+
* called explicitly via revocation (no double-kick when revoke
|
|
121
|
+
* races TTL), or (c) the last agent under the tokenId unregisters
|
|
122
|
+
* naturally (avoid timer leaks on long-lived registries).
|
|
123
|
+
*
|
|
124
|
+
* Idempotent: re-scheduling the same tokenId is a no-op as long as
|
|
125
|
+
* a timer is still queued — a token's `expires_at` doesn't shift
|
|
126
|
+
* across reconnects of the same agent. Closes the sister gap
|
|
127
|
+
* to the revocation finding (`agent-token-revocation-stale-ws`,
|
|
128
|
+
* fixed in `993bc3d9d`) where natural TTL expiration had no
|
|
129
|
+
* propagation path to in-flight WS connections.
|
|
130
|
+
*/
|
|
131
|
+
private readonly tokenExpiryTimers;
|
|
132
|
+
/**
|
|
133
|
+
* Register an agent. If the agentId already exists, updates the existing
|
|
134
|
+
* entry (agent reconnection scenario).
|
|
135
|
+
*/
|
|
136
|
+
register(agentId: string, ws: WsLike, labels: string[], platform?: string, arch?: string, version?: string, maxConcurrency?: number, metadata?: AgentMetadata): void;
|
|
137
|
+
/**
|
|
138
|
+
* Unregister an agent by ID. Removes from all indexes.
|
|
139
|
+
* @returns The removed AgentEntry, or undefined if not found.
|
|
140
|
+
*/
|
|
141
|
+
unregister(agentId: string): AgentEntry | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Unregister an agent by its WebSocket reference (for disconnect handling).
|
|
144
|
+
* @returns The removed AgentEntry, or undefined if not found.
|
|
145
|
+
*/
|
|
146
|
+
unregisterByWs(ws: WsLike): AgentEntry | undefined;
|
|
147
|
+
/**
|
|
148
|
+
* Close every WS authenticated under `tokenId`, send a final
|
|
149
|
+
* `auth.failure` message, then unregister the entry. Returns the
|
|
150
|
+
* count of kicked agents.
|
|
151
|
+
*
|
|
152
|
+
* Closes the gap on the agent->orchestrator leg: when an admin
|
|
153
|
+
* revokes a token via `DELETE /api/v1/agent-tokens/:id`, the route
|
|
154
|
+
* calls this synchronously after `tokenStore.revoke(id)` so the
|
|
155
|
+
* in-flight WS loses data-plane authority before the handler
|
|
156
|
+
* returns.
|
|
157
|
+
*
|
|
158
|
+
* The WS close code is `WS_CLOSE_AGENT_AUTH_FAILED` (4010); the
|
|
159
|
+
* agent's reconnect loop treats both the `auth.failure` message and
|
|
160
|
+
* this close code as permanent and stops retrying.
|
|
161
|
+
*/
|
|
162
|
+
disconnectByTokenId(tokenId: string): number;
|
|
163
|
+
/**
|
|
164
|
+
* Schedule a one-shot TTL kick for `tokenId` at `expiresAt`. When
|
|
165
|
+
* the timer fires (or if `expiresAt` is already past), every
|
|
166
|
+
* in-flight WS authenticated under the token is closed via
|
|
167
|
+
* `disconnectByTokenId`.
|
|
168
|
+
*
|
|
169
|
+
* Idempotent per `tokenId`: if a timer is already scheduled for
|
|
170
|
+
* this token, the call is a no-op. A token's `expires_at` doesn't
|
|
171
|
+
* change across reconnects, so re-scheduling would just re-arm the
|
|
172
|
+
* same trigger.
|
|
173
|
+
*
|
|
174
|
+
* Caller is the agent WS handler at register-time, when the token's
|
|
175
|
+
* `agent_tokens.expires_at` column is non-null. Static tokens have
|
|
176
|
+
* `expires_at = null` and are skipped at the call site (they have
|
|
177
|
+
* no TTL by design). Closes the sister gap to the revocation
|
|
178
|
+
* finding (`agent-token-revocation-stale-ws`, fixed in `993bc3d9d`)
|
|
179
|
+
* where natural TTL expiration had no propagation path to
|
|
180
|
+
* in-flight WS connections.
|
|
181
|
+
*/
|
|
182
|
+
scheduleExpiryKick(tokenId: string, expiresAt: Date): void;
|
|
183
|
+
/**
|
|
184
|
+
* Find available agents that match ALL required labels.
|
|
185
|
+
* An agent is available when it has capacity (activeJobs < maxConcurrency).
|
|
186
|
+
*
|
|
187
|
+
* In addition to the subset + exclusion filters, every label declared in
|
|
188
|
+
* the agent's `mandatoryLabels` must appear in `requiredLabels`. This is
|
|
189
|
+
* the agent-side mirror of the scaler-side mandatory-labels gate
|
|
190
|
+
* (`findBackendForLabels`). Without it, a queued job whose `runsOn` is a
|
|
191
|
+
* subset of a gated agent's labels but does not list the gate label
|
|
192
|
+
* would be drained onto that agent the next time `onAgentAvailable`
|
|
193
|
+
* fires — sidestepping the opt-in semantics the gate is meant to enforce.
|
|
194
|
+
*
|
|
195
|
+
* @param requiredLabels - All labels the agent must have (intersection semantics).
|
|
196
|
+
* @returns Array of matching available AgentEntry objects.
|
|
197
|
+
*/
|
|
198
|
+
findAvailable(requiredLabels: string[], excludeLabels?: string[]): AgentEntry[];
|
|
199
|
+
/**
|
|
200
|
+
* Check if ANY registered agent matches the required labels, regardless of capacity.
|
|
201
|
+
* Used to decide whether to queue (agent exists but busy) vs reject (no agent at all).
|
|
202
|
+
*
|
|
203
|
+
* Applies the same `mandatoryLabels` gate as `findAvailable` — a gated
|
|
204
|
+
* agent only counts as "matching" when every label in its
|
|
205
|
+
* `mandatoryLabels` is present in `requiredLabels`. Without this, the
|
|
206
|
+
* dispatcher's `queued-no-backend` decision in `dispatch()` would treat
|
|
207
|
+
* an off-gate gated agent as "matching but busy" and skip the peer
|
|
208
|
+
* reroute path even though the local agent can never accept the job.
|
|
209
|
+
*/
|
|
210
|
+
hasMatchingAgent(requiredLabels: string[], excludeLabels?: string[]): boolean;
|
|
211
|
+
/**
|
|
212
|
+
* Internal helper: intersect the per-label candidate sets to find agentIds
|
|
213
|
+
* that satisfy `requiredLabels`. Returns `null` when any required label
|
|
214
|
+
* matches zero agents (so callers can short-circuit). Returns an empty
|
|
215
|
+
* Set on `requiredLabels.length === 0` since the caller decides the
|
|
216
|
+
* walk strategy in that case.
|
|
217
|
+
*/
|
|
218
|
+
private intersectLabelCandidates;
|
|
219
|
+
/**
|
|
220
|
+
* Increment activeJobs for an agent.
|
|
221
|
+
* @returns false if agent not found.
|
|
222
|
+
*/
|
|
223
|
+
incrementActiveJobs(agentId: string): boolean;
|
|
224
|
+
/**
|
|
225
|
+
* Decrement activeJobs for an agent (min 0).
|
|
226
|
+
* @returns false if agent not found.
|
|
227
|
+
*/
|
|
228
|
+
decrementActiveJobs(agentId: string): boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Update the last heartbeat timestamp for an agent.
|
|
231
|
+
*/
|
|
232
|
+
updateHeartbeat(agentId: string): boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Get a single agent entry by ID.
|
|
235
|
+
*/
|
|
236
|
+
get(agentId: string): AgentEntry | undefined;
|
|
237
|
+
/**
|
|
238
|
+
* Get an agent entry by its WebSocket reference.
|
|
239
|
+
*/
|
|
240
|
+
getByWs(ws: WsLike): AgentEntry | undefined;
|
|
241
|
+
/**
|
|
242
|
+
* Total number of registered agents.
|
|
243
|
+
*/
|
|
244
|
+
getActiveCount(): number;
|
|
245
|
+
/**
|
|
246
|
+
* Iterator over all agent entries (for heartbeat checks, etc).
|
|
247
|
+
*/
|
|
248
|
+
getAllEntries(): IterableIterator<AgentEntry>;
|
|
249
|
+
/**
|
|
250
|
+
* Remove an agent from the WS reverse map and label index.
|
|
251
|
+
* Does NOT remove from the primary agents map.
|
|
252
|
+
*/
|
|
253
|
+
private removeFromIndexes;
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=registry.d.ts.map
|