import { type JobRegistryHandle } from '../jobs.js'; import type { PreviewIdentity } from './access.js'; import { type PreviewEndpoint } from './delivery.js'; import { jobOwnsPort } from './process.js'; export type PreviewState = 'starting' | 'ready' | 'rebuilding' | 'disconnected' | 'failed' | 'stopped'; export interface PreviewRecord extends PreviewIdentity { browserId: string; default?: boolean; entryPath?: string; pageTarget?: string; sourcePath?: string; branch?: string; ownerWorktree?: string; label: string; endpoint: PreviewEndpoint; state: PreviewState; jobId?: string; sourceFiles: string[]; createdAt: number; lastViewedAt: number; readyDeadline: number; error?: string; } export interface RegisterPreview { target: string; label?: string; kind: 'static' | 'server'; root?: string; port?: number; command?: string; jobId?: string; sourceFiles?: string[]; spa?: boolean; default?: boolean; entryPath?: string; sourcePath?: string; env?: Record; upstreamApiKey?: string; upstreamHost?: string; } export interface PreviewRegistryOptions { directory: string; jobs: JobRegistryHandle; resolveWorktree: (thread: string) => Promise; onChange?: (thread: string, record: PreviewRecord) => void; now?: () => number; readinessMs?: number; idleMs?: number; pollMs?: number; /** Task 217: how long one verification answers for the delivery path. */ liveMs?: number; /** Task 217: cadence of the process-ownership and git worktree proof. */ deepMs?: number; /** Task 217: how long a ready preview keeps serving through failing checks. */ graceMs?: number; ownsPort?: typeof jobOwnsPort; } /** Preview metadata references the existing job registry; it never owns child processes. */ export declare class PreviewRegistry { private readonly opts; private records; private readonly filename; private readonly now; private readonly timer; private polling; private closed; private readonly locks; private readonly viewers; private readonly starts; private readonly stopVersions; private readonly checks; constructor(opts: PreviewRegistryOptions); private persist; private changed; list(thread: string): PreviewRecord[]; get(thread: string, target: string): PreviewRecord | undefined; /** Page choices include unavailable branches without launching anything. */ catalog(thread: string): Promise<{ target: string; label: string; sourcePath: string | undefined; entryPath: string | undefined; default: boolean | undefined; defaultBranch: string | null; branches: { reason?: string | undefined; name: string; available: boolean; }[]; }[]>; private pagePath; private recordWorktree; startBranch(thread: string, target: string, branch: string): Promise; private startBranchLocked; upstreamApiKey(thread: string, target: string): string | undefined; /** Delivery rechecks the exact registration, not the last readiness poll. */ live(thread: string, target: string, session: string): Promise; /** Idempotent, explicitly requested launch. Reads and readiness polls never spawn. */ start(thread: string, target: string): Promise; register(thread: string, req: RegisterPreview, selection?: { owner: string; worktree: string; branch: string; pageTarget?: string; }): Promise; private registerLocked; private revision; update(thread: string, target: string, input: { label?: string; rebuilding?: boolean; default?: boolean; upstreamHost?: string | null; }): Promise; touch(thread: string, target: string, viewer: string): void; stop(thread: string, target: string, remove?: boolean): boolean; /** * Give a new co-thread its own copy of its master's pages (task 218). * * A co-thread previews the same applications as its master, but in its own * checkout, on its own branch, under its own browser origin. Copying the * recipes once at creation is what makes that true without a read-time * fallback to the master: from here the two threads share nothing, and the * co-thread registers, edits and stops pages exactly as a master does. * * Nothing is launched and no port is inherited — each page arrives stopped, * and the co-thread's first Preview open starts it from the recipe the same * way a restart does. */ seed(master: string, thread: string, directory: string): number; removeThread(thread: string): void; rename(from: string, to: string): void; poll(): Promise; /** Is this preview's own process still serving? Static roots always are. */ private answering; private checkState; /** * Task 217 — the one entry point to checking. * * Delivery calls this before every file it serves, and a page is hundreds of * files. Two rules keep that from costing hundreds of checks: an in-flight * check is shared rather than duplicated, and a check younger than `maxAgeMs` * is skipped entirely. `check` itself never rejects. */ private checkNow; /** * A check that could not complete is not evidence that the preview is gone. * * Task 217: a single git or filesystem stumble used to cancel the job and mark * the record failed, which killed healthy dev servers. A ready preview now * keeps serving through the grace window, and even past it the process is left * alone — degrading to `disconnected` is as far as a failed READ may go. */ private degrade; private check; close(): Promise; } //# sourceMappingURL=registry.d.ts.map