@kici-dev/orchestrator 0.6.1 → 0.8.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.
Files changed (187) hide show
  1. package/dist/agent/dispatcher.d.ts +10 -1
  2. package/dist/agent/host-roster.d.ts +8 -3
  3. package/dist/agent/registry.d.ts +60 -5
  4. package/dist/app.d.ts +10 -5
  5. package/dist/cache/dep-cache.d.ts +14 -6
  6. package/dist/cache/global-eval-round-cache.d.ts +1 -1
  7. package/dist/cache/index.d.ts +1 -1
  8. package/dist/cache/source-cache.d.ts +92 -15
  9. package/dist/cancel/cancel-run.d.ts +20 -2
  10. package/dist/cancel/sweep-stuck-cancelling.d.ts +30 -0
  11. package/dist/cli/api-client.d.ts +10 -0
  12. package/dist/cli/commands/agent-service/logs.d.ts +1 -1
  13. package/dist/cli/commands/agent-service/restart.d.ts +1 -1
  14. package/dist/cli/commands/agent-service/start.d.ts +1 -1
  15. package/dist/cli/commands/agent-service/status.d.ts +1 -1
  16. package/dist/cli/commands/agent-service/stop.d.ts +1 -1
  17. package/dist/cli/commands/agent-service/uninstall.d.ts +1 -1
  18. package/dist/cli/commands/agent.d.ts +25 -0
  19. package/dist/cli/commands/config.d.ts +16 -0
  20. package/dist/cli/commands/db-backup.d.ts +46 -0
  21. package/dist/cli/commands/held-run.d.ts +9 -0
  22. package/dist/cli/commands/orchestrator-service/drain.d.ts +2 -19
  23. package/dist/cli/commands/orchestrator-service/index.d.ts +9 -1
  24. package/dist/cli/commands/orchestrator-service/install-env.d.ts +43 -2
  25. package/dist/cli/commands/orchestrator-service/logs.d.ts +1 -1
  26. package/dist/cli/commands/orchestrator-service/restart.d.ts +1 -1
  27. package/dist/cli/commands/orchestrator-service/start.d.ts +1 -1
  28. package/dist/cli/commands/orchestrator-service/status.d.ts +17 -1
  29. package/dist/cli/commands/orchestrator-service/stop.d.ts +1 -1
  30. package/dist/cli/commands/orchestrator-service/uninstall.d.ts +1 -1
  31. package/dist/cli/commands/orchestrator-service/upgrade.d.ts +2 -1
  32. package/dist/cli/commands/rotate.d.ts +1 -1
  33. package/dist/cli/commands/shared/env-file-mode.d.ts +16 -0
  34. package/dist/cli/commands/shared/upgrade-hooks.d.ts +32 -0
  35. package/dist/cli/commands/shared/upgrade-safety.d.ts +81 -0
  36. package/dist/cli/commands/shared/versioned-upgrade.d.ts +67 -12
  37. package/dist/cli/commands/source.d.ts +1 -0
  38. package/dist/cli/commands/token.d.ts +4 -0
  39. package/dist/cli/commands/trust-policy.d.ts +57 -1
  40. package/dist/cli/join.d.ts +1 -1
  41. package/dist/cli/service/backup-timer.d.ts +108 -0
  42. package/dist/cli/service/compose-path.d.ts +11 -0
  43. package/dist/cli/service/compose.d.ts +22 -0
  44. package/dist/cli/service/deploy-env.d.ts +10 -11
  45. package/dist/cli/service/env-assignment.d.ts +24 -0
  46. package/dist/cli/service/index.d.ts +2 -2
  47. package/dist/cli/service/instance/resolve.d.ts +71 -7
  48. package/dist/cli/service/instance/types.d.ts +15 -0
  49. package/dist/cli/service/launchd.d.ts +7 -0
  50. package/dist/cli/service/systemd.d.ts +1 -0
  51. package/dist/cli/service/types.d.ts +36 -0
  52. package/dist/cli/service/windows.d.ts +16 -0
  53. package/dist/cli/wizard/orchestrator-wizard.d.ts +12 -3
  54. package/dist/cli/wizard/prompts.d.ts +7 -0
  55. package/dist/cli.js +12544 -9299
  56. package/dist/cluster/cluster-settings-reader.d.ts +2 -2
  57. package/dist/cluster/coordinator.d.ts +11 -0
  58. package/dist/cluster/instance-heartbeat.d.ts +96 -0
  59. package/dist/cluster/join-client.d.ts +55 -5
  60. package/dist/cluster/join-handler.d.ts +1 -0
  61. package/dist/cluster/orphan-recovery.d.ts +16 -0
  62. package/dist/cluster/peer-registry.d.ts +10 -0
  63. package/dist/concurrency/dispatch-next-queued.d.ts +1 -13
  64. package/dist/concurrency/index.d.ts +1 -2
  65. package/dist/concurrency/queue-manager.d.ts +63 -18
  66. package/dist/config/env-overlay.d.ts +3 -2
  67. package/dist/config.d.ts +24 -0
  68. package/dist/contexts/release-queued-holds.d.ts +23 -1
  69. package/dist/dashboard/attestation-filters.d.ts +2 -0
  70. package/dist/dashboard/handler.d.ts +22 -2
  71. package/dist/db/deferred-indexes.d.ts +72 -0
  72. package/dist/db/migration-test-harness.d.ts +22 -0
  73. package/dist/db/migrations/131_execution_jobs_git_credentials.d.ts +30 -0
  74. package/dist/db/migrations/132_execution_runs_trigger_event.d.ts +23 -0
  75. package/dist/db/migrations/133_dispatch_queue_source_tar_digest.d.ts +23 -0
  76. package/dist/db/migrations/134_dispatch_queue_ownership.d.ts +4 -0
  77. package/dist/db/migrations/135_cluster_settings_retention_days.d.ts +4 -0
  78. package/dist/db/migrations/136_master_key_wrapped_tables_key_version.d.ts +4 -0
  79. package/dist/db/migrations/137_execution_runs_pr_head_context.d.ts +4 -0
  80. package/dist/db/migrations/138_execution_runs_subject_trigger_event.d.ts +4 -0
  81. package/dist/db/migrations/139_admin_token_subject.d.ts +4 -0
  82. package/dist/db/migrations/140_dispatch_queue_canonical_labels.d.ts +54 -0
  83. package/dist/db/migrations/141_event_log_shed.d.ts +15 -0
  84. package/dist/db/migrator.d.ts +47 -0
  85. package/dist/db/notify-listener.d.ts +60 -0
  86. package/dist/db/synthetic-job-ids.d.ts +24 -0
  87. package/dist/db/types.d.ts +169 -4
  88. package/dist/deployment/deployment-identity.d.ts +31 -1
  89. package/dist/diagnostics/checks/index.d.ts +2 -1
  90. package/dist/diagnostics/checks/retention.d.ts +24 -0
  91. package/dist/diagnostics/types.d.ts +7 -0
  92. package/dist/events/event-router.d.ts +1 -1
  93. package/dist/fault-injection-types.d.ts +53 -0
  94. package/dist/firecracker/host-network.d.ts +63 -8
  95. package/dist/git/credential-broker.d.ts +35 -2
  96. package/dist/git/inherited-secret.d.ts +7 -2
  97. package/dist/git/job-context.d.ts +7 -4
  98. package/dist/helpers/secure-write.d.ts +35 -0
  99. package/dist/index.js +196 -67
  100. package/dist/metrics/prometheus.d.ts +116 -1
  101. package/dist/oidc/db-signer.d.ts +27 -5
  102. package/dist/oidc/id-token-claims.d.ts +33 -2
  103. package/dist/oidc/oidc-mint-registration.d.ts +6 -0
  104. package/dist/oidc/orchestrator-mint.d.ts +8 -0
  105. package/dist/oidc/reconcile-signing-key.d.ts +37 -0
  106. package/dist/orchestrator-core.d.ts +9 -3
  107. package/dist/pipeline/decorating-secret-resolver.d.ts +1 -1
  108. package/dist/pipeline/dispatch-matched-workflow.d.ts +65 -14
  109. package/dist/pipeline/manual-schedule.d.ts +1 -0
  110. package/dist/pipeline/process-webhook.d.ts +20 -2
  111. package/dist/pipeline/route-or-dispatch-jobs.d.ts +7 -0
  112. package/dist/pipeline/run-event-context.d.ts +39 -0
  113. package/dist/policy/dashboard-write-policy-listener.d.ts +1 -1
  114. package/dist/policy/dashboard-write-policy.d.ts +47 -1
  115. package/dist/provenance/dispatch-context.d.ts +46 -0
  116. package/dist/provenance/verify-deferred-capture.d.ts +39 -0
  117. package/dist/providers/github/auth.d.ts +9 -0
  118. package/dist/providers/github/deliveries.d.ts +118 -0
  119. package/dist/providers/local/lock-file-fetcher.d.ts +8 -0
  120. package/dist/providers/universal-git/config.d.ts +1 -1
  121. package/dist/queue/cleanup.d.ts +13 -0
  122. package/dist/queue/job-queue.d.ts +162 -14
  123. package/dist/queue/retention.d.ts +105 -0
  124. package/dist/reporting/execution-tracker.d.ts +87 -36
  125. package/dist/routes/admin-db.d.ts +5 -0
  126. package/dist/routes/admin-events.d.ts +13 -0
  127. package/dist/routes/admin-held-runs.d.ts +11 -1
  128. package/dist/routes/admin-org-settings.d.ts +9 -0
  129. package/dist/routes/admin-runs.d.ts +7 -4
  130. package/dist/routes/admin-sources.d.ts +15 -0
  131. package/dist/routes/admin-trust-policy.d.ts +11 -0
  132. package/dist/routes/admin.d.ts +25 -0
  133. package/dist/scaler/backend-factory.d.ts +16 -0
  134. package/dist/scaler/bare-metal-backend.d.ts +22 -4
  135. package/dist/scaler/claim-store.d.ts +0 -2
  136. package/dist/scaler/config.d.ts +6 -3
  137. package/dist/scaler/container-backend.d.ts +102 -3
  138. package/dist/scaler/container-hostconfig.d.ts +60 -0
  139. package/dist/scaler/event-backend.d.ts +7 -6
  140. package/dist/scaler/file-tail.d.ts +25 -2
  141. package/dist/scaler/firecracker-api.d.ts +9 -1
  142. package/dist/scaler/firecracker-backend.d.ts +135 -2
  143. package/dist/scaler/host-access.d.ts +59 -0
  144. package/dist/scaler/index.d.ts +1 -0
  145. package/dist/scaler/manager.d.ts +51 -2
  146. package/dist/scaler/scaler-state-store.d.ts +13 -0
  147. package/dist/scaler/types.d.ts +15 -7
  148. package/dist/scaler/warm-pool.d.ts +6 -4
  149. package/dist/secrets/config.d.ts +48 -0
  150. package/dist/secrets/dashboard-encryption-key.d.ts +19 -0
  151. package/dist/secrets/ephemeral-keys.d.ts +9 -3
  152. package/dist/secrets/index.d.ts +3 -1
  153. package/dist/secrets/job-secret-gate.d.ts +76 -0
  154. package/dist/secrets/master-key-rotation.d.ts +65 -0
  155. package/dist/secrets/secret-output-crypto.d.ts +17 -0
  156. package/dist/secrets/secret-resolver.d.ts +23 -6
  157. package/dist/secrets/source-credentials.d.ts +1 -1
  158. package/dist/secrets/token-manager.d.ts +4 -1
  159. package/dist/security/identity-link.d.ts +1 -1
  160. package/dist/security/reduced-privilege-note.d.ts +5 -0
  161. package/dist/security/trust-directory-store.d.ts +1 -1
  162. package/dist/security/trust-policy-gate.d.ts +70 -6
  163. package/dist/security/trust-tier.d.ts +31 -0
  164. package/dist/server.d.ts +1 -1
  165. package/dist/server.js +10793 -5323
  166. package/dist/sources/source-manager.d.ts +1 -1
  167. package/dist/stale-detector/stale-dispatch-candidates.d.ts +43 -0
  168. package/dist/standalone.js +9385 -4160
  169. package/dist/storage/loopback-guard.d.ts +53 -6
  170. package/dist/webhook/event-log.d.ts +14 -1
  171. package/dist/webhook/generic-sources-listener.d.ts +1 -1
  172. package/dist/webhook/ingest-admission.d.ts +24 -0
  173. package/dist/webhook/ingest-overflow-replayer.d.ts +78 -14
  174. package/dist/webhook/ingest-overflow-types.d.ts +13 -1
  175. package/dist/webhook/register-source-bundle.d.ts +23 -0
  176. package/dist/webhook/relay-reinject.d.ts +11 -12
  177. package/dist/webhook/shed-breadcrumb.d.ts +15 -0
  178. package/dist/worker/in-memory-job-queue.d.ts +9 -0
  179. package/dist/ws/fleet-agent-collector.d.ts +7 -0
  180. package/dist/ws/git-credential-relay.d.ts +41 -12
  181. package/dist/ws/platform-client.d.ts +28 -5
  182. package/dist/ws/test-relay-handlers.d.ts +2 -0
  183. package/installer-image-digests.json +3 -3
  184. package/package.json +4 -4
  185. package/sbom.spdx.json +53 -53
  186. package/dist/concurrency/group-tracker.d.ts +0 -51
  187. package/dist/scaler/nftables.d.ts +0 -111
@@ -45,6 +45,7 @@ export interface Database {
45
45
  run_ephemeral_keys: RunEphemeralKeysTable;
46
46
  run_secret_outputs: RunSecretOutputsTable;
47
47
  concurrency_groups: ConcurrencyGroupsTable;
48
+ cluster_instances: ClusterInstancesTable;
48
49
  sources: SourcesTable;
49
50
  cluster_meta: ClusterMetaTable;
50
51
  join_tokens: JoinTokenTable;
@@ -253,6 +254,7 @@ export interface DispatchQueueTable {
253
254
  source_tar_url: string | null;
254
255
  /** SHA-256 hash of the source tarball bytes for integrity verification. Nullable. */
255
256
  source_tar_hash: string | null;
257
+ source_tar_digest: string | null;
256
258
  /** Pre-built dependency tarball URL (from dep cache). Nullable. */
257
259
  deps_url: string | null;
258
260
  /** SHA-256 hash of the dependency tarball. Nullable. */
@@ -322,7 +324,53 @@ export interface DispatchQueueTable {
322
324
  * NULL for pending rows and for rows dispatched before the column existed.
323
325
  */
324
326
  agent_id: ColumnType<string | null, string | null | undefined, string | null>;
327
+ /**
328
+ * The coordinator watching this dispatch. Written at claim/dispatch from
329
+ * `config.instanceId`, cleared on requeue.
330
+ *
331
+ * `agent_id` above says which agent holds the job; this says which
332
+ * coordinator armed the timers for it, which is the question every
333
+ * cluster-wide sweep has to answer before it acts. A NULL reads as "unknown
334
+ * owner", never as "not mine" — the convention migration 119 established for
335
+ * the scaler plane — so an unknown-owner row is spared by recovery selection
336
+ * and reaped, if genuinely dead, by the stale detector's dispatch-time scan.
337
+ */
338
+ owner_instance_id: ColumnType<string | null, string | null | undefined, string | null>;
339
+ /**
340
+ * When the row was handed to an agent, as distinct from `created_at`, which
341
+ * is when it was enqueued. A job that waited behind a busy fleet has an old
342
+ * `created_at` and a fresh `dispatched_at`, and only the second one measures
343
+ * "this dispatch has gone unacknowledged". NULL for pending rows and for rows
344
+ * dispatched before the column existed; readers fall back to `created_at`.
345
+ */
346
+ dispatched_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
347
+ }
348
+ /**
349
+ * Coordinator heartbeat table (cluster_instances)
350
+ *
351
+ * The liveness source every ownership predicate reads: an orchestrator upserts
352
+ * its own row on a fixed tick, and a row whose `last_heartbeat_at` is inside the
353
+ * grace window means that coordinator is alive. It is a DB heartbeat rather than
354
+ * the in-memory peer registry because the peer registry is empty at exactly the
355
+ * moment startup recovery runs — a freshly booted process has handshaken with
356
+ * nobody — and because it needs no peer connectivity, so it works the same in
357
+ * non-Raft multi-coordinator and standalone deployments. `host_roster` does the
358
+ * same job for agents.
359
+ */
360
+ export interface ClusterInstancesTable {
361
+ /** The coordinator's instance id (`config.instanceId`). */
362
+ instance_id: string;
363
+ /** Raft role at the last heartbeat, or null when the node runs without Raft. */
364
+ role: string | null;
365
+ /** Orchestrator version at the last heartbeat. */
366
+ version: string | null;
367
+ /** When this instance last started. */
368
+ started_at: Generated<Date>;
369
+ /** Refreshed every tick; staleness past the grace window reads as dead. */
370
+ last_heartbeat_at: Generated<Date>;
325
371
  }
372
+ export type ClusterInstance = Selectable<ClusterInstancesTable>;
373
+ export type NewClusterInstance = Insertable<ClusterInstancesTable>;
326
374
  /**
327
375
  * Deduplication cache table
328
376
  * Tracks recently processed webhook delivery IDs to prevent reprocessing.
@@ -452,6 +500,13 @@ export interface ExecutionRunTable {
452
500
  started_at: Generated<Date>;
453
501
  /** When the run completed */
454
502
  completed_at: Date | null;
503
+ /**
504
+ * When the run entered `cancelling`. Stamped once, on the transition, and
505
+ * never cleared: it is the clock the stuck-cancelling re-drive reads, and no
506
+ * other column records when the cancel started. NULL for a run that never
507
+ * cancelled and for one that entered `cancelling` before the column existed.
508
+ */
509
+ cancelling_at: ColumnType<Date | null, Date | null | undefined, Date | null>;
455
510
  /** Total execution duration in milliseconds */
456
511
  duration_ms: number | null;
457
512
  /**
@@ -487,6 +542,54 @@ export interface ExecutionRunTable {
487
542
  context: string | null;
488
543
  /** Matched context id for this run (null if no/unresolved context). */
489
544
  context_id: string | null;
545
+ /**
546
+ * The event type that started this run (`push`, `pr:open`, `schedule`, …).
547
+ *
548
+ * Persisted because the git credential relay evaluates a named context's
549
+ * protection rules against the run, and a context may restrict which trigger
550
+ * types may use it. NULL means the trigger was never recorded, which fails a
551
+ * `triggerTypeFilters` rule closed — a credential is withheld rather than
552
+ * granted on a rule nobody could check.
553
+ */
554
+ trigger_event: string | null;
555
+ /**
556
+ * The event the OIDC token's SUBJECT is derived from, when that is not
557
+ * {@link ExecutionRunTable.trigger_event}.
558
+ *
559
+ * A re-run records `trigger_event: 'rerun'`, which is what the dashboard's
560
+ * trigger filter and the credential relay's `triggerTypeFilters` need to
561
+ * read, but it carries no pull-request dimension — so a re-run of a pull
562
+ * request presented the branch-shaped subject a push to the same base branch
563
+ * presents. A re-run copies the original run's event here so the subject
564
+ * survives the hop.
565
+ *
566
+ * `buildIdTokenSubject` is the ONLY reader. NULL means "use `trigger_event`",
567
+ * which is what every row written before this column existed says, so a
568
+ * legacy row keeps the subject it already mints.
569
+ */
570
+ subject_trigger_event: string | null;
571
+ /**
572
+ * The pull-request HEAD branch — where a contributor's code actually lives.
573
+ * Distinct from {@link ExecutionRunTable.ref}, which is the base branch a PR
574
+ * targets. NULL for a non-PR run and for a row written before this column
575
+ * existed.
576
+ */
577
+ head_ref: string | null;
578
+ /**
579
+ * `owner/repo` of the pull-request HEAD. Equals `repo_identifier` for a
580
+ * same-repo PR and names the contributor's fork for a fork PR. NULL for a
581
+ * non-PR run and for a legacy row.
582
+ */
583
+ head_repository: string | null;
584
+ /**
585
+ * True when the pull request came from a fork (head repo != base repo).
586
+ * NULL means NOT RESOLVED — a legacy row, or one of the two reroute
587
+ * projections, which insert from a `job.reroute` message carrying no event
588
+ * context. Every claim derived from this column renders NULL as
589
+ * `'unresolved'` rather than `'false'`, so a trust policy that pins it fails
590
+ * closed.
591
+ */
592
+ is_fork: boolean | null;
490
593
  /** Trust tier of the contributor for PR runs (null for non-PR events) */
491
594
  trust_tier: string | null;
492
595
  /** Lock file source: 'head' or 'base' (null for non-PR events) */
@@ -679,6 +782,24 @@ export interface ExecutionJobTable {
679
782
  * overwritten with the agent-resolved list for dynamic contexts.
680
783
  */
681
784
  contexts: string | null;
785
+ /**
786
+ * The `gitCredentials` map this job's lock entry declared, as server truth
787
+ * the credential relay reads on every git network operation. JSONB: the
788
+ * driver returns a parsed object on SELECT, while writers pass a
789
+ * `JSON.stringify` string.
790
+ *
791
+ * Copied verbatim from the lock, because the relay compares a request against
792
+ * it byte for byte: a `<name>Secret` field is a secret NAME in qualified
793
+ * `<context>:<key>` form, and its `<name>Value` sibling is material for a
794
+ * credential with no store entry to name.
795
+ *
796
+ * This row is written after the dispatch loop, so NULL means either "the job
797
+ * declared none" or "the row has not caught up with the dispatch yet". The
798
+ * relay does not guess between them — `git/job-context.ts` reads the job's
799
+ * dispatch record, which carries the same declaration and is written before
800
+ * the agent is told about the job.
801
+ */
802
+ git_credentials: ColumnType<Record<string, Record<string, string>> | null, string | null, string | null>;
682
803
  /**
683
804
  * Bound contexts skipped on a test/local run (non-test or unconfigured),
684
805
  * JSON-encoded `string[]`. NULL = nothing skipped.
@@ -1194,6 +1315,14 @@ export interface AdminTokenTable {
1194
1315
  role: string;
1195
1316
  /** Routing key scope (null = all) */
1196
1317
  routing_key: string | null;
1318
+ /**
1319
+ * The intended holder, as the operator stated it at `token create --subject`
1320
+ * (an OIDC `sub` or an email). Advisory metadata only: the orchestrator
1321
+ * cannot verify it and never reads it when authorizing a request. It is the
1322
+ * join key the Platform's RBAC drift report compares against org membership.
1323
+ * NULL means nobody recorded a holder — the report's `unlinked` finding.
1324
+ */
1325
+ subject: string | null;
1197
1326
  /** When this token was created */
1198
1327
  created_at: Generated<Date>;
1199
1328
  /** When this token expires (null = never) */
@@ -1555,6 +1684,8 @@ export interface RunEphemeralKeysTable {
1555
1684
  encrypted_private_key: string;
1556
1685
  /** Base64-encoded DER public key (X25519 SPKI format) */
1557
1686
  public_key: string;
1687
+ /** Master-key generation this row is sealed under. Bumped by `rotate-key`. */
1688
+ key_version: Generated<number>;
1558
1689
  /** When this key pair was created */
1559
1690
  created_at: Generated<Date>;
1560
1691
  }
@@ -1563,7 +1694,12 @@ export type NewRunEphemeralKey = Insertable<RunEphemeralKeysTable>;
1563
1694
  /**
1564
1695
  * Run secret outputs table (run_secret_outputs)
1565
1696
  * Stores encrypted secret output values produced by jobs for cross-job consumption.
1566
- * Values are encrypted with the run's ephemeral public key via ECDH + AES-256-GCM.
1697
+ *
1698
+ * The agent seals a value to the run's ephemeral public key (ECDH + AES-256-GCM),
1699
+ * but that envelope is not what lands here: the orchestrator opens it with the
1700
+ * run private key and RE-ENCRYPTS the plaintext under the master key
1701
+ * (`KICI_SECRET_KEY`) before storing. So this is one of the master-key-wrapped
1702
+ * stores and moves with every key rotation.
1567
1703
  */
1568
1704
  export interface RunSecretOutputsTable {
1569
1705
  /** UUID primary key */
@@ -1574,8 +1710,14 @@ export interface RunSecretOutputsTable {
1574
1710
  job_id: string;
1575
1711
  /** Output key name */
1576
1712
  output_key: string;
1577
- /** Base64-encoded encrypted value (agent-encrypted ECDH envelope) */
1713
+ /**
1714
+ * Base64-encoded value, AES-256-GCM sealed under the master key with AAD
1715
+ * `secret-output:<run_id>`. Read through `unsealSecretOutput`, which carries
1716
+ * the rotation grace window's old-key fallback.
1717
+ */
1578
1718
  encrypted_value: string;
1719
+ /** Master-key generation this row is sealed under. Bumped by `rotate-key`. */
1720
+ key_version: Generated<number>;
1579
1721
  /** When this output was stored */
1580
1722
  created_at: Generated<Date>;
1581
1723
  }
@@ -1583,8 +1725,14 @@ export type RunSecretOutput = Selectable<RunSecretOutputsTable>;
1583
1725
  export type NewRunSecretOutput = Insertable<RunSecretOutputsTable>;
1584
1726
  /**
1585
1727
  * Concurrency groups table (concurrency_groups)
1586
- * Tracks active and queued runs per concurrency group for slot management.
1587
- * Persists across orchestrator restarts; hydrated into in-memory tracker on startup.
1728
+ *
1729
+ * The arbiter of `concurrency: { group, max }`, not a record of a decision made
1730
+ * elsewhere: a slot is acquired by an advisory-locked transaction that counts
1731
+ * `status='active'` rows for the scope and inserts only when the count is below
1732
+ * `max`. That is what makes the cap hold across a restart and across every
1733
+ * coordinator in a cluster, which a per-process map cannot. A partial unique
1734
+ * index on `(routing_key, group_key, run_id) WHERE status='active'` makes a
1735
+ * re-acquire idempotent.
1588
1736
  */
1589
1737
  export interface ConcurrencyGroupsTable {
1590
1738
  /** UUID primary key */
@@ -1914,6 +2062,21 @@ export interface OrgPlanHeadroomTable {
1914
2062
  * / seconds knobs are INTEGER (pg returns a number).
1915
2063
  */
1916
2064
  export interface ClusterSettingsTable {
2065
+ /**
2066
+ * Database-side retention windows, in days. NULL means the orchestrator's
2067
+ * configured default; 0 disables that window. These prune the warm tables
2068
+ * directly, for the installs that run no object store — with the cold store
2069
+ * on, the archivers keep sole ownership of the tables they register.
2070
+ */
2071
+ run_retention_days: number | null;
2072
+ audit_retention_days: number | null;
2073
+ provenance_retention_days: number | null;
2074
+ held_run_retention_days: number | null;
2075
+ /**
2076
+ * When the retention sweep first reported a non-zero window. Deletion starts
2077
+ * a week later, so an upgrade never removes history on its first night.
2078
+ */
2079
+ retention_announced_at: Date | null;
1917
2080
  id: ColumnType<string, string | undefined, never>;
1918
2081
  max_github_payload_bytes: ColumnType<string | null, number | null | undefined, number | null>;
1919
2082
  event_log_max_payload_bytes: ColumnType<string | null, number | null | undefined, number | null>;
@@ -2375,6 +2538,8 @@ export interface DashboardEncryptionKeysTable {
2375
2538
  public_jwk: unknown;
2376
2539
  /** AES-256-GCM-wrapped DER private key (master-key wrapped under KICI_SECRET_KEY). */
2377
2540
  encrypted_private_key: string;
2541
+ /** Master-key generation this row is sealed under. Bumped by `rotate-key`. */
2542
+ key_version: Generated<number>;
2378
2543
  /** Lifecycle status (`active` | `revoked`). */
2379
2544
  status: Generated<string>;
2380
2545
  revocation_reason: string | null;
@@ -1,4 +1,4 @@
1
- import { type DeploymentIdentity } from '@kici-dev/engine';
1
+ import { type DeploymentIdentity, type ConfigPaths } from '@kici-dev/engine';
2
2
  /**
3
3
  * The pinned `<node> <kici-admin>` invocation for a posix bare-metal unit, or
4
4
  * `undefined` when the shim cannot be located.
@@ -91,4 +91,34 @@ export declare function resolveWindowsAdminPath(execPath: string, entryPath: str
91
91
  * shells cannot share one quoting.
92
92
  */
93
93
  export declare function readDeploymentIdentity(env?: NodeJS.ProcessEnv, execPath?: string, entryPath?: string | undefined, fileExists?: (p: string) => boolean): DeploymentIdentity;
94
+ /**
95
+ * Where this orchestrator's own configuration lives on its host.
96
+ *
97
+ * `envFile` and `composeFile` come from the env the installer injects
98
+ * (`KICI_DEPLOY_CONFIG_FILE` / `KICI_DEPLOY_COMPOSE_FILE`), because a running
99
+ * process cannot derive either: systemd's `EnvironmentFile=` delivers the
100
+ * variables and not the filename, and a compose container never sees the host
101
+ * path at all. `scalerConfig` needs no stamp — the orchestrator already holds
102
+ * it in its own config — so every orchestrator reports it, including hand-run
103
+ * ones and installs that predate the stamp.
104
+ *
105
+ * Values are trimmed for the same reason the deployment reader trims them:
106
+ * they arrive through an env file, where a hand edit or a writer that leaves
107
+ * the trailing byte on attaches a space or a newline. A known path carrying a
108
+ * stray space is still a known path, and dropping it would discard an answer
109
+ * we have.
110
+ *
111
+ * No path is checked for existence. On bare metal such a check would pass; in
112
+ * a compose container it would fail for every path, because these are HOST
113
+ * paths the container cannot see — blanking the value for exactly the
114
+ * deployment shape that needs it most.
115
+ *
116
+ * This is a standalone reader rather than a branch of `readDeploymentIdentity`
117
+ * because that function returns early for `compose`, and anything placed after
118
+ * that return does nothing for compose deployments.
119
+ */
120
+ export declare function readConfigPaths(env?: NodeJS.ProcessEnv, scaler?: {
121
+ scalerConfigPath?: string;
122
+ scalerConfigDir?: string;
123
+ }): ConfigPaths;
94
124
  //# sourceMappingURL=deployment-identity.d.ts.map
@@ -7,6 +7,7 @@
7
7
  import type { DiagnosticCheck } from '../types.js';
8
8
  import { checkDbConnectivity } from './db.js';
9
9
  import { checkBackupFreshness } from './backup.js';
10
+ import { checkRunHistoryRetention } from './retention.js';
10
11
  import { checkWsToPlatform } from './ws.js';
11
12
  import { checkAgentConnectivity } from './agents.js';
12
13
  import { checkDiskSpace } from './disk.js';
@@ -16,5 +17,5 @@ import { checkScalerProvisioning } from './scaler.js';
16
17
  import { checkFirecrackerNetwork } from './firecracker-network.js';
17
18
  /** All diagnostic checks in display order. */
18
19
  export declare const defaultChecks: DiagnosticCheck[];
19
- export { checkDbConnectivity, checkBackupFreshness, checkWsToPlatform, checkAgentConnectivity, checkDiskSpace, checkConfigValidity, checkCertificateExpiry, checkScalerProvisioning, checkFirecrackerNetwork, };
20
+ export { checkDbConnectivity, checkBackupFreshness, checkRunHistoryRetention, checkWsToPlatform, checkAgentConnectivity, checkDiskSpace, checkConfigValidity, checkCertificateExpiry, checkScalerProvisioning, checkFirecrackerNetwork, };
20
21
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,24 @@
1
+ import type { DiagnosticDeps, DiagnosticResult } from '../types.js';
2
+ import { type RetentionWindows } from '../../queue/retention.js';
3
+ /** Rows past which an unbounded `execution_runs` is worth warning about. */
4
+ export declare const RETENTION_WARN_ROW_THRESHOLD = 500000;
5
+ /** What the verdict needs to know. Gathered by the check, decided here. */
6
+ export interface RetentionVerdictInput {
7
+ windows: RetentionWindows;
8
+ coldStoreEnabled: boolean;
9
+ /** `execution_runs` row count. Only read when every window is disabled. */
10
+ rows: number;
11
+ announcedAt: Date | null;
12
+ now: Date;
13
+ rowThreshold?: number;
14
+ }
15
+ /**
16
+ * Decide the check's outcome from already-gathered facts.
17
+ *
18
+ * Split from the check so the branches are testable without standing up a
19
+ * database — in particular the WARN branch, which needs a row count larger
20
+ * than any fixture would seed.
21
+ */
22
+ export declare function retentionVerdict(input: RetentionVerdictInput): Pick<DiagnosticResult, 'status' | 'message' | 'details'>;
23
+ export declare function checkRunHistoryRetention(deps: DiagnosticDeps): Promise<DiagnosticResult>;
24
+ //# sourceMappingURL=retention.d.ts.map
@@ -8,6 +8,7 @@ import type { Kysely } from 'kysely';
8
8
  import type { Database } from '../db/types.js';
9
9
  import type { AgentRegistry } from '../agent/registry.js';
10
10
  import type { ScalerManager } from '../scaler/manager.js';
11
+ import type { ClusterSettingsReader } from '../cluster/cluster-settings-reader.js';
11
12
  /** Result of a single diagnostic check. */
12
13
  export interface DiagnosticResult {
13
14
  /** Human-readable check name (e.g., "Database connectivity"). */
@@ -35,6 +36,12 @@ export interface DiagnosticDeps {
35
36
  tlsCertPath?: string;
36
37
  /** Scaler manager for recent spawn-failure health (optional -- no scaler configured). */
37
38
  scalerManager?: ScalerManager;
39
+ /**
40
+ * Fleet-wide settings reader. When present, a check reads the live
41
+ * `cluster_settings` value rather than only the configured default — so
42
+ * `kici-admin diagnose` reports what the cluster is actually doing.
43
+ */
44
+ clusterSettings?: ClusterSettingsReader;
38
45
  }
39
46
  /** A diagnostic check function. May return one result or several (e.g. one per scaler backend). */
40
47
  export type DiagnosticCheck = (deps: DiagnosticDeps) => Promise<DiagnosticResult | DiagnosticResult[]>;
@@ -137,7 +137,7 @@ export declare class EventRouter {
137
137
  private stopped;
138
138
  private readonly registrationIndex;
139
139
  private readonly nodeId;
140
- private client;
140
+ private listener;
141
141
  private lastProcessedEventId;
142
142
  constructor(options: EventRouterOptions);
143
143
  /**
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The shape of the orchestrator's fault-injection policy.
3
+ *
4
+ * The policy's *implementation* is test-only and lives in `src/testing/`, which
5
+ * is excluded from the npm tarball, the container image and the public mirror.
6
+ * The type itself has to ship: three production modules (`app.ts`,
7
+ * `orchestrator-core.ts`, `server.ts`) declare an optional `faultInjection`
8
+ * field, so a projection without this file fails to typecheck with three
9
+ * TS2307s. Only the declaration lives here — its one dependency is a type from
10
+ * `@kici-dev/engine`, so nothing test-only is pulled along with it.
11
+ */
12
+ import type { OrchCapabilities } from '@kici-dev/engine';
13
+ /**
14
+ * The set of synthetic faults a test-only entrypoint can inject into the
15
+ * orchestrator. Every field is optional: an absent field means "no fault at
16
+ * this seam". A whole `undefined` policy means the orchestrator runs with no
17
+ * fault injection at all.
18
+ */
19
+ export interface OrchestratorFaultInjection {
20
+ /**
21
+ * Per-event-name fault map: while `event.attempts <= N`, the EventRouter
22
+ * throws a synthetic dispatch error to drive the retry / DLQ path.
23
+ */
24
+ eventFailFirstN?: Record<string, number>;
25
+ /**
26
+ * Skip the S3 sentinel validation on cluster-identity bootstrap. Read
27
+ * independently of `KICI_TEST_MODE` (matching today's behavior).
28
+ */
29
+ skipS3Sentinel?: boolean;
30
+ /**
31
+ * Predicate over an OIDC `audience`: when true, the *initial* provenance
32
+ * mint fails transiently (defer), so an E2E can exercise the
33
+ * deferred-attestation retry + per-run serve path.
34
+ */
35
+ initialMintFault?: (audience: string) => boolean;
36
+ /**
37
+ * Predicate over an OIDC `audience`: when true, the retrier's later re-mint
38
+ * TERMINALLY REJECTS the audience, exercising the reject → gauge-exclusion →
39
+ * re-arm cycle.
40
+ */
41
+ remintReject?: (audience: string) => boolean;
42
+ /**
43
+ * Invoked by `handleRerunRequest` before `onRerun`, so an HA E2E can make
44
+ * the first coordinator slow enough that the Platform relay fails over.
45
+ */
46
+ beforeRerun?: () => Promise<void>;
47
+ /**
48
+ * Transform the advertised capability manifest — used to reproduce an older
49
+ * / sourceless orchestrator that predates a given dashboard capability.
50
+ */
51
+ capabilitiesTransform?: (c: OrchCapabilities) => OrchCapabilities;
52
+ }
53
+ //# sourceMappingURL=fault-injection-types.d.ts.map
@@ -7,10 +7,10 @@
7
7
  * isolation. One pure command-builder drives live provisioning, the rendered
8
8
  * boot script, and (read-only) verification.
9
9
  *
10
- * This is HOST setup, distinct from the runtime per-VM isolation in
11
- * scaler/nftables.ts (added at spawn / removed at destroy). The two share the
12
- * nft table name but have separate lifecycles; this module never touches the
13
- * per-VM rules.
10
+ * This is HOST setup, distinct from the runtime per-VM isolation the rule
11
+ * builder in `@kici-dev/shared/net` performs (added at spawn / removed at
12
+ * destroy). The two share the nft table name but have separate lifecycles;
13
+ * this module never touches the per-VM rules.
14
14
  */
15
15
  import { FIRECRACKER_NET_INTERFACES } from './net-interfaces.js';
16
16
  export { FIRECRACKER_NET_INTERFACES };
@@ -42,10 +42,17 @@ export declare function cidrToNetwork(cidr: string): string;
42
42
  * Pure — performs no I/O. `provisionBridge` executes these; `renderBootScript`
43
43
  * serializes them.
44
44
  *
45
- * The nft `delete table`/`add table` here only ever touches `cfg.table`, so a
46
- * coord-B provision never wipes coord A's table (and vice versa). Every
47
- * forward/postrouting/MSS rule is source-scoped to the bridge subnet so two
48
- * tables on the shared hooks do not cross-drop each other's traffic.
45
+ * The command list NEVER deletes the table. It is a self-heal `ensureHostReady`
46
+ * runs it whenever `verifyBridge` reports unhealthy, which happens on any of
47
+ * four conditions none of which knows how many VMs are live — so dropping the
48
+ * table would leave every running VM fail-open, with full RFC1918 and
49
+ * cloud-metadata reach, until it was destroyed. Instead the baseline lives in
50
+ * its own regular chain (`baseline`, see {@link BASELINE_CHAIN}) that is flushed
51
+ * and refilled, and the hooked `forward` chain keeps its per-VM rules
52
+ * untouched, reaching the baseline through a `jump` appended as its last rule.
53
+ *
54
+ * Every forward/postrouting/MSS rule is source-scoped to the bridge subnet so
55
+ * two tables on the shared hooks do not cross-drop each other's traffic.
49
56
  */
50
57
  export declare function buildBridgeCommands(cfg: FirecrackerBridgeConfig): CommandSpec[];
51
58
  export declare const NM_CONF_PATH = "/etc/NetworkManager/conf.d/90-kici-unmanaged.conf";
@@ -71,13 +78,61 @@ export interface BridgeHealth {
71
78
  bridgeUp: boolean;
72
79
  addrPresent: boolean;
73
80
  tablePresent: boolean;
81
+ /** The regular baseline chain exists and `forward` ends in a jump to it. */
82
+ baselineChainPresent: boolean;
83
+ /** Every enslaved kici-* TAP carries bridge port isolation. */
84
+ tapIsolationPresent: boolean;
74
85
  healthy: boolean;
75
86
  detail: string;
76
87
  }
88
+ /**
89
+ * Delete every rule in the table's `forward` chain that no live VM owns.
90
+ *
91
+ * A per-VM rule matches one host address or one exact TAP name; everything else
92
+ * in that chain belongs to this provisioner — the tail `jump baseline`, and on
93
+ * a host provisioned by an older boot script, the six baseline rules that used
94
+ * to sit directly in `forward`. Removing only those makes re-provisioning
95
+ * idempotent and upgrades an old-shaped host in place, without the `delete
96
+ * table` that used to strip every running VM's isolation.
97
+ *
98
+ * One exception, and it is not this provisioner's: on a host that also runs a
99
+ * container-mode agent, the agent installs ONE drop set for its whole
100
+ * {@link JOB_NETWORK_SUBNET} rather than one per job container, so that a
101
+ * customer image's `ENTRYPOINT` cannot run ahead of its own rules. nft reports
102
+ * a subnet source as a prefix object, which is exactly what makes
103
+ * `listForwardRules` report no per-agent identifier — so those rules read as
104
+ * this provisioner's and would be reaped, leaving every job container already
105
+ * running at that moment with no egress filtering until the next job repairs
106
+ * it. They are spared by name.
107
+ *
108
+ * Best-effort: a chain that cannot be read yields no rules, so a fresh host
109
+ * sweeps nothing and provisioning proceeds. A chain whose TEXT cannot be read
110
+ * sweeps nothing either — the spared set is unknown at that point, and deleting
111
+ * an unclassified rule from a chain carrying a security control is the wrong
112
+ * direction to guess in.
113
+ */
114
+ export declare function sweepUnownedForwardRules(cfg: FirecrackerBridgeConfig, opts?: ExecOptions): Promise<number>;
77
115
  /** Provision (or heal) one Firecracker host bridge. Throws on any failure. */
78
116
  export declare function provisionBridge(cfg: FirecrackerBridgeConfig, opts?: ExecOptions): Promise<void>;
79
117
  /** Read-only health probe for one bridge. Never throws on a missing resource. */
80
118
  export declare function verifyBridge(cfg: FirecrackerBridgeConfig, opts?: ExecOptions): Promise<BridgeHealth>;
119
+ /**
120
+ * True when the LAST rule of a `nft -j list chain … forward` listing is a jump
121
+ * to {@link BASELINE_CHAIN}.
122
+ *
123
+ * Position is the assertion, not mere presence: a jump that is not last would
124
+ * let the baseline's unconditional internet accept run before a per-VM
125
+ * `denyAll` drop.
126
+ */
127
+ export declare function forwardEndsInBaselineJump(nftJson: string): boolean;
128
+ /**
129
+ * Names of the kici-* TAPs enslaved to the bridge that are NOT port-isolated,
130
+ * read from `ip -d -j link show master <bridge>`.
131
+ *
132
+ * Only kici-* TAPs are checked: an operator may legitimately enslave another
133
+ * interface, and isolating it is not this module's business.
134
+ */
135
+ export declare function unisolatedTapNames(ipJson: string): string[];
81
136
  /** Remove the bridge + its nft table. Leaves the host-scoped NM conf in place. */
82
137
  export declare function teardownBridge(cfg: FirecrackerBridgeConfig, opts?: ExecOptions): Promise<void>;
83
138
  /** Serialize the provisioning command list into a dependency-free boot script. */
@@ -18,7 +18,9 @@
18
18
  *
19
19
  * Knows nothing about git, clones, or agents.
20
20
  */
21
- import type { GitCredentialRef, GitCredentialResult, ProviderGitAuth } from '@kici-dev/engine';
21
+ import type { GitCredentialRef, GitCredentialResult, ProviderGitAuth, TrustTier } from '@kici-dev/engine';
22
+ import type { ContextStore } from '../contexts/context-store.js';
23
+ import type { JobDispatchContext } from '../contexts/protection/pipeline.js';
22
24
  import type { SecretResolverApi } from '../secrets/secret-resolver.js';
23
25
  import { type MintedToken } from './installation-token.js';
24
26
  /** Injected so tests need no network and so the mint seam stays explicit. */
@@ -35,6 +37,19 @@ type MintFn = (args: {
35
37
  * the decryption stays in the one place that already owns it.
36
38
  */
37
39
  type SecretOutputFn = (runId: string, jobId: string, key: string) => Promise<string | null>;
40
+ /**
41
+ * What a qualified `<context>:<key>` reference is authorized against.
42
+ *
43
+ * Required, not optional: a caller that could omit it would silently get the
44
+ * ungated lookup back, which is the exact shape this class used to have. A
45
+ * caller with no job to authorize against — there is none today — would have to
46
+ * say so explicitly.
47
+ */
48
+ export interface BrokerGateContext {
49
+ /** The dispatch facts the named context's protection rules evaluate against. */
50
+ dispatchCtx: JobDispatchContext;
51
+ trustTier: TrustTier | undefined;
52
+ }
38
53
  export interface BrokerResolveArgs {
39
54
  orgId: string;
40
55
  repositories: readonly string[];
@@ -43,14 +58,23 @@ export interface BrokerResolveArgs {
43
58
  permissions?: Readonly<Record<string, string>>;
44
59
  runId?: string;
45
60
  jobId?: string;
61
+ /** Server truth a `<context>:<key>` reference is gated on. */
62
+ gate: BrokerGateContext;
46
63
  }
47
64
  export declare class GitCredentialBroker {
48
65
  private readonly secretResolver;
66
+ private readonly contextStore;
49
67
  private readonly sourceAuth;
50
68
  private readonly mint;
51
69
  private readonly secretOutputs;
52
70
  constructor(deps: {
53
71
  secretResolver: SecretResolverApi;
72
+ /**
73
+ * Reads the context a qualified reference names, so its protection rules
74
+ * can run. Required: without it there is no gate, and a broker with no gate
75
+ * resolves any secret in the org.
76
+ */
77
+ contextStore: ContextStore;
54
78
  /**
55
79
  * Yields the source credential for a repository — normally
56
80
  * `bundle.cloneTokenProvider.issueGitAuth(...)`. Injected rather than
@@ -79,7 +103,16 @@ export declare class GitCredentialBroker {
79
103
  * `isQualifiedSecretRef` in `packages/sdk/src/workflow.ts`.
80
104
  */
81
105
  private sourced;
82
- /** Route a qualified reference to the store that owns it. */
106
+ /**
107
+ * Route a qualified reference to the store that owns it.
108
+ *
109
+ * A store-backed reference goes through the job secret gate, which refuses a
110
+ * reserved namespace, refuses an untrusted contributor, and runs the NAMED
111
+ * context's protection rules before reading anything. The reserved `needs:`
112
+ * context keeps its own path: it reads no secret store at all, only a
113
+ * run-scoped output bound to `(runId, jobId)` and written by an upstream this
114
+ * job declared in `needs` — so the `needs` edge is already the authorization.
115
+ */
83
116
  private resolveQualified;
84
117
  /**
85
118
  * Resolve a secret output this job inherited from a `needs` upstream.
@@ -6,13 +6,18 @@
6
6
  * `run_secret_outputs`, and is deleted when the run completes — so this reads
7
7
  * the store that already exists rather than adding a second one.
8
8
  */
9
+ import type { ResolvedMasterKeys } from '../secrets/config.js';
9
10
  import type { SecretOutputStore } from '../secrets/secret-output-store.js';
10
11
  export interface InheritedSecretDeps {
11
12
  secretOutputStore: SecretOutputStore;
12
13
  /** Upstream job ids for a job, in the same shape the run merge path uses. */
13
14
  upstreamJobIds: (runId: string, jobId: string) => Promise<string[]>;
14
- /** The orchestrator's master secret key, as configured. */
15
- secretKey: string;
15
+ /**
16
+ * The orchestrator's master key, plus the previous generation during a
17
+ * rotation grace window — a stored output sealed under the old key still
18
+ * unseals until `rotate-key` has swept the table.
19
+ */
20
+ masterKeys: ResolvedMasterKeys;
16
21
  }
17
22
  /**
18
23
  * Build the `secretOutputs` lookup the credential broker takes.
@@ -1,13 +1,16 @@
1
1
  /**
2
2
  * Per-job facts the git credential relay needs, read from server truth.
3
3
  *
4
- * The relay never takes the org or the source repository from request params —
5
- * an agent could name any repository it liked. Both come from the run row the
6
- * orchestrator itself wrote at dispatch.
4
+ * The relay never takes any of these from request params — an agent could name
5
+ * any repository, declare any credential, and claim any trust tier it liked.
6
+ * Every field comes from rows the orchestrator itself wrote at dispatch: the
7
+ * run row for the org, the repository, the branch, the trigger and the
8
+ * contributor's trust tier, and the dispatch record for the credentials the
9
+ * job's lock entry declared.
7
10
  */
8
11
  import type { Kysely } from 'kysely';
9
12
  import type { Database } from '../db/types.js';
10
13
  import type { JobCredentialContext } from '../ws/git-credential-relay.js';
11
14
  /** Build the `jobContext` lookup the git credential handler takes. */
12
- export declare function createJobCredentialContextReader(db: Kysely<Database>): (runId: string) => Promise<JobCredentialContext | null>;
15
+ export declare function createJobCredentialContextReader(db: Kysely<Database>): (runId: string, jobId: string) => Promise<JobCredentialContext | null>;
13
16
  //# sourceMappingURL=job-context.d.ts.map