import { type Result } from "@fjall/generator"; import { type ServiceArtefact } from "@fjall/util"; import type { AwsCredentials } from "../../types/credentials.js"; import type { DeployCallbacks } from "../../types/callbacks.js"; import { EcsService } from "../../services/infrastructure/EcsService.js"; import { EcsServiceResolver } from "../../services/infrastructure/EcsServiceResolver.js"; import { EcrImageInspectorService } from "../../services/infrastructure/EcrImageInspectorService.js"; import { SsmParameterMetadataService } from "../../services/infrastructure/SsmParameterMetadataService.js"; import { type ApplicationSecretsDrift } from "./secretsDrift.js"; export interface RestartParams { /** Application name. */ target: string; awsCredentials: AwsCredentials; callbacks: DeployCallbacks; /** Restrict the restart to a single ECS service by name (case-insensitive). */ serviceName?: string; abortSignal?: AbortSignal; } /** One ECS service a restart rolled, identified the way drift rows are. */ export interface RestartedService { serviceName: string; clusterName: string; } export interface RestartResult { target: string; /** * Per-service image identity of what is now running — the image each * service's own build runs, recovered in the app's image repository, under * a fresh task-definition revision. A service with no container that runs * its own build from that repository has none, as a full deploy records * none for it; the schema gate is never its build, whatever its image. One * whose tag cannot be recovered, or whose containers there run more than * one image, is omitted with a warning. */ artefacts: ServiceArtefact[]; /** * Every service this restart rolled, in roll order. Independent of * `artefacts`, which omits every service the restart rolled whose * `selectAppImageContainers` verdict is an `AppImageRefused`, and a `found` * one whose image tag could not be recovered. Reconstructing the count from * `artefacts` leaves those services out, and reconstructing it from * `preRestartDrift` reports the number JUDGED rather than the number * restarted. * * The cluster rides along because an application's services may span * clusters, so the name alone does not identify one. Renderers compose * their own label; the engine does not hand out one. */ restartedServices: RestartedService[]; /** * Version of each consumed SSM parameter as SSM reported it immediately * BEFORE the roll began, recorded onto the restart Release, where a caller * mints one, as the baseline this restart was taken against. The CLI's * tracker posts it only beside a non-empty `artefacts`, so a restart that * records no image for any service records no baseline there. It is NOT an * attestation of what the relaunched tasks resolved: a rotation landing * between this read and a task's launch is not reflected here. * * Empty when the drift probe failed, as when the application injects no * SSM parameters, so on this line `{}` does not tell the two apart. */ appliedParameterVersions: Record; /** Drift state observed BEFORE the restart (what this restart healed). */ preRestartDrift?: ApplicationSecretsDrift; durationMs: number; cancelled?: boolean; } export interface RestartServices { ecsService: EcsService; ecsResolver: EcsServiceResolver; ecrImageInspector: EcrImageInspectorService; ssmService: SsmParameterMetadataService; } export declare function createRestartServices(awsCredentials: AwsCredentials): RestartServices; export type SecretsDriftProbeParams = Omit; /** * Read-only secrets-drift probe over an application's live ECS services — * the same resolution ladder as `restart()` without rolling anything. * Used by the CLI's pre-confirm drift display and the webapp's drift pulse. */ export declare function probeSecretsDrift(params: SecretsDriftProbeParams, injectedServices?: RestartServices): Promise>; /** Per-service snapshot of the PRIMARY ECS deployment's rollout state. */ export interface ServiceDeploymentStatus { serviceName: string; serviceArn: string; /** The cluster this service runs in — one app's services may span clusters. */ clusterArn: string; clusterName: string; desiredCount: number; runningCount: number; pendingCount: number; /** `COMPLETED` | `IN_PROGRESS` | `FAILED` — absent on services predating rollout-state reporting. */ rolloutState?: string; rolloutStateReason?: string; failedTasks?: number; /** Task definition the PRIMARY deployment is rolling out. */ taskDefinition?: string; /** Deployment count on the service — >1 means an old deployment is still draining. */ activeDeployments: number; /** * Set when ECS reported the service under `failures` instead of describing * it — the reason ECS gave (`MISSING` when the cluster no longer holds the * service). Such a service has zero counts and is never complete. */ ecsFailureReason?: string; /** The smoke verdict for this service — see `isServiceDeploymentComplete`. */ completed: boolean; } export interface ApplicationServiceStatus { target: string; services: ServiceDeploymentStatus[]; /** True only when EVERY discovered service's PRIMARY deployment is complete. */ allCompleted: boolean; } /** * Read-only per-service deployment-status probe (`fjall services`) — the * same resolution ladder as `restart()`/`probeSecretsDrift()`, reporting each * service's PRIMARY deployment rollout state. This is the CD smoke surface * from the worker-deploy-safety design (item 12): a worker that CloudFormation * waved through but is now churning shows `IN_PROGRESS`/`FAILED` (or a * running-count shortfall) here instead of being invisible to the gate. */ export declare function probeServiceDeploymentStatus(params: SecretsDriftProbeParams, injectedServices?: RestartServices): Promise>; /** * Restart an application's ECS services without building or deploying: * re-register each service's live task definition unchanged and roll the * service onto the new revision. Relaunched tasks re-resolve their SSM * `valueFrom` secrets at start-up — this is the lightweight rollout primitive * that makes a secret rotation take effect (R2). The revision bump is what * lets the secrets-drift probe self-heal: drift compares parameter * modification time against task-definition registration time. */ export declare function restart(params: RestartParams, injectedServices?: RestartServices): Promise>;