import type { DeployCallbacks } from "../../types/callbacks.js"; import type { DeployParams } from "../../types/params.js"; import type { CloudFormationService } from "../../services/infrastructure/CloudFormationService.js"; import type { EcsService } from "../../services/infrastructure/EcsService.js"; import type { EcsServiceResolver } from "../../services/infrastructure/EcsServiceResolver.js"; /** * Read the application's Database-stack connection outputs (endpoint/port * keys only). Returns `{}` when the stack or its outputs do not exist, and * `undefined` when the read itself failed — callers use that distinction to * warn that endpoint stability could not be verified rather than silently * treating a failed read as "no endpoints". */ export declare function captureDatabaseConnectionOutputs(cfnService: CloudFormationService, appName: string, abortSignal?: AbortSignal): Promise | undefined>; /** * Snapshot each live ECS service's current task-definition ARN before the * stack loop runs. The post-deploy reconcile compares these against the * post-deploy ARNs to tell which services CloudFormation already rolled * during the deploy (ARN changed ⇒ tasks relaunched after the Database phase * and re-resolved the updated secret) versus which still run pre-deploy tasks * (ARN unchanged ⇒ stale connection values). Inferring this from build state * is wrong in the primary scenario: a config-only database replacement * rebuilds the same content-hash image, so the Compute stack no-ops and never * rolls anything. * * Returns `{}` ONLY on proof that the application ran nothing: a Compute * stack CloudFormation refuses by name. Every other empty outcome is * `undefined`, including a Compute stack that exists and exports no * deployable service — that is indistinguishable from an application * deployed before the `DeployableService` exports existed, which runs * services this read cannot see. Reading it as `{}` would make the reconcile * find every one of those services absent from the baseline on the upgrade * deploy and skip the restart it exists to perform. * * The consumer trusts that split exactly: a service absent from a `{}` * baseline was created during the deploy, and an `undefined` baseline * restarts every service. An extra roll is harmless, a missed one is not. */ export declare function captureServiceTaskDefinitions(ecsResolver: EcsServiceResolver, ecsService: EcsService, appName: string, abortSignal?: AbortSignal): Promise | undefined>; export interface DatabaseEndpointReconcileParams { appName: string; /** Pre-deploy connection-output capture; `undefined` when the read failed. */ connectionOutputsBefore: Record | undefined; /** * Pre-deploy serviceArn → task-definition ARN baseline; `undefined` when * the read failed (every service is then restarted — the safe direction). */ serviceTaskDefinitionsBefore: Record | undefined; services: { cfnService: CloudFormationService; ecsService: EcsService; ecsResolver: EcsServiceResolver; }; callbacks: DeployCallbacks; confirmRestart?: DeployParams["confirmDatabaseEndpointRestart"]; abortSignal?: AbortSignal; } export type DatabaseEndpointReconcileOutcome = { kind: "not-needed"; } | { kind: "unverified"; } | { kind: "already-current"; } | { kind: "declined"; } | { kind: "reconciled"; services: string[]; } | { kind: "failed"; } | { kind: "cancelled"; }; /** * Post-deploy reconcile for a replaced database. A create-only property * change (e.g. `snapshotIdentifier`) replaces the database: the credentials * secret updates in place (same ARN, new host), so the ECS task definition is * byte-identical and CloudFormation makes no ECS change — running tasks keep * the stale connection values injected at launch and silently write to the * doomed old database until CloudFormation deletes it. This step diffs the * Database stack's connection outputs across the deploy and restarts the * services whose task-definition ARN did not change during the deploy (those * whose ARN moved were already relaunched after the Database phase). * Best-effort: every failure warns with a `fjall rollout` hint and never * fails the deploy. */ export declare function reconcileDatabaseEndpointChange(params: DatabaseEndpointReconcileParams): Promise;