/** * Start the application, rather than asking for one that is already running. * * The API plane is the only plane that can settle anything on a Prisma, * Drizzle or raw-`pg` stack, and until now reaching it took four manual steps: * build the app, start it, find out which port it landed on, and pass `--api`. * A test that needs four steps before it can run is not a default. * * The shape is Playwright's `webServer`, deliberately and to the letter — * `command`, `url`, `timeout`, `reuseExistingServer` — because that is the * proven pattern for this exact problem and because a developer who has * configured one has configured this. Two deviations, both in the direction of * needing less: * * - `command` may be omitted, and is then read off `package.json`'s scripts * *only when the answer is unambiguous*. A wrong guess runs somebody's * build, so an ambiguous project is asked rather than guessed at. * - `url` may be omitted, and Crossline then picks a free port and passes it * as `PORT`, which every Node framework in this population honours. That is * more reliable than parsing a port out of a script, and it means two runs * in the same repository cannot collide. * * Reuse is checked first whenever a URL is known: starting a second copy of an * app that is already listening would fail on the port and, worse, might * succeed against a different database than the one being checked. */ export interface ServerConfig { /** The command to run. Inferred from package.json when omitted. */ command?: string; /** Where it will listen. A free port is chosen and passed as `PORT` when omitted. */ url?: string; /** How long to wait for it to answer, in milliseconds. Default 120000. */ timeout?: number; /** Use a server already listening at `url` instead of starting one. Default true. */ reuseExistingServer?: boolean; /** Extra environment for the child process. */ env?: Record; } export interface RunningApp { baseUrl: string; /** What happened, in one sentence, for the face of the report. */ how: string; /** False when an existing server was reused, so nothing is ours to stop. */ started: boolean; stop(): Promise; } export type StartOutcome = { ok: true; app: RunningApp; } | { ok: false; reason: string; }; export declare function startAppServer(cwd: string, config?: ServerConfig, deps?: { /** Ambient environment for the child. Defaults to `process.env`. */ env?: NodeJS.ProcessEnv; }): Promise; export type CommandChoice = { ok: true; command: string; why: string; dir?: string; } | { ok: false; reason: string; }; /** * Read the start command off `package.json`, or decline. * * Two shapes are unambiguous and nothing else is: * * - a `dev` script, which by universal convention starts the application in * development and needs no build first; * - a `start` script in a project with no `build` script, which is what an * Express or Fastify service looks like — there is nothing to build, so * `start` cannot mean "serve a build that does not exist yet". * * A `start` script *beside* a `build` script is exactly the ambiguous case: * `next start` on an unbuilt project fails, and running `next build` on a * developer's behalf because a test wanted a server is not a thing to do * without being asked. So that project is asked. * * The root is asked first and answers for most repositories, including every * Turborepo — `turbo dev` at the root is a `dev` script like any other. When it * cannot, the app is looked for one level down, because a monorepo root whose * own `package.json` starts nothing is the ordinary `apps/web` layout rather * than a project with no server. */ export declare function inferStartCommand(cwd: string): CommandChoice; /** * Does this project serve HTTP? * * The gate on starting anything uninvited. Without it, a bare `crossline` in a * repository that merely happens to have a `dev` script would run it and wait, * which is a worse first experience than the missing check it was trying to * supply. */ export declare function looksLikeWebApp(cwd: string): boolean; /** npm unless a lockfile says otherwise. */ export declare function packageManager(cwd: string): string; /** A port nothing is using, obtained by having the OS pick one and letting it go. */ export declare function freePort(): Promise;