import type { HerokuApiClientOptions } from '@heroku/heroku-fetch'; import type { App, BuildpackInstallation, ConfigVar, Dyno } from '@heroku/types/3.sdk'; import type { ResourceCtx } from '../../../core/extend-resource.js'; import { type WaitForInfoOptions } from './wait-for-info.js'; export type ExecOptions = { signal?: AbortSignal; }; /** * Raw facts the CLI needs to decide whether — and how — Heroku Exec can * be enabled for an app. This helper only gathers; every branch * (Shield restriction, container-stack warning, missing-buildpack * error, the deprecated `HEROKU_EXEC_URL` add-on notice) stays in the * caller so the SDK owns no presentation or prompting. */ export type ExecPrereqs = { /** Installed buildpacks, for the exec-buildpack presence check. */ buildpacks: BuildpackInstallation[]; /** `build_stack.name`, e.g. `'container'`. */ buildStack: string | undefined; /** Full config-var map; the caller reads `HEROKU_EXEC_URL` off it. */ configVars: ConfigVar; /** Whether the `runtime-heroku-exec` feature is already enabled. */ featureEnabled: boolean; /** App generation; `'fir'` apps do not support exec. */ generation: string; /** App's Private Space, if any (carries `shield`). */ space: App['space']; }; /** * Gather the app facts that gate Heroku Exec in one parallel round-trip: * app info, buildpack installations, config vars, and the exec feature. * * Returns raw facts only — the caller branches on them. `configVars` is * returned whole because the caller inspects `HEROKU_EXEC_URL` (the * deprecated add-on) as well as passing config through to the exchange. */ export declare function execPrereqs(ctx: Pick, appIdentity: string, options?: ExecOptions): Promise; /** * Enable the `runtime-heroku-exec` feature on an app. Used both on the * first-run restart path and on the Private-Space buildpack path, so it * stays a bare enable — the caller decides whether a restart follows. */ export declare function enableExec(ctx: Pick, appIdentity: string, options?: ExecOptions): Promise; /** * Thrown by {@link restartForExec} the moment the awaited dyno reports * `crashed`, so the caller can surface the failure immediately rather * than waiting out the remaining poll attempts. */ export declare class DynoCrashedError extends Error { readonly dyno: Dyno; readonly id = "dyno_crashed"; constructor(dyno: Dyno); } export type RestartForExecOptions = WaitForInfoOptions & { /** * Milliseconds to wait after enabling the feature before restarting, * letting the enable propagate. Defaults to 2000, matching the * historical CLI behavior. */ settleMs?: number; }; /** * Restart all of an app's dynos and wait for the named dyno to come * back `up`. Enabling Heroku Exec for the first time requires a dyno * restart, so this bundles the settle delay, `dyno.restartAll`, and the * wait-for-`up` poll into one step. A `crashed` dyno throws * {@link DynoCrashedError} at once instead of exhausting the attempts. * * The wait is bounded by {@link WaitForInfoOptions.attempts} (default * 20). Callers that need to tolerate a slow boot should raise it. */ export declare function restartForExec(ctx: Pick, appIdentity: string, dynoIdentity: string, options?: RestartForExecOptions): Promise; /** Connection info the exec-manager returns for a client-key exchange. */ export type ExecCredentials = { client_user: string; dyno_ip: string; proxy_public_key: string; tunnel_host: string; }; export type ExchangeExecCredentialsOptions = { /** API key used as the Basic-auth password (username is the app). */ apiKey: string; /** * Options forwarded to the raw `HerokuApiClient`. The exec-manager is * not in the routes registry, so the call is issued via a bare client * with `service: 'custom'`. */ clientOptions?: Omit; /** * App config vars. When `HEROKU_EXEC_URL` is present (the deprecated * add-on), its embedded credentials and the `/api/v1` prefix are used. */ configVars?: ConfigVar; /** Target dyno, e.g. `'web.1'`. */ dyno: string; /** Extra request headers (e.g. from `HEROKU_HEADERS`). */ headers?: Record; /** OpenSSH-format public key generated by the caller. */ publicKey: string; signal?: AbortSignal; }; /** * Exchange a client public key for exec connection info. * * Issues `PUT {execHost}{apiPath}/{dyno}` with `{client_key}` and Basic * auth (`app:apiKey`, or the credentials embedded in `HEROKU_EXEC_URL`) * via a bare `HerokuApiClient` — the exec-manager is a custom host with * no routes entry and no bearer token (the empty `token` lets the Basic * `Authorization` header survive). The caller feeds the returned info, * plus the private key it holds, to its own SSH transport; the SDK does * not open the connection. * * @param ctx - Internal: supplied by the SDK's dyno extension to thread the * resolved client identity and cancellation signal into the custom-host * client. Standalone callers omit it, and the client falls back to the * pre-threading bare construction. */ export declare function exchangeExecCredentials(appIdentity: string, options: ExchangeExecCredentialsOptions, ctx?: Pick): Promise; /** A running exec reservation, as reported by the exec-manager status endpoint. */ export type ExecReservation = { [key: string]: unknown; dyno_name: string; }; export type ExecStatusOptions = { apiKey: string; clientOptions?: Omit; configVars?: ConfigVar; headers?: Record; signal?: AbortSignal; }; /** * List the app's running exec reservations. * * Issues `GET {execHost}{apiPath}` (no dyno segment) with the same * custom-host Basic-auth setup as {@link exchangeExecCredentials}. The * caller correlates each reservation's `dyno_name` with live dyno state * for display. * * @param ctx - Internal: supplied by the SDK's dyno extension to thread the * resolved client identity and cancellation signal into the custom-host * client. Standalone callers omit it, and the client falls back to the * pre-threading bare construction. */ export declare function execStatus(appIdentity: string, options: ExecStatusOptions, ctx?: Pick): Promise;