export interface EvidenceRoots { /** The capture workspace: every live shot, the sheets, the run log. */ evidence: string; /** The project's `.lookout/issues`, holding each dossier's frozen frames. */ issues: string; } /** Serve only from inside the path's own root, whatever the URL claims. */ export declare function safeEvidencePath(roots: EvidenceRoots, rel: string): string | null; /** * What a browser is told to compare a cached tile against. * * Everything that decides what comes back: which file, as it is on disk right * now, at which width, cropped or whole. Hashed, not encoded. This was base64 * of that key truncated to 32 characters, and base64 is a prefix code: 32 * characters is the first 24 bytes, which is the front of an absolute path and * nothing else. Every thumbnail the server produced carried the same ETag, * decoding to `/Users/somebody/Workspac`, and the mtime, size, width and fit * the key exists to distinguish were all cut off the end. * * What that cost is precisely what lookout is for: re-capture a screenshot and * the browser revalidates the tile, is told 304, and goes on showing the defect * you just fixed. Measured on 2026-09-01, replacing a desktop capture with a * phone one and revalidating returned 304 with no body. * * Its own function because that is the half worth testing, and because reading * the file's mtime here means a caller cannot forget to. */ export declare function thumbEtag(path: string, width: number, whole: boolean): string; /** * Full-page screenshots run to megabytes each, and a grid of them stalls the * page for the whole run. Thumbnails are generated on demand and cropped the * same way the contact sheet crops, so the grid matches what the sheet shows. */ export declare function serveThumb(req: Request, roots: EvidenceRoots, url: URL): Promise; /** The screenshot itself, streamed as it is on disk. */ export declare function serveEvidence(roots: EvidenceRoots, url: URL): Response;