/** * Zero-configuration public app routes for a Vercel devbox. * * Runs after the remote checkout is ready and before readiness is rendered: * reconcile any pending route update, scan the remote checkout for app-port * candidates, decide which of them to expose, and apply the full desired port * set to the running Sandbox without recreating it. * * Everything happens under the branch metadata lock. A route update is written * as a pending `{ previous, desired }` record first and committed after, so a * crash between the two leaves a route set that the next attach can reconcile * against the Sandbox's actual routes rather than an untracked public port. */ import type { Writable } from 'node:stream'; import { promptForAppPorts } from './app-port-prompt.js'; import { type VercelBranchMetadata, type VercelBranchMetadataStore } from './metadata.js'; import type { VercelSandboxClient, VercelSandboxHandle } from './client.js'; import type { ProviderInput } from '../types.js'; export type AppPortPrompt = typeof promptForAppPorts; /** * Why the flow is running. A boot is already a decision point, so its prompt * defaults to accepting what was detected. A resume is usually "get me back * in" -- often a second terminal beside a running dev server -- so its prompt * defaults to keeping whatever is already exposed and never stands between the * user and their shell. */ export type AppPortFlowMode = 'boot' | 'resume'; /** * The scan is two short commands on a Sandbox that is already up. Bound it * separately from the rest of the flow, which waits on a human at the prompt. */ export declare const APP_PORT_SCAN_TIMEOUT_MS = 60000; export interface AppPortFlowOptions { sandbox: VercelSandboxHandle; client: VercelSandboxClient; branchStore: VercelBranchMetadataStore; /** Host repository root; the trusted explicit `forwardPorts` source. */ repoRoot: string; /** Repository working directory inside the Sandbox. */ workspace: string; branch: string; tty: boolean; stdin: ProviderInput; stderr: Writable; /** Explicit non-interactive opt-in from `--expose-ports`. */ exposePorts?: readonly number[]; secrets?: readonly string[]; signal?: AbortSignal; prompt?: AppPortPrompt; mode?: AppPortFlowMode; } export interface AppPortFlowResult { /** Inferred/opted-in app ports now exposed. */ selected: number[]; /** Full port set believed to be on the Sandbox. */ applied: number[]; /** True when this run changed the Sandbox's route set. */ updated: boolean; /** Framework labels for the selected ports, for route rendering. */ labels: Record; } export declare function applyAppPorts(options: AppPortFlowOptions): Promise; /** * Reconcile a durable pending record against the Sandbox's actual routes. * * An already-applied desired set is committed, an unapplied pending set is * cleared, and anything else is restored to the recorded previous set before * the record is cleared. An unknown route set is never treated as committed. */ export declare function reconcilePendingAppPorts(options: AppPortFlowOptions, metadata: VercelBranchMetadata | null): Promise;