import type { Dyno } from '@heroku/types/3.sdk'; import type { ResourceCtx } from '../../../core/extend-resource.js'; /** * Documented dyno states from the Platform API: * https://devcenter.heroku.com/articles/platform-api-reference#dyno * * Recommended for autocomplete in {@link WaitForInfoOptions.states}, * which accepts any string at runtime — the platform does not commit * to a closed set, so the comparison is plain string equality. */ export type DynoState = 'crashed' | 'down' | 'idle' | 'starting' | 'up'; /** * Thrown by {@link waitForInfo} when `states` was set, the dyno was * reachable, but its `state` never matched within the configured * number of attempts. Carries the last observed dyno so callers can * branch on its state (e.g. distinguish a `crashed` dyno from one * stuck in `starting`). */ export declare class DynoNotReadyError extends Error { readonly dyno: Dyno; readonly expectedStates: ReadonlyArray; readonly attempts: number; readonly id = "dyno_not_ready"; constructor(dyno: Dyno, expectedStates: ReadonlyArray, attempts: number); } export type WaitForInfoOptions = { /** * Maximum total number of `dyno.info` calls before giving up. * Defaults to 20. Each attempt is one info call; the delay * between attempts is {@link WaitForInfoOptions.delayMs}. */ attempts?: number; /** * Delay between attempts in milliseconds. Defaults to 1000. * On a 429 response, the platform's `Retry-After` header takes * precedence over this value for the next wait. */ delayMs?: number; /** * Fires after every successful `dyno.info` call, including ones * whose `state` does not yet match {@link WaitForInfoOptions.states} * and trigger another retry, AND for the final matching dyno * before it is returned. Use this to surface live state * transitions in a UI (e.g. a CLI spinner that updates * `starting → up`). Not called when an attempt errors (404, 429, * 503). Exceptions thrown from this callback propagate and end * the wait — there is no implicit catch. */ onPoll?: (dyno: Dyno) => void; signal?: AbortSignal; /** * If set, only return when the dyno's `state` is one of these. * If omitted, the call returns on the first 2xx response * regardless of state — useful for racing past the post-creation * 404 window without waiting for the dyno to be runnable. The * recommended values are documented as {@link DynoState}; any * string is accepted. */ states?: ReadonlyArray; }; /** * Poll `dyno.info` until the dyno exists and (optionally) reaches a * caller-specified state. Absorbs two distinct races: * * - **Post-creation 404.** The platform briefly returns 404 for a * newly-provisioning dyno even after `dyno.create` resolves * (also observable from log events emitting "Starting process" * before the dyno row is queryable). Callers that just need the * row to exist should omit `states` and accept the first 2xx — * the dyno's `state` value does not gate the return. * - **Wait for runnable.** Callers that need to act on the dyno * (open an SSH connection, exec a one-off command) need it in * `starting` or `up` first. Pass `{states: ['starting', 'up']}` * and the helper polls until the dyno reports one of those * states. * * Retry policy: 404, 429, and 503 are treated as transient and * trigger another attempt. 429 responses honor `Retry-After` for * the next wait. Any other error throws immediately. * * After {@link WaitForInfoOptions.attempts} attempts: * - If state-filtered, throws {@link DynoNotReadyError} carrying * the last observed dyno. * - Otherwise rethrows the last transient error. * * @example * ```ts * // Race past the post-creation 404; return on first 2xx regardless of state. * await platform.dyno.waitForInfo(app, name) * * // Wait for the dyno to be ready to accept connections. * await platform.dyno.waitForInfo(app, name, {states: ['starting', 'up']}) * ``` */ export declare function waitForInfo(ctx: Pick, appIdentity: string, dynoIdentity: string, options?: WaitForInfoOptions): Promise;