@vosjs/render-core 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/record/driver.ts","../../src/record/cap.ts","../../src/record/pace.ts","../../src/record/wall.ts","../../src/record/exposure.ts","../../src/record/setup.ts","../../src/record/recorder.ts","../../src/record/actions.ts","../../src/record/encodePage.ts","../../src/record/plan.ts"],"sourcesContent":["/**\n * The recorder's driver: what it needs from a browser, as a STRUCTURAL\n * contract. Playwright's own `Browser`/`BrowserContext`/`Page` satisfy it\n * unchanged, and so does `@cloudflare/playwright`'s (the same client\n * surface over Browser Rendering), so the CLI hands in a launched Node\n * browser and the fleet hands in a connected one, and the recorder never\n * imports either package. Only the members the recorder calls are named\n * here; a driver that offers more is fine, one that offers less fails to\n * type.\n *\n * Frames leave through a `FrameSink`, never through a filesystem: the CLI's\n * sink writes a take directory, the fleet's puts each JPEG to R2.\n */\n\nexport interface RecorderRect {\n x: number\n y: number\n width: number\n height: number\n}\n\nexport interface RecorderLocator {\n waitFor(opts: { state: 'visible'; timeout: number }): Promise<unknown>\n scrollIntoViewIfNeeded(): Promise<unknown>\n boundingBox(): Promise<RecorderRect | null>\n click(): Promise<unknown>\n fill(value: string): Promise<unknown>\n}\n\nexport interface RecorderLocatorRoot {\n first(): RecorderLocator\n}\n\nexport interface RecorderResponse {\n status(): number\n}\n\nexport interface RecorderConsoleMessage {\n type(): string\n text(): string\n}\n\nexport interface RecorderPage {\n goto(\n url: string,\n opts: { waitUntil: 'networkidle'; timeout: number },\n ): Promise<RecorderResponse | null>\n url(): string\n title(): Promise<string>\n // Playwright's evaluate takes a function or an expression string; the\n // recorder hands it strings (the probes) and small functions.\n evaluate<T>(pageFunction: string | (() => T)): Promise<T>\n on(event: 'console', cb: (m: RecorderConsoleMessage) => void): unknown\n locator(selector: string): RecorderLocatorRoot\n mouse: {\n move(x: number, y: number): Promise<void>\n down(): Promise<void>\n up(): Promise<void>\n wheel(dx: number, dy: number): Promise<void>\n }\n keyboard: {\n type(text: string): Promise<void>\n press(key: string): Promise<void>\n }\n}\n\nexport interface RecorderCdp {\n on(\n event: 'Page.screencastFrame',\n cb: (ev: {\n data: string\n sessionId: number\n metadata: { timestamp?: number }\n }) => void,\n ): unknown\n send(method: string, params?: Record<string, unknown>): Promise<unknown>\n}\n\n/** One intercepted request, as Playwright's `Route` answers it. */\nexport interface RecorderRoute {\n request(): { url(): string; headers(): Record<string, string> }\n continue(opts?: { headers?: Record<string, string> }): Promise<unknown>\n}\n\nexport interface RecorderContext {\n newPage(): Promise<RecorderPage>\n addInitScript(script: string): Promise<unknown>\n setExtraHTTPHeaders(headers: Record<string, string>): Promise<unknown>\n /**\n * Request interception, when the driver has it: how a job's headers are\n * sent to the recorded origin alone. A driver without it gets them on\n * every request through `setExtraHTTPHeaders`, and the recorder says so.\n */\n route?(\n pattern: string,\n handler: (route: RecorderRoute) => Promise<unknown> | unknown,\n ): Promise<unknown>\n // The page handed back is the one `newPage()` answered; typed loosely so\n // Playwright's `Page | Frame` parameter satisfies the contract.\n newCDPSession(page: unknown): Promise<RecorderCdp>\n close(): Promise<void>\n}\n\nexport interface RecorderBrowser {\n newContext(opts: {\n viewport: { width: number; height: number }\n deviceScaleFactor: number\n storageState?: string\n extraHTTPHeaders?: Record<string, string>\n }): Promise<RecorderContext>\n}\n\n/**\n * Where the screencast's frames go. `frame` is called in order with the\n * JPEG bytes; the recorder keeps the index (`file`, `tMs`) itself. The CLI\n * writes `frames/<file>`; the fleet puts to R2. A sink may be async and\n * slow: the recorder never awaits it on the screencast's own thread, so a\n * slow store costs no frames, only memory until it catches up.\n */\nexport interface FrameSink {\n frame(file: string, bytes: Uint8Array): Promise<void> | void\n}\n\n/** The clock and the pauses, injectable so a rehearsal runs fast. */\nexport interface RecorderClock {\n now(): number\n sleep(ms: number): Promise<void>\n}\n\nexport const realSleep = (ms: number): Promise<void> =>\n new Promise<void>((r) => setTimeout(r, ms))\n","/**\n * The recording cap as the recorder applies it, pure. WHAT the cap is\n * (the hosted plan's number, read from `GET /api/limits`) is a vos.so fact\n * and stays in the CLI's platform client; the recorder only knows a number\n * of seconds and stops there.\n */\n\n/** True once the take has reached the cap — the recorder stops driving steps. */\nexport function capReached(elapsedMs: number, capSeconds: number): boolean {\n return elapsedMs >= capSeconds * 1000\n}\n\n/** A wait step never sleeps past the cap. */\nexport function clampWait(\n waitMs: number,\n elapsedMs: number,\n capSeconds: number,\n): number {\n return Math.max(0, Math.min(waitMs, capSeconds * 1000 - elapsedMs))\n}\n\n/** `30 min`, `1 h 30 min`, `45 s` — the duration cap in words. */\nexport function formatDurationCap(seconds: number): string {\n if (seconds < 60) return `${seconds} s`\n const m = Math.round(seconds / 60)\n if (m < 60) return `${m} min`\n const h = Math.floor(m / 60)\n const rest = m % 60\n return rest ? `${h} h ${rest} min` : `${h} h`\n}\n\n/** The one line printed when the cap stopped the take. */\nexport function cappedLine(capSeconds: number): string {\n return `stopped at ${formatDurationCap(capSeconds)} (--max-duration ${capSeconds}); the remaining steps did not run`\n}\n","/**\n * The recorder's pace — the pure parts.\n *\n * A take of a scripted flow should run as long as the script asks, plus the\n * gestures a person makes between the asks (the pointer's travel, the press,\n * the settle after it) and no more. Measured before this module (§4.5 of\n * the utility-clip retrospective), hovers ran 2× their ask, drags 4.8× and\n * a 25 s script recorded 42 s, for two reasons the numbers here answer:\n *\n * - The motion loops counted STEPS (one per 16 ms of the asked duration)\n * and awaited a `mouse.move` round trip per step, so a page that\n * re-renders per move (a slider) stretched every gesture by the round\n * trip. A gesture is now driven by the CLOCK: its position is a function\n * of the elapsed time, and it ends when the asked duration has elapsed,\n * however many samples the page allowed.\n * - The settles after a gesture were fixed sleeps (500 ms after a click,\n * 250 after every selector lookup). A settle is DATA: `ms` on the step\n * overrides a small default, and the script's own `wait` steps carry\n * the intended pauses.\n */\n\n/** Pointer travel: ms per CSS px, floor and ceiling — a person's hand. */\nexport const POINTER_MS_PER_PX = 0.7\nexport const POINTER_MIN_MS = 250\nexport const POINTER_MAX_MS = 800\n/** The sample cadence a motion loop aims for. */\nexport const MOTION_TICK_MS = 16\n\n/** The settle after a gesture when the step names none, by verb. */\nexport const SETTLE_MS = {\n click: 150,\n type: 150,\n press: 150,\n scroll: 200,\n drag: 80,\n} as const\n\n/** The press: the pause before the button goes down, and the hold. */\nexport const PRESS_LEAD_MS = 80\nexport const PRESS_HOLD_MS = 70\n/** The pause between a selector lookup that scrolled the page and the move. */\nexport const SCROLL_SETTLE_MS = 120\n\n/**\n * A scroll travels by the clock too, at a wheel's pace: 0.9 ms per px,\n * floored so a short flick still reads as motion and capped so a long page\n * does not crawl. Each tick moves the page's scroll container in the page\n * itself (recorder.ts says why not a wheel event, an animation frame or a\n * page timer).\n */\nexport const SCROLL_MS_PER_PX = 0.9\nexport const SCROLL_MIN_MS = 240\nexport const SCROLL_MAX_MS = 1000\n/** The hold after the last step, so the take does not cut on a press. */\nexport const TRAILING_HOLD_MS = 400\n\n/** How long the pointer takes to travel `dist` CSS px. */\nexport function scrollTravelMs(px: number): number {\n return Math.min(\n SCROLL_MAX_MS,\n Math.max(SCROLL_MIN_MS, Math.round(Math.abs(px) * SCROLL_MS_PER_PX)),\n )\n}\n\nexport function pointerTravelMs(dist: number): number {\n return Math.min(\n POINTER_MAX_MS,\n Math.max(POINTER_MIN_MS, Math.round(dist * POINTER_MS_PER_PX)),\n )\n}\n\n/**\n * A click's `ms` is READING time, held from the page's last visual change,\n * and the recorder pays the settle itself: the same `ms` was read on one\n * run and dead on the next because the hold started at the press and the\n * page's settle varied run to run (0.3 s to 0.7 s on the same step).\n *\n * The settle is watched on the screencast, which emits only on change:\n * after the press, a change that arrives within RESPONSE_MS says the page\n * is answering, and it has settled once QUIET_MS pass with no new frame.\n * No change within RESPONSE_MS means the page did not change (a click that\n * only moves state) and the settle is over. SETTLE_CAP_MS bounds a page\n * that never stops changing (a playing preview), which is a page nothing\n * is dead on, so the hold simply starts.\n */\nexport const RESPONSE_MS = 400\nexport const QUIET_MS = 250\nexport const SETTLE_CAP_MS = 1200\n\n/**\n * Is the page settled? Pure: the recorder feeds it what it knows at each\n * tick since the press.\n */\nexport function settleVerdict(\n t: {\n /** ms since the press. */\n sincePress: number\n /** ms since the last screencast frame, or null when none arrived since the press. */\n sinceChange: number | null\n },\n c = { response: RESPONSE_MS, quiet: QUIET_MS, cap: SETTLE_CAP_MS },\n): 'wait' | 'settled' {\n if (t.sincePress >= c.cap) return 'settled'\n if (t.sinceChange === null)\n return t.sincePress >= c.response ? 'settled' : 'wait'\n return t.sinceChange >= c.quiet ? 'settled' : 'wait'\n}\n\n/**\n * What is left of a hold once the settle is detected: the hold is measured\n * from the last change, so the quiet already spent counts toward it.\n */\nexport function holdLeftMs(holdMs: number, sinceChange: number | null): number {\n return Math.max(0, holdMs - (sinceChange ?? 0))\n}\n\n/** The settle after a step: its own `ms` when it names one, else the verb's. */\nexport function settleMs(step: { do: string; ms?: number }): number {\n if (typeof step.ms === 'number' && step.ms >= 0) return step.ms\n const d = step.do as keyof typeof SETTLE_MS\n return SETTLE_MS[d] ?? 0\n}\n\nexport const easeInOutCubic = (u: number): number =>\n u < 0.5 ? 4 * u * u * u : 1 - Math.pow(-2 * u + 2, 3) / 2\n\n/**\n * Drive a motion by the clock: `at(u)` is called with the eased progress\n * for each sample, and the loop ends when `dur` ms have elapsed, with the\n * last call at u = 1 exactly. Between samples it sleeps to the next tick\n * only when the sample came back early; a slow sample (a page busy\n * re-rendering) is followed at once, so the gesture keeps its length and\n * loses samples, never the other way round.\n */\nexport async function clockMotion(\n dur: number,\n at: (u: number) => Promise<void>,\n clock: { now: () => number; sleep: (ms: number) => Promise<void> },\n): Promise<number> {\n const start = clock.now()\n let samples = 0\n for (;;) {\n const tick = clock.now()\n const elapsed = tick - start\n if (elapsed >= dur) break\n await at(easeInOutCubic(Math.min(1, elapsed / dur)))\n samples++\n const next =\n start + Math.ceil((clock.now() - start) / MOTION_TICK_MS) * MOTION_TICK_MS\n const wait = Math.min(next, start + dur) - clock.now()\n if (wait > 0) await clock.sleep(wait)\n // A sample that cost no clock time still yields a tick. On a Worker the\n // clock moves only across I/O, so a sample that awaited nothing (a\n // scroll tick that owed no pixels yet) left `now` where it was, the wait\n // came out at zero, and the loop spun on a frozen clock for good: the\n // fleet's first three clock-driven scrolls did exactly that.\n else if (clock.now() === tick) await clock.sleep(MOTION_TICK_MS)\n }\n await at(1)\n return samples + 1\n}\n\n/**\n * Typing paced by the clock: the i-th character is due at `start + i·delay`;\n * after each keystroke the loop sleeps to the next due time only if the\n * keystroke came back early. A slow field (an editor re-rendering per key)\n * types as fast as it can and says so in the pace report.\n */\nexport async function clockTyping(\n chars: readonly string[],\n delay: number,\n type: (ch: string, index: number) => Promise<void>,\n clock: { now: () => number; sleep: (ms: number) => Promise<void> },\n): Promise<void> {\n const start = clock.now()\n for (let i = 0; i < chars.length; i++) {\n await type(chars[i], i)\n const due = start + (i + 1) * delay\n const wait = due - clock.now()\n if (wait > 0 && i < chars.length - 1) await clock.sleep(wait)\n // The same yield as clockMotion's: a keystroke that cost no clock time\n // must not let the loop outrun a clock that only moves across I/O.\n else if (i < chars.length - 1 && clock.now() === start + i * delay)\n await clock.sleep(1)\n }\n}\n\n/** One step's pace: what the script asked for it and what it took. */\nexport interface StepPace {\n step: number\n do: string\n /** The script's own ask: a wait's ms, a hover's dwell, a drag's ms, typing's chars × delay, a click's read after the settle; 0 for a scroll. */\n askedMs: number\n /** The gesture the recorder adds by design: pointer travel, the press, the settle. */\n gestureMs: number\n wallMs: number\n}\n\nexport interface PaceReport {\n askedMs: number\n gestureMs: number\n wallMs: number\n /** Wall time neither asked nor a gesture: what the page and the round trips cost. */\n overheadMs: number\n overheadPct: number\n /** The steps whose wall ran past their ask plus gesture by more than a third. */\n slow: { step: number; do: string; askedMs: number; wallMs: number }[]\n}\n\n/** What a script asks of a step, in ms: the part of its wall time that is the author's. */\nexport function askedMs(step: {\n do: string\n ms?: number\n text?: string\n delayMs?: number\n}): number {\n switch (step.do) {\n case 'wait':\n return step.ms ?? 0\n // A click's ms is the read after the page settled: the author's.\n case 'click':\n return step.ms ?? SETTLE_MS.click\n case 'hover':\n return step.ms ?? 700\n case 'drag':\n return step.ms ?? 700\n case 'type':\n return (step.text?.length ?? 0) * (step.delayMs ?? 40)\n case 'press':\n return step.ms ?? SETTLE_MS.press\n default:\n return 0\n }\n}\n\nexport function paceReport(steps: readonly StepPace[]): PaceReport {\n const askedMs = steps.reduce((a, s) => a + s.askedMs, 0)\n const gestureMs = steps.reduce((a, s) => a + s.gestureMs, 0)\n const wallMs = steps.reduce((a, s) => a + s.wallMs, 0)\n const overheadMs = Math.max(0, wallMs - askedMs - gestureMs)\n const slow = steps\n .filter((s) => s.wallMs > (s.askedMs + s.gestureMs) * 1.34 + 60)\n .map((s) => ({\n step: s.step,\n do: s.do,\n askedMs: s.askedMs,\n wallMs: s.wallMs,\n }))\n return {\n askedMs,\n gestureMs,\n wallMs,\n overheadMs,\n overheadPct: wallMs > 0 ? Math.round((overheadMs / wallMs) * 100) : 0,\n slow,\n }\n}\n\n/** The pace in one line for the log. */\nexport function paceLine(r: PaceReport): string {\n const s = (ms: number) => `${(ms / 1000).toFixed(1)} s`\n const slow = r.slow.length\n ? `; slow: ${r.slow.map((x) => `#${x.step} ${x.do} ${s(x.wallMs)} for ${s(x.askedMs)} asked`).join(', ')}`\n : ''\n return `pace: the script asked ${s(r.askedMs)}, the gestures added ${s(r.gestureMs)}, the take ran ${s(r.wallMs)} (${r.overheadPct} % overhead${slow})`\n}\n\n/**\n * DEAD TIME, the smoothness fact that replaces the freeze share as the\n * warning. A still frame is not a defect: a page the viewer is reading is\n * content, and a workspace tour is mostly still. What is dead is a still\n * frame under a PARKED cursor past the beat it takes to read what changed:\n * after that the picture, the pointer and the camera all hold and nothing\n * is being said. So the derivation reads, per step, when the page settled\n * after the step's act, how long the settled frame was held, and whether\n * the cursor moved in that hold; a hold past the reading beat is dead.\n *\n * The beat is longer after a page changed (a navigation shows a whole new\n * page to take in) than after a control changed (one thing to see).\n */\nexport const READ_BEAT_MS = { page: 1000, control: 600 } as const\n/** A dead stretch this long is a warning on its own, whatever the share. */\nexport const DEAD_STRETCH_WARN_MS = 1500\n/** The share of the take past which dead time is a warning. */\nexport const DEAD_SHARE_WARN_PCT = 20\n\nexport interface DeadStep {\n step: number\n id?: string\n do: string\n /** ms from the step's act (its press, else its start) to the last frame change in the step. */\n settledMs: number\n /** ms the settled frame was held before the step ended. */\n heldMs: number\n /** the hold past the reading beat, while the cursor was parked; 0 when the hold was read or the pointer moved. */\n deadMs: number\n}\n\nexport interface DeadReport {\n ms: number\n pct: number\n /** the steps that carried any dead time, in order. */\n steps: DeadStep[]\n /** the longest single dead hold. */\n longestMs: number\n}\n\nexport function deadTime(\n steps: readonly {\n step: number\n id?: string\n do: string\n tStart: number\n tEnd: number\n navigated?: boolean\n }[],\n frames: readonly { tMs: number }[],\n events: readonly { t: number; type: string }[],\n durationMs: number,\n): DeadReport {\n const out: DeadStep[] = []\n let ms = 0\n let longestMs = 0\n for (const s of steps) {\n const t0 = s.tStart * 1000\n const t1 = s.tEnd * 1000\n if (!(t1 > t0)) continue\n // The act: the step's first press, else its start (a wait, a move).\n const press = events.find(\n (e) => e.type === 'down' && e.t >= t0 && e.t <= t1,\n )\n const act = press ? press.t : t0\n // The last visual change inside the step, after the act.\n let last = act\n for (const f of frames) {\n if (f.tMs > act && f.tMs <= t1) last = f.tMs\n }\n const settledMs = Math.round(last - act)\n const heldMs = Math.round(t1 - last)\n // Parked: no pointer motion while the settled frame was held.\n const moved = events.some(\n (e) =>\n (e.type === 'move' || e.type === 'scroll') && e.t > last && e.t <= t1,\n )\n // The opening step shows a page the viewer has not seen: a page beat.\n const beat =\n s.navigated || s.step === 0 ? READ_BEAT_MS.page : READ_BEAT_MS.control\n const deadMs = moved ? 0 : Math.max(0, heldMs - beat)\n if (deadMs > 0) {\n out.push({\n step: s.step,\n ...(s.id ? { id: s.id } : {}),\n do: s.do,\n settledMs,\n heldMs,\n deadMs,\n })\n ms += deadMs\n longestMs = Math.max(longestMs, deadMs)\n }\n }\n return {\n ms,\n pct: durationMs > 0 ? Math.round((ms / durationMs) * 100) : 0,\n steps: out,\n longestMs,\n }\n}\n\n/** Whether a dead report earns a warning: the share, or one long hold. */\nexport function deadWarns(r: DeadReport): boolean {\n return r.pct >= DEAD_SHARE_WARN_PCT || r.longestMs >= DEAD_STRETCH_WARN_MS\n}\n\n/** The dead time in words, naming the steps and what to cut. */\nexport function deadLine(r: DeadReport): string {\n const s = (ms: number) => `${(ms / 1000).toFixed(1)} s`\n if (!r.steps.length) return 'dead time: none'\n const parts = r.steps.map(\n (d) =>\n `#${d.step}${d.id ? ` (${d.id})` : ''} ${d.do} held ${s(d.heldMs)} after it settled, ${s(d.deadMs)} past the beat`,\n )\n return `dead time: ${s(r.ms)} (${r.pct} %), a still frame under a parked cursor past the reading beat: ${parts.join('; ')}. Cut those steps' ms; a hold is what it takes to read what changed.`\n}\n","/**\n * The wall check: did the recorder land where it was asked, or in front of\n * a sign-in? A take of a product behind a login, recorded without a session,\n * used to succeed: the footage was the login page (or wherever the site\n * sends a stranger), and the only symptom was a skipped selector. This says\n * it in words, before a frame is captured and before a re-record clears the\n * footage it would have replaced.\n *\n * Pure: the recorder gathers the evidence, this decides. A heuristic is\n * acceptable because both failure directions are cheap: a false refusal\n * costs one flag (`--allow-wall`), a false pass costs what every such take\n * cost before.\n */\n\n/** What the recorder saw once the first navigation settled. */\nexport interface Arrival {\n askedUrl: string\n landedUrl: string\n /** HTTP status of the main document, when the navigation produced one. */\n status?: number\n /** `input[type=password]` fields that are visible on the page. */\n passwordFields: number\n /** A password field marked `autocomplete=\"new-password\"` (a settings or sign-up form). */\n newPasswordField: boolean\n /** A visible one-time-code field (`autocomplete=\"one-time-code\"`). */\n oneTimeCodeField: boolean\n}\n\nexport type WallKind =\n /** the asked URL answered 401 or 403 */\n | 'status'\n /** landed on an identity provider's host */\n | 'idp'\n /** landed on a sign-in form or a sign-in path */\n | 'signin'\n /** sent somewhere else, with no sign-in in sight (a site that shows strangers a public page) */\n | 'redirect'\n\nexport interface WallVerdict {\n kind: WallKind\n /**\n * `hard` is refused always; `soft` is refused under `--strict` and said as\n * a warning otherwise, because a redirect alone is not proof of a wall.\n */\n level: 'hard' | 'soft'\n /** origin + path, never the query or hash (they can carry tokens). */\n asked: string\n landed: string\n message: string\n}\n\n/** Hosts that only ever mean \"sign in\". Suffix match on the label boundary. */\nconst IDP_HOSTS = [\n 'accounts.google.com',\n 'login.microsoftonline.com',\n 'login.live.com',\n 'appleid.apple.com',\n 'auth0.com',\n 'okta.com',\n 'onelogin.com',\n 'clerk.accounts.dev',\n 'accounts.dev',\n 'b2clogin.com',\n 'amazoncognito.com',\n 'workos.com',\n 'stytch.com',\n]\n\n/** Path segments that name a sign-in surface. Whole segments, never substrings. */\nconst SIGNIN_SEGMENTS = new Set([\n 'login',\n 'log-in',\n 'signin',\n 'sign-in',\n 'sign_in',\n 'sso',\n 'auth',\n 'authenticate',\n 'authorize',\n 'oauth',\n 'oauth2',\n 'saml',\n])\n\nfunction parse(url: string): URL | null {\n try {\n return new URL(url)\n } catch {\n return null\n }\n}\n\nconst bareHost = (h: string) => h.replace(/^www\\./, '').toLowerCase()\nconst trimSlash = (p: string) => (p.length > 1 ? p.replace(/\\/+$/, '') : p)\nconst place = (u: URL) => `${u.origin}${trimSlash(u.pathname)}`\n\nexport function isIdpHost(host: string): boolean {\n const h = host.toLowerCase()\n if (h.startsWith('clerk.')) return true\n return IDP_HOSTS.some((idp) => h === idp || h.endsWith(`.${idp}`))\n}\n\nexport function isSignInPath(pathname: string): boolean {\n const segs = pathname.toLowerCase().split('/').filter(Boolean)\n return segs.some((s) => SIGNIN_SEGMENTS.has(s))\n}\n\n/**\n * Sent AWAY, as opposed to sent deeper. `/` → `/en`, `/docs` → `/docs/start`\n * and `/pricing` → `/en/pricing` are a site arranging itself; `/dashboard` →\n * `/gallery` is a site declining to show the page. `www.` and the apex are\n * one host.\n */\nexport function redirectedAway(asked: URL, landed: URL): boolean {\n if (bareHost(asked.hostname) !== bareHost(landed.hostname)) return true\n const a = trimSlash(asked.pathname).toLowerCase()\n const l = trimSlash(landed.pathname).toLowerCase()\n if (a === l || a === '/') return false\n if (l.startsWith(`${a}/`)) return false\n if (l.endsWith(a)) return false\n return true\n}\n\nconst LADDER =\n 'This is a missing or expired session, not a script bug. Ways past, cheapest first: mint a session from the test auth the project already has; script the sign-in off camera and save the storage state; or have a person sign in once (npx playwright open --channel chrome --save-storage=<file> <url>). Then pass --storage-state <file>. The ladder: https://vos.so/llms-full.txt, \"Sessions\". A take OF this page is --allow-wall.'\n\nexport function wallVerdict(a: Arrival): WallVerdict | null {\n const asked = parse(a.askedUrl)\n const landed = parse(a.landedUrl)\n // A file: or data: take, or a URL we cannot read, has no wall to speak of.\n if (!asked || !landed) return null\n if (!/^https?:$/.test(asked.protocol)) return null\n\n const away = redirectedAway(asked, landed)\n const where = { asked: place(asked), landed: place(landed) }\n const host = bareHost(asked.hostname)\n\n if (a.status === 401 || a.status === 403) {\n return {\n kind: 'status',\n level: 'hard',\n ...where,\n message: `asked for ${asked.pathname}, answered ${a.status}: no session for ${host}. ${LADDER}`,\n }\n }\n\n // Someone who ASKED for the sign-in page and got it wants that take.\n const askedForSignIn =\n isSignInPath(asked.pathname) || isIdpHost(asked.hostname)\n if (askedForSignIn && !away) return null\n\n if (away && isIdpHost(landed.hostname) && !isIdpHost(asked.hostname)) {\n return {\n kind: 'idp',\n level: 'hard',\n ...where,\n message: `asked for ${asked.pathname}, landed on ${landed.hostname}: no session for ${host}. ${LADDER}`,\n }\n }\n\n // One password field that is not a new-password field is a sign-in form.\n // Two, or a new-password one, is a settings page or a sign-up.\n const signInForm =\n (a.passwordFields === 1 && !a.newPasswordField) || a.oneTimeCodeField\n if (\n (away && isSignInPath(landed.pathname)) ||\n (signInForm && !askedForSignIn)\n ) {\n const seen = away\n ? `landed on ${landed.pathname}`\n : 'the page is a sign-in form'\n return {\n kind: 'signin',\n level: 'hard',\n ...where,\n message: `asked for ${asked.pathname}, ${seen}: no session for ${host}. ${LADDER}`,\n }\n }\n\n if (away) {\n return {\n kind: 'redirect',\n level: 'soft',\n ...where,\n message: `asked for ${asked.pathname}, landed on ${landed.pathname}: the site sent the recorder elsewhere, which is what a page behind a login does to a stranger. If that is the page you meant, record it by its own URL. ${LADDER}`,\n }\n }\n return null\n}\n\n/** A take refused at the wall. Carries the verdict for `--json`. */\nexport class WallError extends Error {\n constructor(public verdict: WallVerdict) {\n super(verdict.message)\n this.name = 'WallError'\n }\n}\n\n/**\n * Evidence gathered in the page. A STRING, never a function: a serialized\n * function picks up the bundler's `__name` helper and dies in the page.\n */\nexport const WALL_PROBE = `(() => {\n const shown = (el) => {\n const r = el.getBoundingClientRect()\n if (r.width < 2 || r.height < 2) return false\n const s = getComputedStyle(el)\n return s.visibility !== 'hidden' && s.display !== 'none'\n }\n const pw = [...document.querySelectorAll('input[type=\"password\"]')].filter(shown)\n const otp = [...document.querySelectorAll('input[autocomplete=\"one-time-code\"]')].filter(shown)\n return {\n passwordFields: pw.length,\n newPasswordField: pw.some((el) => (el.getAttribute('autocomplete') || '').includes('new-password')),\n oneTimeCodeField: otp.length > 0,\n }\n})()`\n","/**\n * What a signed-in take SHOWS. Getting past the login is half the problem;\n * the other half is that the account's own data is now in the frame: an\n * email address in the header, a key on a settings page, a card number.\n * Asking nicely does not hold this line (a person asked to sign in with a\n * demo account signs in as themselves, because it is the account they have),\n * so the recorder looks.\n *\n * Two pieces, both run IN the page:\n *\n * - the EXPOSURE scan reads the text that is visible in the viewport after\n * each step and reports the KIND of thing it saw and where. Never the\n * string itself: a report that quotes the secret is a second leak.\n * - a MASK hides a selector before the first frame is captured and keeps it\n * hidden across navigations and re-renders, so the real value is never in\n * a frame, never in the recording, never pushed. `as: 'text'` swaps the\n * words (a product reads better than a redaction); `as: 'blur'` blurs.\n *\n * The matchers are ONE plain-JavaScript source string, evaluated in the page\n * and, by the tests, in Node: a function serialized out of a bundle picks up\n * the bundler's `__name` helper and dies in the page, and two copies of a\n * regex drift.\n */\nimport type { RecordingMeta } from '@vosjs/studio-core'\n\nexport type ExposureKind = 'email' | 'key' | 'card' | 'card-tail'\nexport type Exposure = NonNullable<RecordingMeta['exposures']>[number]\nexport type MaskReport = NonNullable<RecordingMeta['masks']>[number]\n\nexport interface MaskRule {\n selector: string\n /** `blur` (default) blurs the element; `text` swaps its words for `text`. */\n as?: 'blur' | 'text'\n text?: string\n}\n\n/**\n * `kindsIn(text)` → the kinds of sensitive-looking strings in `text`.\n *\n * - email: any address, EXCEPT one on a domain that can reach no one\n * (example.com/.org/.net, and the reserved .test/.example/.invalid/\n * .localhost TLDs), which is what demo data should use.\n * - key: the prefixes of keys people actually paste into dashboards, and a\n * JWT's three base64url parts.\n * - card: 13 to 19 digits that pass the Luhn check, so an order number or a\n * phone number is not a card.\n * - card-tail: a masked number's visible tail (•••• 4242).\n */\nexport const EXPOSURE_MATCHERS_SRC = `(() => {\n const EMAIL = /[A-Za-z0-9._%+-]+@((?:[A-Za-z0-9-]+\\\\.)+[A-Za-z]{2,})/g\n const SAFE_HOST = /(^|\\\\.)example\\\\.(com|org|net)$|\\\\.(test|example|invalid|localhost)$/i\n const KEY = new RegExp([\n '\\\\\\\\b[srp]k_(?:live|test)_[A-Za-z0-9]{8,}',\n '\\\\\\\\bgh[pousr]_[A-Za-z0-9]{20,}',\n '\\\\\\\\bgithub_pat_[A-Za-z0-9_]{20,}',\n '\\\\\\\\bxox[abprs]-[A-Za-z0-9-]{10,}',\n '\\\\\\\\bAKIA[0-9A-Z]{16}\\\\\\\\b',\n '\\\\\\\\bAIza[0-9A-Za-z_-]{30,}',\n '\\\\\\\\bvos_(?:sk|rg|ho)_[A-Za-z0-9]{8,}',\n '\\\\\\\\beyJ[A-Za-z0-9_-]{8,}\\\\\\\\.eyJ[A-Za-z0-9_-]{8,}\\\\\\\\.[A-Za-z0-9_-]{8,}',\n ].join('|'))\n const CARD = /(?:^|[^0-9])((?:[0-9][ -]?){12,18}[0-9])(?![0-9])/g\n const TAIL = /[\\\\u2022\\\\u00b7*xX]{2,}[ -]?[0-9]{4}(?![0-9])/\n const luhn = (digits) => {\n let sum = 0, alt = false\n for (let i = digits.length - 1; i >= 0; i--) {\n let d = digits.charCodeAt(i) - 48\n if (alt) { d *= 2; if (d > 9) d -= 9 }\n sum += d; alt = !alt\n }\n return sum % 10 === 0\n }\n const kindsIn = (text) => {\n const kinds = []\n if (!text || text.length < 6) return kinds\n EMAIL.lastIndex = 0\n for (let m; (m = EMAIL.exec(text)); ) {\n if (!SAFE_HOST.test(m[1])) { kinds.push('email'); break }\n }\n if (KEY.test(text)) kinds.push('key')\n CARD.lastIndex = 0\n for (let m; (m = CARD.exec(text)); ) {\n const digits = m[1].replace(/[ -]/g, '')\n if (digits.length >= 13 && digits.length <= 19 && !/^0+$/.test(digits) && luhn(digits)) { kinds.push('card'); break }\n }\n if (TAIL.test(text)) kinds.push('card-tail')\n return kinds\n }\n return { kindsIn }\n})()`\n\n/**\n * The scan: visible text in the viewport, plus the values of text inputs.\n * Skips anything inside a masked element, password fields, and text the eye\n * cannot see. Reports kind + a selector-ish name for the element + its rect.\n */\nexport const EXPOSURE_PROBE = `(() => {\n const { kindsIn } = ${EXPOSURE_MATCHERS_SRC}\n const vw = innerWidth, vh = innerHeight\n // A selector that reaches THIS element and no other, so it can be pasted\n // into \"mask\" as it is: climb until the path is unique, and say which\n // sibling wherever a tag-and-class alone would match several.\n const segment = (el) => {\n const tid = el.getAttribute('data-testid')\n if (tid) return el.tagName.toLowerCase() + '[data-testid=\"' + tid + '\"]'\n if (el.id && /^[A-Za-z_][\\\\w-]*$/.test(el.id)) return el.tagName.toLowerCase() + '#' + el.id\n const cls = [...el.classList].filter((c) => /^[A-Za-z_-][\\\\w-]*$/.test(c)).slice(0, 2)\n let seg = el.tagName.toLowerCase() + (cls.length ? '.' + cls.join('.') : '')\n const p = el.parentElement\n if (p && [...p.children].filter((c) => c.matches(seg)).length > 1)\n seg += ':nth-child(' + ([...p.children].indexOf(el) + 1) + ')'\n return seg\n }\n const name = (el) => {\n const parts = []\n for (let cur = el; cur && cur !== document.body && cur !== document.documentElement; cur = cur.parentElement) {\n parts.unshift(segment(cur))\n let n = 2\n try { n = document.querySelectorAll(parts.join(' > ')).length } catch {}\n // a bare tag is unique HERE and nowhere else: give it its parent too\n const bare = parts.length === 1 && !/[#.\\\\[]/.test(parts[0])\n if ((n === 1 && !bare) || parts.length >= 5) break\n }\n return parts.join(' > ')\n }\n const seen = (el) => {\n if (el.closest('[data-vos-masked]')) return null\n const r = el.getBoundingClientRect()\n if (r.width < 2 || r.height < 2) return null\n if (r.bottom <= 0 || r.right <= 0 || r.top >= vh || r.left >= vw) return null\n const s = getComputedStyle(el)\n if (s.visibility === 'hidden' || s.display === 'none' || +s.opacity === 0) return null\n return r\n }\n const out = [], keys = new Set()\n const add = (el, text) => {\n const kinds = kindsIn(text)\n if (!kinds.length) return\n const r = seen(el)\n if (!r) return\n const selector = name(el)\n for (const kind of kinds) {\n const k = kind + '|' + selector\n if (keys.has(k) || out.length >= 40) continue\n keys.add(k)\n out.push({ kind, selector, rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } })\n }\n }\n const walker = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT)\n for (let n; (n = walker.nextNode()); ) {\n const el = n.parentElement\n if (!el || /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(el.tagName)) continue\n add(el, n.nodeValue)\n }\n for (const el of document.querySelectorAll('input, textarea')) {\n if (/^(password|hidden|file|checkbox|radio)$/.test(el.type)) continue\n add(el, el.value)\n }\n const hits = {}\n for (const [sel, n] of Object.entries(window.__vosMaskHits || {})) hits[sel] = n\n return { exposures: out, maskHits: hits }\n})()`\n\n/**\n * The mask, as an init script: it runs at document start on EVERY navigation,\n * so a masked value is hidden before the page's first paint, and a\n * MutationObserver re-applies it after a client-side re-render. A form\n * control is blurred even when `as: 'text'` was asked for: writing into an\n * input would change what the app submits.\n */\nexport function maskInitScript(masks: MaskRule[]): string {\n const rules = masks.map((m) => ({\n selector: m.selector,\n as: m.as === 'text' ? 'text' : 'blur',\n text: m.text ?? '',\n }))\n return `(() => {\n const RULES = ${JSON.stringify(rules)}\n const hits = (window.__vosMaskHits = window.__vosMaskHits || {})\n for (const r of RULES) hits[r.selector] = hits[r.selector] || 0\n const css = RULES.map((r) => r.selector + '[data-vos-masked=\"blur\"]{filter:blur(7px) !important;user-select:none !important}').join('\\\\n')\n const paint = () => {\n const root = document.head || document.documentElement\n if (!root || document.getElementById('__vos-mask-style')) return\n const style = document.createElement('style')\n style.id = '__vos-mask-style'\n style.textContent = css\n root.appendChild(style)\n }\n const apply = () => {\n paint()\n for (const r of RULES) {\n let found\n try { found = document.querySelectorAll(r.selector) } catch { continue }\n if (found.length > hits[r.selector]) hits[r.selector] = found.length\n for (const el of found) {\n const form = /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName)\n const mode = r.as === 'text' && !form ? 'text' : 'blur'\n if (el.getAttribute('data-vos-masked') !== mode) el.setAttribute('data-vos-masked', mode)\n if (mode !== 'text') continue\n const texts = []\n const w = document.createTreeWalker(el, NodeFilter.SHOW_TEXT)\n for (let n; (n = w.nextNode()); ) texts.push(n)\n if (!texts.length) { if (el.textContent !== r.text) el.textContent = r.text; continue }\n texts.forEach((n, i) => { const want = i === 0 ? r.text : ''; if (n.nodeValue !== want) n.nodeValue = want })\n }\n }\n }\n new MutationObserver(apply).observe(document, { childList: true, subtree: true, characterData: true })\n document.addEventListener('DOMContentLoaded', apply)\n apply()\n})()`\n}\n\n/**\n * Accumulates scans across a take: an exposure is reported ONCE, at the\n * first step it was seen, with how many scans saw it.\n */\nexport class ExposureLog {\n private byKey = new Map<string, Exposure>()\n private maskHits = new Map<string, number>()\n\n constructor(masks: MaskRule[] = []) {\n for (const m of masks) this.maskHits.set(m.selector, 0)\n }\n\n add(\n step: number,\n scan: {\n exposures?: Omit<Exposure, 'step' | 'seen'>[]\n maskHits?: Record<string, number>\n } | null,\n ): void {\n if (!scan) return\n for (const e of scan.exposures ?? []) {\n const key = `${e.kind}|${e.selector}`\n const had = this.byKey.get(key)\n if (had) had.seen += 1\n else this.byKey.set(key, { step, ...e, seen: 1 })\n }\n for (const [sel, n] of Object.entries(scan.maskHits ?? {})) {\n if (n > (this.maskHits.get(sel) ?? 0)) this.maskHits.set(sel, n)\n }\n }\n\n exposures(): Exposure[] {\n return [...this.byKey.values()]\n }\n\n masks(rules: MaskRule[]): MaskReport[] {\n return rules.map((m) => ({\n selector: m.selector,\n as: m.as === 'text' ? 'text' : 'blur',\n hits: this.maskHits.get(m.selector) ?? 0,\n }))\n }\n}\n\nconst KIND_WORDS: Record<ExposureKind, string> = {\n email: 'an email address',\n key: 'something shaped like an API key or token',\n card: 'a card number',\n 'card-tail': \"a card's last digits\",\n}\n\n/** One exposure, in words. `step` -1 is the page as it opened. */\nexport function exposureLine(e: Exposure): string {\n const when = e.step < 0 ? 'as the page opened' : `at step #${e.step}`\n return `${KIND_WORDS[e.kind]} in ${e.selector} (${when}, ${e.rect.x},${e.rect.y} ${e.rect.w}×${e.rect.h})`\n}\n\nexport const EXPOSURE_ADVICE =\n 'The recording shows these. Record from a demo account, or hide them before the camera rolls with \"mask\" in actions.json: { \"selector\": \"…\", \"as\": \"text\", \"text\": \"demo@acme.test\" } swaps the words, \"as\": \"blur\" blurs. Then re-record.'\n","/**\n * `setup`: the steps that run BEFORE the camera rolls. A sign-in form, a\n * cookie banner, the \"choose your editor\" modal, an onboarding tour: things\n * a take must get past and must not show. They run after the first\n * navigation and before `Page.startScreencast`, with no cursor synthesis,\n * no pace accounting and nothing written to `meta.steps`. Then the recorder\n * navigates to `url` again and the take begins where the setup left it.\n *\n * A `type` step's `text` may be `{ \"env\": \"DEMO_PASSWORD\" }`: resolved at run\n * time from the `env` the caller hands in (the shell's for the CLI, the\n * job's own map for a hosted take), never logged, never stored. The\n * guarantee is narrow and real: the secret is never in a file that travels\n * (`actions.json` is committed and pushed with the take; `meta.json` is read\n * by the digest) and never in the footage.\n */\nimport type { RecorderPage } from './driver'\n\nexport type SetupText = string | { env: string }\n\nexport type SetupStep = (\n | { do: 'wait'; ms: number }\n | { do: 'click'; selector: string; ms?: number }\n | { do: 'type'; selector: string; text: SetupText; ms?: number }\n | { do: 'press'; key: string; ms?: number }\n | { do: 'goto'; url: string }\n) & { id?: string }\n\nconst VERBS = new Set(['wait', 'click', 'type', 'press', 'goto'])\n\n/**\n * Why a page address is not one the recorder opens, or null. A script's\n * `url` and a setup's `goto` open a browser, so only http and https are\n * taken: a `file:` address would read this machine's disk into a take\n * and a `javascript:` one would run in the page.\n */\nexport function urlSchemeProblem(url: string): string | null {\n let u: URL\n try {\n u = new URL(url)\n } catch {\n return `${url} is not a URL`\n }\n if (u.protocol !== 'http:' && u.protocol !== 'https:')\n return `${url} is not an http(s) address, and the recorder opens only http and https pages`\n return null\n}\n\n/** Structural validation, mirrored on `validateActions` for `steps`. */\nexport function validateSetup(value: unknown): string[] {\n const errors: string[] = []\n if (!Array.isArray(value)) return ['setup must be an array of steps']\n value.forEach((raw, i) => {\n const at = `setup[${i}]`\n if (typeof raw !== 'object' || raw === null) {\n errors.push(`${at}: must be an object`)\n return\n }\n const s = raw as Record<string, unknown>\n if (typeof s.do !== 'string' || !VERBS.has(s.do)) {\n errors.push(`${at}: \"do\" must be one of ${[...VERBS].join(', ')}`)\n return\n }\n if ((s.do === 'click' || s.do === 'type') && typeof s.selector !== 'string')\n errors.push(`${at}: ${s.do} needs a selector`)\n if (s.do === 'wait' && typeof s.ms !== 'number')\n errors.push(`${at}: wait needs ms`)\n if (s.do === 'press' && typeof s.key !== 'string')\n errors.push(`${at}: press needs a key`)\n if (s.do === 'goto') {\n if (typeof s.url !== 'string') errors.push(`${at}: goto needs a url`)\n else {\n const problem = urlSchemeProblem(s.url)\n if (problem) errors.push(`${at}: goto ${problem}`)\n }\n }\n if (s.do === 'type') {\n const t = s.text\n const isEnv =\n typeof t === 'object' &&\n t !== null &&\n typeof (t as { env?: unknown }).env === 'string' &&\n Object.keys(t).length === 1\n if (typeof t !== 'string' && !isEnv)\n errors.push(\n `${at}: type needs text, a string or { \"env\": \"NAME\" } read at run time`,\n )\n if (\n typeof t === 'string' &&\n /passw|secret|token/i.test(String(s.selector)) &&\n t.length > 0\n )\n errors.push(\n `${at}: a literal value typed into ${String(s.selector)} would live in actions.json, which is committed and pushed. Use { \"env\": \"NAME\" }`,\n )\n }\n })\n return errors\n}\n\n/** The names a setup reads from its env, so a host can say what it must supply. */\nexport function setupEnvNames(steps: SetupStep[] | undefined): string[] {\n const out = new Set<string>()\n for (const s of steps ?? []) {\n if (s.do === 'type' && typeof s.text === 'object') out.add(s.text.env)\n }\n return [...out]\n}\n\n/** A `{ env }` text resolved, or thrown in words. The value is never returned to a log. */\nexport function resolveSetupText(\n t: SetupText,\n env: Record<string, string | undefined>,\n): { value: string; secret: boolean } {\n if (typeof t === 'string') return { value: t, secret: false }\n const v = env[t.env]\n if (v === undefined || v === '')\n throw new SetupEnvError(\n `setup: the environment variable ${t.env} is not set, and a type step reads it. Export it in the shell that runs vos record; it is never written to a file`,\n )\n return { value: v, secret: true }\n}\n\nexport interface SetupResult {\n ran: number\n /** what the log may say about each step: the verb and the selector, never a typed value */\n lines: string[]\n /** a selector that never appeared; the take does not start */\n failed?: { step: number; do: string; selector?: string }\n}\n\n/**\n * Run the setup on a page, with plain Playwright actions: no humanized\n * pointer, no cursor events, no frames. A selector that never appears\n * fails the setup, because a take that begins at a half-finished sign-in is\n * the wall by another name.\n */\nexport async function runSetup(\n page: RecorderPage,\n steps: SetupStep[],\n opts: {\n sleep: (ms: number) => Promise<void>\n /** Absent means no env at all: a `{ env }` text then fails in words. */\n env?: Record<string, string | undefined>\n },\n): Promise<SetupResult> {\n const env = opts.env ?? {}\n const lines: string[] = []\n for (const [i, step] of steps.entries()) {\n const settle = 'ms' in step && typeof step.ms === 'number' ? step.ms : 150\n try {\n switch (step.do) {\n case 'wait':\n await opts.sleep(step.ms)\n lines.push(`setup #${i} wait ${step.ms}ms`)\n break\n case 'goto':\n await page\n .goto(step.url, { waitUntil: 'networkidle', timeout: 45000 })\n .catch(() => null)\n lines.push(`setup #${i} goto ${step.url}`)\n break\n case 'press':\n await page.keyboard.press(step.key)\n await opts.sleep(settle)\n lines.push(`setup #${i} press ${step.key}`)\n break\n case 'click': {\n const loc = page.locator(step.selector).first()\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n await loc.click()\n await opts.sleep(settle)\n lines.push(`setup #${i} click ${step.selector}`)\n break\n }\n case 'type': {\n const loc = page.locator(step.selector).first()\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n const { value, secret } = resolveSetupText(step.text, env)\n await loc.fill(value)\n await opts.sleep(settle)\n // The log names the field, never what went into it.\n lines.push(\n `setup #${i} type ${secret ? `\\${${(step.text as { env: string }).env}}` : `${value.length} chars`} into ${step.selector}`,\n )\n break\n }\n }\n } catch (e) {\n if (e instanceof SetupEnvError) throw e\n return {\n ran: i,\n lines,\n failed: {\n step: i,\n do: step.do,\n ...('selector' in step ? { selector: step.selector } : {}),\n },\n }\n }\n }\n return { ran: steps.length, lines }\n}\n\n/** A `{ env }` the shell did not provide: a usage error, not a page's. */\nexport class SetupEnvError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'SetupEnvError'\n }\n}\n\n/** A setup step whose selector never appeared: the take does not start. */\nexport class SetupError extends Error {\n constructor(public failed: NonNullable<SetupResult['failed']>) {\n super(\n `setup #${failed.step} ${failed.do}${failed.selector ? ` ${failed.selector}` : ''}: the selector never appeared, so the take would begin at a half-finished setup. Nothing was recorded. Fix the setup step (rehearse with --dry-run), then record.`,\n )\n this.name = 'SetupError'\n }\n}\n\n/** `--header name=value`, repeatable: extra request headers on every request. */\nexport function parseHeaders(\n given: string[] | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const h of given ?? []) {\n const i = h.indexOf('=')\n if (i <= 0) throw new Error(`--header wants name=value, got \"${h}\"`)\n out[h.slice(0, i).trim()] = h.slice(i + 1)\n }\n return out\n}\n","/**\n * The recorder — a browser drives the action script while:\n * - CDP Page.startScreencast collects JPEG frames (epoch-timestamped;\n * hold-last-frame gaps are filled at encode time), and\n * - every dispatched input is logged as a CursorEvent (the synthesized track:\n * exact coords, exact times, fresh element rects — no capture needed).\n *\n * The MECHANISM, host-free (AN4): the browser arrives as a structural driver\n * (a launched Node Playwright browser from the CLI, a connected\n * @cloudflare/playwright browser from the fleet), frames leave through a\n * sink, the platform and the setup env are handed in, and nothing here\n * touches a filesystem or a process. The CLI's `recordTake` wraps this with\n * a take directory; the fleet's consumer wraps it with R2. Both produce the\n * same events, meta and frame index for the same script.\n */\nimport type {\n FrameSink,\n RecorderBrowser,\n RecorderClock,\n RecorderContext,\n} from './driver'\nimport { realSleep } from './driver'\nimport { capReached, cappedLine, clampWait } from './cap'\nimport {\n PRESS_HOLD_MS,\n PRESS_LEAD_MS,\n SCROLL_SETTLE_MS,\n TRAILING_HOLD_MS,\n askedMs,\n deadLine,\n deadTime,\n deadWarns,\n holdLeftMs,\n settleVerdict,\n clockMotion,\n clockTyping,\n paceLine,\n paceReport,\n pointerTravelMs,\n scrollTravelMs,\n settleMs,\n} from './pace'\nimport type { DeadReport, PaceReport, StepPace } from './pace'\nimport type {\n CursorEvent,\n RecordingMeta,\n Rect,\n StepSpan,\n} from '@vosjs/studio-core'\nimport { WALL_PROBE } from './wall'\nimport { EXPOSURE_PROBE, ExposureLog, maskInitScript } from './exposure'\nimport { SetupError, runSetup } from './setup'\nimport type { ActionsFile } from './actions'\n\n/** How long a `read` waits for its element after the step settled. */\nconst READ_WAIT_MS = 1500\n/** The most a step's `read` keeps: a payload, never a page. */\nconst READ_MAX_CHARS = 2048\n\n/**\n * The headers a request carries, or null to leave it alone: a job's\n * headers (a preview's bypass token) go to the ORIGIN the take is of and\n * nowhere else, since the recorded page embeds whatever third parties it\n * likes and a redirect can land anywhere.\n */\nexport function headersFor(\n requestUrl: string,\n entryUrl: string,\n headers: Record<string, string>,\n): Record<string, string> | null {\n try {\n return new URL(requestUrl).origin === new URL(entryUrl).origin\n ? headers\n : null\n } catch {\n return null\n }\n}\n\nasync function applyHeaders(\n context: RecorderContext,\n headers: Record<string, string>,\n entryUrl: string,\n log: (msg: string) => void,\n): Promise<void> {\n if (!context.route) {\n await context.setExtraHTTPHeaders(headers)\n log(' (this browser scopes no headers: they ride every request)')\n return\n }\n await context.route('**/*', async (route) => {\n const req = route.request()\n const scoped = headersFor(req.url(), entryUrl, headers)\n await route.continue(\n scoped ? { headers: { ...req.headers(), ...scoped } } : undefined,\n )\n })\n}\n\n/** A page URL as a take keeps it: origin and path, never a query or a hash. */\nexport function publicUrl(u: string): string {\n try {\n const x = new URL(u)\n return `${x.origin}${x.pathname}`\n } catch {\n return ''\n }\n}\nimport type { Arrival, WallVerdict } from './wall'\n\nexport interface FrameRec {\n file: string\n /** ms since t0 */\n tMs: number\n}\n\nexport interface SkippedStep {\n /** index into actions.steps */\n step: number\n do: string\n selector: string\n}\n\n/** A stretch with no screencast frames — the page pixels did not change. */\nexport interface FreezeSpan {\n /** seconds into the take */\n from: number\n to: number\n ms: number\n}\n\nexport interface RecordResult {\n events: CursorEvent[]\n frames: FrameRec[]\n meta: RecordingMeta\n /** The take's pace: what the script asked, what the gestures added, what the page cost. */\n pace: PaceReport\n /** steps whose selector never became visible — the take continued without them. */\n skipped: SkippedStep[]\n /** the initial goto never reached networkidle (recording proceeded anyway). */\n navTimeout: boolean\n /** A wall the caller let through; null when the recorder landed where it was asked. */\n wall: WallVerdict | null\n /** Sensitive-looking text seen in the frame (kind + place, never the string). */\n exposures: NonNullable<RecordingMeta['exposures']>\n /** The script's masks with how many elements each reached; hits 0 hid nothing. */\n masks: NonNullable<RecordingMeta['masks']>\n /**\n * Smoothness telemetry: stretches ≥400ms with no visual change. Frozen\n * footage is the #1 enemy of a smooth product video — either the flow should\n * keep motion in frame (animate, hover a preview, scroll) or the doc should\n * trim/speed through these. freezePct = share of the take that is frozen.\n */\n freezes: FreezeSpan[]\n freezePct: number\n /**\n * The smoothness WARNING: still footage under a parked cursor past the\n * beat it takes to read what changed, per step (`deadTime`). A still page\n * being read is content; this is the part of a hold nobody is reading.\n */\n dead: DeadReport\n /** The take reached --max-duration and stopped there; later steps did not run. */\n capped: boolean\n /** The actions as recorded, `url` resolved: what a take directory writes back. */\n actions: ActionsFile\n}\n\nexport interface RecordOpts {\n /** Stop the capture at this many seconds (the hosted cap). */\n maxDurationSeconds?: number\n /**\n * Path to a Playwright storage state (cookies + origin storage), so the\n * recorder drives a SIGNED-IN product. A demo of anything behind a login\n * needs it, and a sign-in form cannot always be scripted (an emailed code,\n * an SSO hop). Export one from a real browser, or with\n * `context.storageState({ path })`.\n */\n storageState?: string\n /**\n * REHEARSE the flow: every step runs against the real page, in order,\n * because a later selector usually exists only after an earlier click. But\n * nothing is captured (no screencast, no frames), nothing is written, the\n * pointer lands instead of travelling and every pause is cut to a beat, so\n * a script that misses a selector says so in seconds instead of after a\n * full real-time take and its encode. Selector lookups keep their whole\n * timeout, so a miss here is a miss in the take.\n */\n dryRun?: boolean\n /**\n * Called once the first navigation has settled, BEFORE a frame is captured.\n * The caller judges the wall here and only then prepares the take\n * directory, so a take refused at a sign-in never clears the footage a\n * re-record would have replaced. A throw closes the context and propagates.\n */\n onArrival?: (\n arrival: Arrival,\n ) => Promise<WallVerdict | null | void> | WallVerdict | null | void\n /** Extra request headers on every request (`--header name=value`). */\n headers?: Record<string, string>\n /**\n * A ready-made context to record IN, instead of one made from `browser`:\n * `--session <name>`, a persistent profile the person signed in to. The\n * recorder still sizes the viewport and closes it at the end.\n */\n context?: RecorderContext\n /**\n * The environment a setup's `{ env }` texts resolve from: the shell's\n * for the CLI, the job's own map on the fleet. Absent means no env at\n * all, so a setup that reads one fails in words.\n */\n env?: Record<string, string | undefined>\n /** The platform the take is recorded on, for `meta.platform`. */\n platform?: RecordingMeta['platform']\n}\n\n/** The longest any pause lasts in a rehearsal. */\nconst DRY_PAUSE_MS = 120\n\n/**\n * The expression a scroll tick evaluates: move the first scrollable\n * ancestor of the element under the cursor by `dy`, else the window, the\n * container a wheel at that point would have moved. A string, so no host\n * helper (`__name`) has to exist in the page.\n */\nexport function scrollByScript(x: number, y: number, dy: number): string {\n return `(() => {\n let el = document.elementFromPoint(${Math.round(x)}, ${Math.round(y)});\n while (el && el !== document.body && el !== document.documentElement) {\n const cs = getComputedStyle(el);\n if (/(auto|scroll)/.test(cs.overflowY) && el.scrollHeight > el.clientHeight + 1) {\n el.scrollBy(0, ${dy});\n return 'el';\n }\n el = el.parentElement;\n }\n window.scrollBy(0, ${dy});\n return 'window';\n})()`\n}\n\n/** Minimal JPEG SOF parse for real encoded dimensions. */\nexport function jpegDims(buf: Uint8Array): { w: number; h: number } | null {\n const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)\n let i = 2\n while (i < buf.length - 9) {\n if (buf[i] !== 0xff) return null\n const marker = buf[i + 1]\n const len = view.getUint16(i + 2)\n if (\n marker >= 0xc0 &&\n marker <= 0xcf &&\n marker !== 0xc4 &&\n marker !== 0xc8 &&\n marker !== 0xcc\n ) {\n return { h: view.getUint16(i + 5), w: view.getUint16(i + 7) }\n }\n i += 2 + len\n }\n return null\n}\n\n/** Base64 to bytes without Node's Buffer, so the fleet's isolate runs it too. */\nexport function base64Bytes(data: string): Uint8Array {\n const bin = atob(data)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nexport async function recordTake(\n browser: RecorderBrowser,\n url: string,\n actions: ActionsFile,\n sink: FrameSink,\n log: (msg: string) => void,\n opts: RecordOpts = {},\n): Promise<RecordResult> {\n const dry = opts.dryRun === true\n const sleep = dry\n ? (ms: number) => realSleep(Math.min(ms, DRY_PAUSE_MS))\n : realSleep\n // A rehearsal is not held to the recording cap: its clock is not the take's.\n const maxSeconds = dry ? Infinity : (opts.maxDurationSeconds ?? Infinity)\n const vw = actions.viewport?.width ?? 1280\n const vh = actions.viewport?.height ?? 720\n const context =\n opts.context ??\n (await browser.newContext({\n viewport: { width: vw, height: vh },\n deviceScaleFactor: 1,\n ...(opts.storageState ? { storageState: opts.storageState } : {}),\n }))\n if (opts.headers && Object.keys(opts.headers).length)\n await applyHeaders(context, opts.headers, url, log)\n // Masks go in as an init script, so they are in force at document start on\n // every navigation: the real value never reaches a painted frame.\n const masks = actions.mask ?? []\n if (masks.length) await context.addInitScript(maskInitScript(masks))\n const exposureLog = new ExposureLog(masks)\n const page = await context.newPage()\n // What the frame shows, read after each step. A few ms in the page; a scan\n // that fails (mid-navigation) is skipped, never fatal.\n const scanExposures = async (step: number) => {\n const scan = await page.evaluate(EXPOSURE_PROBE).catch(() => null)\n exposureLog.add(step, scan as Parameters<ExposureLog['add']>[1])\n }\n page.on('console', (m) => {\n if (m.type() === 'error') log(` [page error] ${m.text()}`)\n })\n\n log(`goto ${url}`)\n let navTimeout = false\n let response = await page\n .goto(url, { waitUntil: 'networkidle', timeout: 45000 })\n .catch(() => {\n navTimeout = true\n log(' (networkidle timeout — continuing)')\n return null\n })\n await sleep(800) // hydration settle\n\n // The setup: off camera, before the wall is judged, because a setup that\n // signs in is exactly what makes the wall not there. A selector that never\n // appears fails the take here, in words, before anything is captured.\n const setup = actions.setup ?? []\n if (setup.length) {\n log(`setup: ${setup.length} step(s), off camera`)\n const result = await runSetup(page, setup, {\n sleep: realSleep,\n env: opts.env ?? {},\n })\n for (const line of result.lines) log(` ${line}`)\n if (result.failed) {\n await context.close().catch(() => {})\n throw new SetupError(result.failed)\n }\n // Back to the page the take is OF, signed in and past the banners.\n log(`goto ${url} (after setup)`)\n response = await page\n .goto(url, { waitUntil: 'networkidle', timeout: 45000 })\n .catch(() => null)\n await sleep(800)\n }\n\n // A wall the caller let through (--allow-wall, or a soft one without\n // --strict) rides the take's meta, so a digest made later still says so.\n let wall: WallVerdict | null = null\n if (opts.onArrival) {\n const seen = (await page.evaluate(WALL_PROBE).catch(() => null)) as Pick<\n Arrival,\n 'passwordFields' | 'newPasswordField' | 'oneTimeCodeField'\n > | null\n try {\n wall =\n (await opts.onArrival({\n askedUrl: url,\n landedUrl: page.url(),\n ...(response ? { status: response.status() } : {}),\n passwordFields: seen?.passwordFields ?? 0,\n newPasswordField: seen?.newPasswordField ?? false,\n oneTimeCodeField: seen?.oneTimeCodeField ?? false,\n })) ?? null\n } catch (e) {\n await context.close().catch(() => {})\n throw e\n }\n }\n\n await scanExposures(-1)\n\n const cdp = await context.newCDPSession(page)\n const frames: FrameRec[] = []\n let frameIdx = 0\n let t0 = 0\n // Written from the screencast callback, so the read below does not\n // narrow: a box, not a plain local.\n const first: { dims: { w: number; h: number } | null } = { dims: null }\n // Frames are handed to the sink in order; the chain keeps a slow sink\n // (R2) from reordering them and is awaited before the meta is built.\n let sinkChain: Promise<void> = Promise.resolve()\n if (!dry)\n cdp.on('Page.screencastFrame', (ev) => {\n const tsMs = ev.metadata.timestamp\n ? ev.metadata.timestamp * 1000\n : Date.now()\n const file = `frame-${String(frameIdx++).padStart(5, '0')}.jpg`\n const bytes = base64Bytes(ev.data)\n if (!first.dims) first.dims = jpegDims(bytes)\n frames.push({ file, tMs: Math.max(0, Math.round(tsMs - t0)) })\n sinkChain = sinkChain.then(() => sink.frame(file, bytes)).catch(() => {})\n cdp\n .send('Page.screencastFrameAck', { sessionId: ev.sessionId })\n .catch(() => {})\n })\n\n t0 = Date.now()\n if (!dry)\n await cdp.send('Page.startScreencast', {\n format: 'jpeg',\n quality: 90,\n maxWidth: vw,\n maxHeight: vh,\n everyNthFrame: 1,\n })\n\n const events: CursorEvent[] = []\n const cur = { x: 48, y: 48 }\n const now = () => Date.now() - t0\n const emit = (e: Omit<CursorEvent, 't'>) => events.push({ t: now(), ...e })\n\n await page.mouse.move(cur.x, cur.y)\n emit({ x: cur.x, y: cur.y, type: 'move' })\n\n const clock: RecorderClock = { now: () => Date.now(), sleep }\n // The pointer's travel is driven by the CLOCK (pace.ts): its position is\n // a function of the elapsed time and it ends when the travel's duration\n // has elapsed, so a page that answers each mouse.move slowly costs\n // samples, never seconds. Every sample the page took is a cursor event\n // at its real time, which is what the smoothing and the follow read.\n const moveTo = async (tx: number, ty: number) => {\n const dist = Math.hypot(tx - cur.x, ty - cur.y)\n const from = { ...cur }\n await clockMotion(\n dry ? 0 : pointerTravelMs(dist),\n async (u) => {\n cur.x = from.x + (tx - from.x) * u\n cur.y = from.y + (ty - from.y) * u\n await page.mouse.move(cur.x, cur.y)\n emit({ x: Math.round(cur.x), y: Math.round(cur.y), type: 'move' })\n },\n clock,\n )\n }\n\n /**\n * The words under a selector once a step has settled: trimmed,\n * whitespace collapsed, bounded. Null when nothing matches in time, which\n * the step line says; a missing payload never fails a take.\n */\n const readText = async (\n pg: typeof page,\n selector: string,\n ): Promise<string | null> => {\n try {\n await pg\n .locator(selector)\n .first()\n .waitFor({ state: 'visible', timeout: READ_WAIT_MS })\n // The probe is a string, the one evaluate shape every driver shares.\n // A field's words are its VALUE (what was typed), which textContent\n // never carries; everything else keeps its textContent.\n const raw = await pg.evaluate<string>(\n `(() => { const el = document.querySelector(${JSON.stringify(selector)}); if (!el) return ''; if ('value' in el && typeof el.value === 'string' && /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName)) return el.value; return el.textContent || '' })()`,\n )\n const words = raw.replace(/\\s+/g, ' ').trim()\n return words ? words.slice(0, READ_MAX_CHARS) : null\n } catch {\n return null\n }\n }\n const boxOf = async (selector: string): Promise<Rect | null> => {\n const loc = page.locator(selector).first()\n try {\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n const before = await page\n .evaluate(() => [window.scrollX, window.scrollY])\n .catch(() => [0, 0])\n await loc.scrollIntoViewIfNeeded()\n const after = await page\n .evaluate(() => [window.scrollX, window.scrollY])\n .catch(() => before)\n // A lookup that scrolled the page lets the scroll land; one that\n // did not costs nothing.\n if (before[0] !== after[0] || before[1] !== after[1])\n await sleep(SCROLL_SETTLE_MS)\n const bb = await loc.boundingBox()\n if (!bb) return null\n return { x: bb.x, y: bb.y, w: bb.width, h: bb.height }\n } catch {\n log(` (selector not found, skipping: ${selector})`)\n return null\n }\n }\n\n const clickAt = async (rect: Rect) => {\n await moveTo(rect.x + rect.w / 2, rect.y + rect.h / 2)\n await sleep(PRESS_LEAD_MS)\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button: 0,\n rect,\n })\n await page.mouse.down()\n await sleep(PRESS_HOLD_MS)\n await page.mouse.up()\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'up',\n button: 0,\n rect,\n })\n }\n\n /**\n * Wait for the page to settle after a press, reading the screencast:\n * returns ms since the last change (null when nothing changed). A dry\n * run has no frames and settles at once.\n */\n const waitSettled = async (): Promise<number | null> => {\n if (dry) return null\n const pressAt = now()\n const before = frames.length\n for (;;) {\n const t = now()\n const last = frames.length > before ? frames[frames.length - 1] : null\n const sinceChange = last ? t - last.tMs : null\n if (settleVerdict({ sincePress: t - pressAt, sinceChange }) === 'settled')\n return sinceChange\n await sleep(40)\n }\n }\n\n const skipped: SkippedStep[] = []\n // The step timeline: when each step ran, in source seconds — what\n // lets a cut anchored to steps re-time onto a NEW recording of the same\n // script (`vos plan --reuse`). Every step that STARTED is recorded; a\n // skipped selector is marked, never silently absent.\n const stepSpans: StepSpan[] = []\n const paces: StepPace[] = []\n let capped = false\n for (const [stepIdx, step] of actions.steps.entries()) {\n // The cap is checked between steps (a step is one gesture and runs\n // whole); only a wait is cut short, since it is the one step that can\n // sit past the cap on its own.\n if (capReached(now(), maxSeconds)) {\n capped = true\n break\n }\n const stepStart = now()\n // The gesture the recorder adds by design around this step's ask: the\n // pointer's travel, the press, the settle. Everything else the step's\n // wall time holds is the page's (a slow round trip, a scroll landing).\n let gestureMs = 0\n const gesture = async <T>(fn: () => Promise<T>): Promise<T> => {\n const t = now()\n const out = await fn()\n gestureMs += now() - t\n return out\n }\n const skippedBefore = skipped.length\n // A step that changes the page's URL (a click that navigates, the\n // wait that lets the load land) is marked: the planner proposes a\n // transition at the page change.\n const urlBefore = page.url()\n // The selector's box at the gesture: kept on the step so a layer can\n // name what the step touched (`overlays[].pin.step`).\n let stepRect: Rect | null = null\n switch (step.do) {\n case 'wait':\n await sleep(clampWait(step.ms, now(), maxSeconds))\n break\n case 'move':\n await moveTo(step.x, step.y)\n break\n case 'hover': {\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (rect) {\n await gesture(() => moveTo(rect.x + rect.w / 2, rect.y + rect.h / 2))\n log(`hover ${step.selector}`)\n await sleep(step.ms ?? 700) // parked cursor = dwell signal for the planner\n } else\n skipped.push({ step: stepIdx, do: step.do, selector: step.selector })\n break\n }\n case 'click': {\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (rect) {\n await gesture(() => clickAt(rect))\n log(`click ${step.selector}`)\n // The settle is the recorder's (watched on the screencast); the\n // hold is the author's, from the page's last change.\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\n } else\n skipped.push({ step: stepIdx, do: step.do, selector: step.selector })\n break\n }\n case 'type': {\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (rect) {\n // The click is what opens the typing zoom on the field. A step that\n // only finishes earlier typing (a submitting Enter) passes\n // focus:false: the field is already focused and a second click\n // rings a click effect on empty space beside the text.\n if (step.focus !== false) await gesture(() => clickAt(rect))\n // Where the caret stands before the first character: a click\n // lands it where the pointer hit, and a code editor line is\n // typed at its end. `replace` selects the value so the typing\n // replaces it (a form that opens filled in).\n if (step.at === 'end') await page.keyboard.press('End')\n else if (step.at === 'start') await page.keyboard.press('Home')\n if (step.replace) await page.keyboard.press('ControlOrMeta+a')\n // Typing-activity pings (TZ): one per ~350ms while characters land,\n // plus one at completion so the planner's hold starts at the true\n // typing end. When-and-where only — a ping never carries the text.\n // ~0.6s+ of typing earns the zoom (TYPING_MIN_DUR + ping floor), so\n // pace delayMs like a person for a camera moment, not a paste.\n const delay = step.delayMs ?? 40\n const ping = () =>\n emit({\n x: Math.round(rect.x + rect.w / 2),\n y: Math.round(rect.y + rect.h / 2),\n type: 'key',\n rect,\n })\n let lastPing = -Infinity\n await clockTyping(\n [...step.text],\n delay,\n async (ch) => {\n if (now() - lastPing >= 350) {\n lastPing = now()\n ping()\n }\n await page.keyboard.type(ch)\n },\n clock,\n )\n ping()\n log(`type ${step.text.length} chars into ${step.selector}`)\n await gesture(() => sleep(settleMs(step)))\n } else\n skipped.push({ step: stepIdx, do: step.do, selector: step.selector })\n break\n }\n case 'press': {\n // One named key, recorded as a typing ping (when-and-where only,\n // never the key) so the planner's typing session holds through a\n // submitting Enter or an Escape that closes what a click opened.\n // No click: the field is as the flow left it. With a selector the\n // ping (and the step's rect) is that element's; without, the\n // pointer's.\n let rect: Rect | null = null\n if (step.selector) {\n rect = await boxOf(step.selector)\n stepRect = rect\n if (!rect) {\n skipped.push({\n step: stepIdx,\n do: step.do,\n selector: step.selector,\n })\n break\n }\n }\n emit({\n x: Math.round(rect ? rect.x + rect.w / 2 : cur.x),\n y: Math.round(rect ? rect.y + rect.h / 2 : cur.y),\n type: 'key',\n ...(rect ? { rect } : {}),\n })\n await page.keyboard.press(step.key)\n log(`press ${step.key}`)\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\n break\n }\n case 'scroll': {\n // The scroll travels by the clock, like the pointer, and each tick\n // moves the scroll container under the cursor INSIDE the page\n // (`Runtime.evaluate` returns at once). Not wheel events: CDP's\n // wheel dispatch waits for the renderer to handle the event, and a\n // tab that paints no frame for a small delta, which a fleet browser's\n // background tab is, never answers, so a clock-driven wheel stalled\n // there for good. And not requestAnimationFrame or an in-page timer,\n // which such a tab never fires or throttles to once a second. The\n // screencast captures whatever the compositor paints between ticks,\n // and a layout moved by scrollTo is never a torn composite.\n const total = Math.abs(step.dy)\n const dir = Math.sign(step.dy)\n const sent = { px: 0 }\n await gesture(() =>\n clockMotion(\n dry ? 0 : scrollTravelMs(total),\n async (u) => {\n const target = Math.round(total * u)\n const delta = target - sent.px\n if (delta <= 0) return\n sent.px = target\n await page\n .evaluate(scrollByScript(cur.x, cur.y, dir * delta))\n .catch(() => undefined)\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'scroll',\n })\n },\n clock,\n ),\n )\n await gesture(() => sleep(settleMs(step)))\n break\n }\n case 'drag': {\n // Start point: selector center when given, else explicit coords.\n let start: { x: number; y: number } | null = null\n let rect: Rect | undefined\n if (step.selector) {\n const box = await boxOf(step.selector)\n stepRect = box\n if (box) {\n rect = box\n start = { x: box.x + box.w / 2, y: box.y + box.h / 2 }\n } else {\n skipped.push({\n step: stepIdx,\n do: step.do,\n selector: step.selector,\n })\n break\n }\n } else if (typeof step.x === 'number' && typeof step.y === 'number') {\n start = { x: step.x, y: step.y }\n }\n if (!start) break\n await gesture(() => moveTo(start.x, start.y))\n await gesture(() => sleep(PRESS_LEAD_MS))\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button: 0,\n rect,\n })\n await page.mouse.down()\n await gesture(() => sleep(PRESS_HOLD_MS))\n // The drag is the ask: `ms` of travel by the clock, however slowly\n // the page answers each move (a slider re-rendering per sample).\n const dur = step.ms ?? 700\n const from = { ...cur }\n await clockMotion(\n dur,\n async (u) => {\n cur.x = from.x + (step.tx - from.x) * u\n cur.y = from.y + (step.ty - from.y) * u\n await page.mouse.move(cur.x, cur.y)\n emit({ x: Math.round(cur.x), y: Math.round(cur.y), type: 'move' })\n },\n clock,\n )\n await gesture(() => sleep(settleMs({ do: 'drag' })))\n await page.mouse.up()\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'up',\n button: 0,\n rect,\n })\n log(\n `drag ${step.selector ?? `${start.x},${start.y}`} → ${step.tx},${step.ty}`,\n )\n await sleep(400)\n break\n }\n }\n const stepInfo = step as { id?: string; selector?: string; read?: string }\n // The take carries its payload: the page the step left (origin and\n // path, never a query or a hash) and, when the step named a `read`,\n // that element's words once the step has settled, so a layer quotes\n // the take instead of a replay of it.\n const urlAfter = publicUrl(page.url())\n const text = stepInfo.read ? await readText(page, stepInfo.read) : null\n if (stepInfo.read && text === null)\n log(` (read ${stepInfo.read}: nothing there after the step)`)\n stepSpans.push({\n step: stepIdx,\n ...(stepInfo.id ? { id: stepInfo.id } : {}),\n do: step.do,\n ...(stepInfo.selector ? { selector: stepInfo.selector } : {}),\n tStart: +(stepStart / 1000).toFixed(3),\n tEnd: +(now() / 1000).toFixed(3),\n ...(skipped.length > skippedBefore ? { skipped: true } : {}),\n ...(page.url() !== urlBefore ? { navigated: true } : {}),\n ...(urlAfter ? { url: urlAfter } : {}),\n ...(text !== null ? { text } : {}),\n ...(stepRect\n ? {\n rect: {\n x: +stepRect.x.toFixed(1),\n y: +stepRect.y.toFixed(1),\n w: +stepRect.w.toFixed(1),\n h: +stepRect.h.toFixed(1),\n },\n }\n : {}),\n })\n paces.push({\n step: stepIdx,\n do: step.do,\n askedMs: askedMs(step as Parameters<typeof askedMs>[0]),\n gestureMs,\n wallMs: now() - stepStart,\n })\n // After the pace is taken: the scan's few ms are not the step's.\n await scanExposures(stepIdx)\n }\n if (!capped) await sleep(TRAILING_HOLD_MS) // trailing hold\n if (capped || capReached(now(), maxSeconds)) {\n capped = true\n log(` ${cappedLine(maxSeconds)}`)\n }\n\n const durationMs = capped ? Math.min(now(), maxSeconds * 1000) : now()\n await cdp.send('Page.stopScreencast').catch(() => {})\n await sleep(200)\n const pageTitle = await page.title().catch(() => '')\n await context.close()\n // Every frame the screencast delivered has reached the sink.\n await sinkChain\n\n const meta: RecordingMeta = {\n dpr: 1,\n zoom: 1,\n t0,\n durationMs,\n width: vw,\n height: vh,\n fps: 30,\n hasAudio: false,\n captureWidth: first.dims?.w ?? vw,\n captureHeight: first.dims?.h ?? vh,\n captureSurface: 'tab',\n // The take keeps the address, never its query or hash, which is where\n // a token or a magic link would ride.\n pageUrl: publicUrl(url) || url,\n pageTitle,\n platform: opts.platform ?? 'linux',\n producer: 'cli',\n steps: stepSpans,\n ...(wall\n ? { wall: { kind: wall.kind, asked: wall.asked, landed: wall.landed } }\n : {}),\n ...(exposureLog.exposures().length\n ? { exposures: exposureLog.exposures() }\n : {}),\n ...(masks.length ? { masks: exposureLog.masks(masks) } : {}),\n }\n\n // Smoothness telemetry: screencast emits only on visual change, so frame\n // gaps = frozen pixels. ≥400ms reads as dead time in a product video.\n const freezes: FreezeSpan[] = []\n for (let i = 1; i < frames.length; i++) {\n const gap = frames[i].tMs - frames[i - 1].tMs\n if (gap >= 400) {\n freezes.push({\n from: +(frames[i - 1].tMs / 1000).toFixed(2),\n to: +(frames[i].tMs / 1000).toFixed(2),\n ms: gap,\n })\n }\n }\n const frozenMs = freezes.reduce((sum, f) => sum + f.ms, 0)\n const freezePct =\n durationMs > 0 ? Math.round((frozenMs / durationMs) * 100) : 0\n // The freeze share is a FACT (a workspace tour is mostly still and fine);\n // the warning is dead time: a hold nobody is reading, named per step.\n const dead = deadTime(stepSpans, frames, events, durationMs)\n if (deadWarns(dead)) log(` WARNING: ${deadLine(dead)}`)\n\n const pace = paceReport(paces)\n if (!dry) log(` ${paceLine(pace)}`)\n return {\n events,\n frames,\n meta,\n pace,\n skipped,\n navTimeout,\n wall,\n exposures: exposureLog.exposures(),\n masks: exposureLog.masks(masks),\n freezes,\n freezePct,\n dead,\n capped,\n actions: { ...actions, url },\n }\n}\n","import type { MaskRule } from './exposure'\nimport type { SetupStep } from './setup'\nimport { urlSchemeProblem, validateSetup } from './setup'\n\n/**\n * The action script — the declarative recipe an agent (or human) writes to\n * drive a take. Small on purpose: selectors + a handful of verbs. The recorder\n * executes it with humanized cursor motion and synthesizes the CursorTrack\n * from its own dispatches.\n */\nexport interface ActionsFile {\n /** Page to record. `--url` overrides. */\n url?: string\n /** Recording viewport in CSS px (default 1280x720). */\n viewport?: { width: number; height: number }\n /**\n * Hidden BEFORE the first frame is captured and kept hidden across\n * navigations: what a signed-in account shows that must not ship. `blur`\n * (default) blurs the element; `text` swaps its words for `text`, which is\n * for IDENTIFIERS (an email, a name, an account id), never for product\n * copy or numbers: the video must stay true to the product.\n */\n mask?: MaskRule[]\n /**\n * Run BEFORE the camera rolls, after the first navigation: a sign-in form,\n * a cookie banner, an onboarding tour. Plain actions with no cursor, no\n * frames, no pace and nothing in `meta.steps`; then the recorder opens\n * `url` again and the take begins where the setup left it. A `type`\n * step's text may be `{ env: 'NAME' }`, read at run time and never logged\n * or stored.\n */\n setup?: SetupStep[]\n steps: ActionStep[]\n}\n\nexport type ActionStep = (\n | { do: 'wait'; ms: number }\n | { do: 'hover'; selector: string; ms?: number }\n /** `ms` is the settle after the press (default 150). */\n | { do: 'click'; selector: string; ms?: number }\n /**\n * Type into `selector`. The recorder clicks the field first, which is what\n * opens the typing zoom on it; `focus: false` types into the field as it is\n * already focused, for a keystroke that follows earlier typing (a submitting\n * Enter) rather than starting it — a second click there rings a click effect\n * on empty space beside the text.\n */\n | {\n do: 'type'\n selector: string\n text: string\n delayMs?: number\n focus?: boolean\n /**\n * Select the field's value before typing, so what is typed REPLACES\n * it (a form that opens filled in, a search box with the last query).\n */\n replace?: boolean\n /**\n * Where the caret goes after the focusing click, before the first\n * character: `end` or `start` of the field (a code editor line is\n * typed at its end; a click lands the caret where the pointer hit).\n */\n at?: 'end' | 'start'\n /** the settle after the last character (default 150) */\n ms?: number\n }\n /**\n * One named key, recorded as a typing ping where the pointer is (or on\n * `selector` when given, with no click): Escape closes what a click\n * opened, Enter submits what was typed, Tab moves on, an arrow nudges.\n * Never a character: words are typed with `type`.\n */\n | { do: 'press'; key: PressKey; selector?: string; ms?: number }\n /** `ms` is the settle after the scroll lands (default 200). */\n | { do: 'scroll'; dy: number; ms?: number }\n | { do: 'move'; x: number; y: number }\n /**\n * Press-move-release — real edits (drag an element on the stage canvas,\n * slide a range input, move a timeline clip). Start = the selector's center\n * when given, else (x, y); end = (tx, ty); eased over ms (default 700).\n */\n | {\n do: 'drag'\n selector?: string\n x?: number\n y?: number\n tx: number\n ty: number\n ms?: number\n }\n) & {\n /**\n * Optional stable identity: anchors in doc.json name a step by this\n * id (else by index), so a step can move or gain neighbours across script\n * edits without breaking the cut anchored to it. Unique when present.\n */\n id?: string\n /**\n * A beat's caption, two to eight words: `vos deliver` lands it as a\n * lower-third at this step's moment on the cuts that take words, and\n * `vos actions script` leads the beat with it.\n */\n caption?: string\n /**\n * A selector whose words the recorder keeps once the step has settled\n * (`meta.steps[].text`: trimmed, whitespace collapsed, at most 2 KB), so\n * a layer quotes the take instead of a replay: the URL a share button\n * minted, the code a dialog printed, the status a request answered. On\n * a click it reads after the click's settle, so what the click opened is\n * what is read. Only what the flow names, never a secret it did not.\n */\n read?: string\n}\n\nconst VERBS = new Set([\n 'wait',\n 'hover',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'move',\n 'drag',\n])\n\n/** The keys a `press` step may name: navigation and control, never a character. */\nexport const PRESS_KEYS = [\n 'Escape',\n 'Enter',\n 'Tab',\n 'Backspace',\n 'Delete',\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n 'Space',\n] as const\nexport type PressKey = (typeof PRESS_KEYS)[number]\n\n/** Structural validation with actionable messages. Returns [] when valid. */\nexport function validateActions(value: unknown): string[] {\n const errors: string[] = []\n if (typeof value !== 'object' || value === null)\n return ['actions file must be a JSON object']\n const obj = value as Record<string, unknown>\n if (obj.url !== undefined) {\n if (typeof obj.url !== 'string') errors.push('url must be a string')\n else {\n const problem = urlSchemeProblem(obj.url)\n if (problem) errors.push(`url ${problem}`)\n }\n }\n if (obj.viewport !== undefined) {\n const v: unknown = obj.viewport\n if (typeof v !== 'object' || v === null) {\n errors.push('viewport must be { width, height }')\n } else {\n const vp = v as Record<string, unknown>\n if (typeof vp.width !== 'number' || typeof vp.height !== 'number') {\n errors.push('viewport must be { width, height }')\n }\n }\n }\n if (obj.setup !== undefined) errors.push(...validateSetup(obj.setup))\n if (obj.mask !== undefined) {\n if (!Array.isArray(obj.mask)) {\n errors.push('mask must be an array of { selector, as?, text? }')\n } else {\n obj.mask.forEach((raw, i) => {\n const at = `mask[${i}]`\n const m = (raw ?? {}) as Record<string, unknown>\n if (typeof m.selector !== 'string' || !m.selector.trim())\n errors.push(`${at}: needs a selector`)\n if (m.as !== undefined && m.as !== 'blur' && m.as !== 'text')\n errors.push(`${at}: as must be \"blur\" or \"text\"`)\n if (m.as === 'text' && (typeof m.text !== 'string' || !m.text))\n errors.push(`${at}: as \"text\" needs the text to show instead`)\n if (m.as !== 'text' && m.text !== undefined)\n errors.push(`${at}: text is only read with as \"text\"`)\n })\n }\n }\n if (!Array.isArray(obj.steps) || obj.steps.length === 0) {\n errors.push('steps must be a non-empty array')\n return errors\n }\n const seenIds = new Set<string>()\n obj.steps.forEach((raw, i) => {\n const at = `steps[${i}]`\n if (typeof raw !== 'object' || raw === null) {\n errors.push(`${at}: must be an object`)\n return\n }\n const s = raw as Record<string, unknown>\n if (s.read !== undefined && (typeof s.read !== 'string' || !s.read.trim()))\n errors.push(`${at}: read must be a selector`)\n if (typeof s.do !== 'string' || !VERBS.has(s.do)) {\n errors.push(`${at}: \"do\" must be one of ${[...VERBS].join(', ')}`)\n return\n }\n if (s.id !== undefined) {\n if (typeof s.id !== 'string' || !s.id.trim()) {\n errors.push(`${at}: id must be a non-empty string`)\n } else if (seenIds.has(s.id)) {\n errors.push(\n `${at}: duplicate id \"${s.id}\" — an anchor could not tell the two steps apart`,\n )\n } else {\n seenIds.add(s.id)\n }\n }\n const needSelector = s.do === 'hover' || s.do === 'click' || s.do === 'type'\n if (needSelector && typeof s.selector !== 'string')\n errors.push(`${at}: ${s.do} needs a selector`)\n if (s.do === 'wait' && typeof s.ms !== 'number')\n errors.push(`${at}: wait needs ms`)\n if (\n s.ms !== undefined &&\n (typeof s.ms !== 'number' || !Number.isFinite(s.ms) || s.ms < 0)\n )\n errors.push(`${at}: ms must be a number of milliseconds ≥ 0`)\n if (s.do === 'type' && typeof s.text !== 'string')\n errors.push(`${at}: type needs text`)\n if (\n s.do === 'type' &&\n s.focus !== undefined &&\n typeof s.focus !== 'boolean'\n )\n errors.push(`${at}: type focus must be true or false`)\n if (\n s.do === 'type' &&\n s.replace !== undefined &&\n typeof s.replace !== 'boolean'\n )\n errors.push(`${at}: type replace must be true or false`)\n if (\n s.do === 'type' &&\n s.at !== undefined &&\n s.at !== 'end' &&\n s.at !== 'start'\n )\n errors.push(`${at}: type at must be \"end\" or \"start\"`)\n if (s.do === 'press') {\n if (\n typeof s.key !== 'string' ||\n !(PRESS_KEYS as readonly string[]).includes(s.key)\n )\n errors.push(\n `${at}: press needs a key, one of ${PRESS_KEYS.join(', ')}; words are typed with type`,\n )\n if (s.selector !== undefined && typeof s.selector !== 'string')\n errors.push(`${at}: press selector must be a string`)\n }\n if (s.do === 'scroll' && typeof s.dy !== 'number')\n errors.push(`${at}: scroll needs dy`)\n if (\n s.do === 'move' &&\n (typeof s.x !== 'number' || typeof s.y !== 'number')\n ) {\n errors.push(`${at}: move needs x and y (CSS px)`)\n }\n if (s.do === 'drag') {\n if (typeof s.tx !== 'number' || typeof s.ty !== 'number') {\n errors.push(`${at}: drag needs tx and ty (CSS px)`)\n }\n const hasStart =\n typeof s.selector === 'string' ||\n (typeof s.x === 'number' && typeof s.y === 'number')\n if (!hasStart)\n errors.push(\n `${at}: drag needs a selector OR x and y as the start point`,\n )\n }\n })\n return errors\n}\n","/**\n * Frames → CFR WebM, as a PAGE. The VFR screencast JPEGs are drawn\n * hold-last-frame onto a canvas at a fixed 30fps and encoded with\n * mediabunny (WebCodecs) inside a headless page — no ffmpeg dependency.\n * The CLI serves the take directory to it and reads the bytes back through\n * its own `/save`; the fleet serves the frames through the ingest route and\n * the page PUTs the recording to the same route. One page, two hosts: the\n * URLs and the way out are the host's, the encode is not.\n */\n\nconst MEDIABUNNY_URL = 'https://esm.sh/mediabunny@1.55.7?target=es2022'\n\nexport interface EncodePageOptions {\n /** Where `frames.json` (the index `[{file, tMs}]`) is fetched from. */\n framesIndexUrl: string\n /** Where `meta.json` is fetched from. */\n metaUrl: string\n /** `<framesBaseUrl><file>` is each JPEG. */\n framesBaseUrl: string\n /** The way out: a POST to the CLI's take server, or a PUT to the ingest route. */\n save: { method: 'POST' | 'PUT'; url: string }\n /** Optional `?rt=`-style query the frame fetches must carry (the fleet's token). */\n frameQuery?: string\n /** Where mediabunny loads from (a host's mirror); esm.sh by default. */\n mediabunnyUrl?: string\n}\n\nexport function buildEncodePage(o: EncodePageOptions): string {\n const q = o.frameQuery ? `?${o.frameQuery}` : ''\n const mediabunnyUrl = o.mediabunnyUrl ?? MEDIABUNNY_URL\n return `<!doctype html><html><head><meta charset=\"utf-8\"></head><body>\n<script type=\"module\">\ntry {\n const MB = await import(${JSON.stringify(mediabunnyUrl)})\n const frames = await (await fetch(${JSON.stringify(o.framesIndexUrl)})).json()\n const meta = await (await fetch(${JSON.stringify(o.metaUrl)})).json()\n const W = meta.captureWidth ?? meta.width, H = meta.captureHeight ?? meta.height\n const FPS = 30\n const durSec = meta.durationMs / 1000\n const cv = document.createElement('canvas')\n cv.width = W; cv.height = H\n const c2 = cv.getContext('2d')\n const output = new MB.Output({ format: new MB.WebMOutputFormat(), target: new MB.BufferTarget() })\n const src = new MB.CanvasSource(cv, { codec: 'vp9', bitrate: 8_000_000 })\n output.addVideoTrack(src, { frameRate: FPS })\n await output.start()\n let fi = -1\n const total = Math.ceil(durSec * FPS)\n for (let i = 0; i < total; i++) {\n const t = i / FPS\n let next = fi\n while (next + 1 < frames.length && frames[next + 1].tMs <= t * 1000) next++\n if (next < 0) next = 0\n if (next !== fi) {\n fi = next\n const blob = await (await fetch(${JSON.stringify(o.framesBaseUrl)} + frames[fi].file + ${JSON.stringify(q)})).blob()\n const bmp = await createImageBitmap(blob)\n c2.drawImage(bmp, 0, 0, W, H)\n bmp.close()\n }\n await src.add(t, 1 / FPS)\n window.__progress = i / total\n }\n await output.finalize()\n const buf = output.target.buffer\n const res = await fetch(${JSON.stringify(o.save.url)}, { method: ${JSON.stringify(o.save.method)}, headers: { 'content-type': 'video/webm' }, body: buf })\n if (!res.ok) throw new Error('save failed: ' + res.status)\n // Two hosts, two completion words: the CLI's take server polls __done,\n // the fleet's page runner polls __renderComplete.\n window.__done = { ok: true, bytes: buf.byteLength }\n window.__renderComplete = { success: true, size: buf.byteLength, uploaded: true }\n} catch (e) {\n window.__error = String(e && e.stack || e)\n window.__renderComplete = { success: false, error: String(e && e.message || e) }\n}\n</script></body></html>`\n}\n","/**\n * The FRESH plan of a take: what `vos record` writes as doc.json the moment\n * a recording lands, and what a hosted take gets on the fleet. One\n * composition, so a take recorded anywhere opens on the same camera: the\n * artifact becomes a document (`projectFromArtifact`), the zooms are\n * planned from the cursor track, the speed spans from the same track. The\n * backdrop is a host's PICK (vosso's house set, the CLI's `--background`),\n * handed in as a wire row; studio-core carries only the mechanism.\n *\n * The CLI's `vos plan` is the fuller verb (reuse, style, motion, a still);\n * this is its fresh branch, byte-identical to it.\n */\nimport {\n DEFAULT_FRAME_STYLE,\n planAutoSpeed,\n planAutoZoom,\n projectFromArtifact,\n withBackdrop,\n} from '@vosjs/studio-core'\nimport type {\n Backdrop,\n ProjectDoc,\n RecordingArtifact,\n} from '@vosjs/studio-core'\n\nexport interface FreshPlanOptions {\n /** The backdrop the document opens on; absent keeps the bare frame. */\n backdrop?: Backdrop | null\n /** A digest's activity bins, when one exists (the speed planner's witness). */\n activity?: readonly number[] | null\n}\n\nexport function planFreshTake(\n artifact: RecordingArtifact,\n recordingName: string,\n opts: FreshPlanOptions = {},\n): ProjectDoc {\n const ingest = opts.backdrop\n ? { frame: withBackdrop(DEFAULT_FRAME_STYLE, opts.backdrop) }\n : {}\n const doc = projectFromArtifact(artifact, recordingName, ingest).doc\n doc.zoom = planAutoZoom(doc.source.cursor, {\n width: doc.source.meta.width,\n height: doc.source.meta.height,\n duration: doc.source.meta.durationMs / 1000,\n style: doc.zoomStyle,\n params: doc.zoomParams,\n })\n doc.speed = planAutoSpeed(doc.source.cursor, {\n durationMs: doc.source.meta.durationMs,\n params: doc.speedParams,\n activity: opts.activity,\n })\n return doc\n}\n"],"mappings":"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","names":["askedMs","VERBS"]}
1
+ {"version":3,"sources":["../../src/record/driver.ts","../../src/record/cap.ts","../../src/record/pace.ts","../../src/record/wall.ts","../../src/record/exposure.ts","../../src/record/setup.ts","../../src/record/takeClock.ts","../../src/record/pageErrors.ts","../../src/record/actions.ts","../../src/record/waits.ts","../../src/record/outputs.ts","../../src/record/recorder.ts","../../src/record/encodePage.ts","../../src/record/plan.ts"],"sourcesContent":["/**\n * The recorder's driver: what it needs from a browser, as a STRUCTURAL\n * contract. Playwright's own `Browser`/`BrowserContext`/`Page` satisfy it\n * unchanged, and so does `@cloudflare/playwright`'s (the same client\n * surface over Browser Rendering), so the CLI hands in a launched Node\n * browser and the fleet hands in a connected one, and the recorder never\n * imports either package. Only the members the recorder calls are named\n * here; a driver that offers more is fine, one that offers less fails to\n * type.\n *\n * Frames leave through a `FrameSink`, never through a filesystem: the CLI's\n * sink writes a take directory, the fleet's puts each JPEG to R2.\n */\n\nexport interface RecorderRect {\n x: number\n y: number\n width: number\n height: number\n}\n\nexport interface RecorderLocator {\n waitFor(opts: {\n state: 'visible' | 'attached'\n timeout: number\n }): Promise<unknown>\n scrollIntoViewIfNeeded(): Promise<unknown>\n boundingBox(): Promise<RecorderRect | null>\n click(): Promise<unknown>\n fill(value: string): Promise<unknown>\n /** what an `expect` and an `await` read, and the disabled-click report */\n isVisible(): Promise<boolean>\n isEnabled(opts?: { timeout?: number }): Promise<boolean>\n /** a `download` src reads the media element's source through the locator engine */\n evaluate<R>(fn: (el: RecorderMediaElement) => R): Promise<R>\n}\n\n/** What a `download` src reads off the element its selector matched. */\nexport interface RecorderMediaElement {\n currentSrc?: string\n src?: string\n getAttribute(name: string): string | null\n}\n\n/** A browser download, as Playwright's `Download` answers it. */\nexport interface RecorderDownload {\n suggestedFilename(): string\n // A Node Readable on Playwright; any async stream of byte chunks will do.\n createReadStream(): Promise<AsyncIterable<unknown> | null>\n}\n\n/** The page's own request context (its cookies), as Playwright's `APIResponse` answers. */\nexport interface RecorderApiResponse {\n ok(): boolean\n status(): number\n headers(): Record<string, string>\n body(): Promise<Uint8Array>\n}\n\nexport interface RecorderLocatorRoot {\n first(): RecorderLocator\n}\n\nexport interface RecorderResponse {\n status(): number\n}\n\nexport interface RecorderConsoleMessage {\n type(): string\n text(): string\n}\n\nexport interface RecorderPage {\n goto(\n url: string,\n opts: { waitUntil: 'networkidle'; timeout: number },\n ): Promise<RecorderResponse | null>\n url(): string\n title(): Promise<string>\n /** An `await` with `reload: true`; absent, the recorder opens the page's URL again. */\n reload?(opts: {\n waitUntil: 'networkidle'\n timeout: number\n }): Promise<RecorderResponse | null>\n /** A `download` step's click; absent, the recorder says the browser reports none. */\n waitForEvent?(\n event: 'download',\n opts: { timeout: number },\n ): Promise<RecorderDownload>\n /** A `download` step's `src` fetch, with the page's cookies; absent, it fetches in the page. */\n request?: {\n get(url: string, opts?: { timeout?: number }): Promise<RecorderApiResponse>\n }\n // Playwright's evaluate takes a function or an expression string; the\n // recorder hands it strings (the probes) and small functions.\n evaluate<T>(pageFunction: string | (() => T)): Promise<T>\n on(event: 'console', cb: (m: RecorderConsoleMessage) => void): unknown\n locator(selector: string): RecorderLocatorRoot\n mouse: {\n move(x: number, y: number): Promise<void>\n down(): Promise<void>\n up(): Promise<void>\n wheel(dx: number, dy: number): Promise<void>\n }\n keyboard: {\n type(text: string): Promise<void>\n press(key: string): Promise<void>\n }\n}\n\nexport interface RecorderCdp {\n on(\n event: 'Page.screencastFrame',\n cb: (ev: {\n data: string\n sessionId: number\n metadata: { timestamp?: number }\n }) => void,\n ): unknown\n send(method: string, params?: Record<string, unknown>): Promise<unknown>\n}\n\n/** One intercepted request, as Playwright's `Route` answers it. */\nexport interface RecorderRoute {\n request(): { url(): string; headers(): Record<string, string> }\n continue(opts?: { headers?: Record<string, string> }): Promise<unknown>\n}\n\nexport interface RecorderContext {\n newPage(): Promise<RecorderPage>\n addInitScript(script: string): Promise<unknown>\n setExtraHTTPHeaders(headers: Record<string, string>): Promise<unknown>\n /**\n * Request interception, when the driver has it: how a job's headers are\n * sent to the recorded origin alone. A driver without it gets them on\n * every request through `setExtraHTTPHeaders`, and the recorder says so.\n */\n route?(\n pattern: string,\n handler: (route: RecorderRoute) => Promise<unknown> | unknown,\n ): Promise<unknown>\n // The page handed back is the one `newPage()` answered; typed loosely so\n // Playwright's `Page | Frame` parameter satisfies the contract.\n newCDPSession(page: unknown): Promise<RecorderCdp>\n close(): Promise<void>\n}\n\nexport interface RecorderBrowser {\n newContext(opts: {\n viewport: { width: number; height: number }\n deviceScaleFactor: number\n storageState?: string\n extraHTTPHeaders?: Record<string, string>\n }): Promise<RecorderContext>\n}\n\n/**\n * Where the screencast's frames go. `frame` is called in order with the\n * JPEG bytes; the recorder keeps the index (`file`, `tMs`) itself. The CLI\n * writes `frames/<file>`; the fleet puts to R2. A sink may be async and\n * slow: the recorder never awaits it on the screencast's own thread, so a\n * slow store costs no frames, only memory until it catches up.\n */\nexport interface FrameSink {\n frame(file: string, bytes: Uint8Array): Promise<void> | void\n}\n\n/**\n * Where a `download` step's file goes: the CLI writes `outputs/<name>` in\n * the take directory. A host that hands in none cannot keep a download,\n * and the recorder refuses such a script before capturing anything.\n */\nexport interface OutputSink {\n save(\n name: string,\n bytes: Uint8Array,\n contentType?: string,\n ): Promise<void> | void\n}\n\n/** The clock and the pauses, injectable so a rehearsal runs fast. */\nexport interface RecorderClock {\n now(): number\n sleep(ms: number): Promise<void>\n}\n\nexport const realSleep = (ms: number): Promise<void> =>\n new Promise<void>((r) => setTimeout(r, ms))\n","/**\n * The recording cap as the recorder applies it, pure. WHAT the cap is\n * (the hosted plan's number, read from `GET /api/limits`) is a vos.so fact\n * and stays in the CLI's platform client; the recorder only knows a number\n * of seconds and stops there.\n */\n\n/** True once the take has reached the cap — the recorder stops driving steps. */\nexport function capReached(elapsedMs: number, capSeconds: number): boolean {\n return elapsedMs >= capSeconds * 1000\n}\n\n/** A wait step never sleeps past the cap. */\nexport function clampWait(\n waitMs: number,\n elapsedMs: number,\n capSeconds: number,\n): number {\n return Math.max(0, Math.min(waitMs, capSeconds * 1000 - elapsedMs))\n}\n\n/** `30 min`, `1 h 30 min`, `45 s` — the duration cap in words. */\nexport function formatDurationCap(seconds: number): string {\n if (seconds < 60) return `${seconds} s`\n const m = Math.round(seconds / 60)\n if (m < 60) return `${m} min`\n const h = Math.floor(m / 60)\n const rest = m % 60\n return rest ? `${h} h ${rest} min` : `${h} h`\n}\n\n/** The one line printed when the cap stopped the take. */\nexport function cappedLine(capSeconds: number): string {\n return `stopped at ${formatDurationCap(capSeconds)} (--max-duration ${capSeconds}); the remaining steps did not run`\n}\n","/**\n * The recorder's pace — the pure parts.\n *\n * A take of a scripted flow should run as long as the script asks, plus the\n * gestures a person makes between the asks (the pointer's travel, the press,\n * the settle after it) and no more. Measured before this module (§4.5 of\n * the utility-clip retrospective), hovers ran 2× their ask, drags 4.8× and\n * a 25 s script recorded 42 s, for two reasons the numbers here answer:\n *\n * - The motion loops counted STEPS (one per 16 ms of the asked duration)\n * and awaited a `mouse.move` round trip per step, so a page that\n * re-renders per move (a slider) stretched every gesture by the round\n * trip. A gesture is now driven by the CLOCK: its position is a function\n * of the elapsed time, and it ends when the asked duration has elapsed,\n * however many samples the page allowed.\n * - The settles after a gesture were fixed sleeps (500 ms after a click,\n * 250 after every selector lookup). A settle is DATA: `ms` on the step\n * overrides a small default, and the script's own `wait` steps carry\n * the intended pauses.\n */\n\n/** Pointer travel: ms per CSS px, floor and ceiling — a person's hand. */\nexport const POINTER_MS_PER_PX = 0.7\nexport const POINTER_MIN_MS = 250\nexport const POINTER_MAX_MS = 800\n/** The sample cadence a motion loop aims for. */\nexport const MOTION_TICK_MS = 16\n\n/** The settle after a gesture when the step names none, by verb. */\nexport const SETTLE_MS = {\n click: 150,\n type: 150,\n press: 150,\n scroll: 200,\n drag: 80,\n} as const\n\n/** The press: the pause before the button goes down, and the hold. */\nexport const PRESS_LEAD_MS = 80\nexport const PRESS_HOLD_MS = 70\n/** The pause between a selector lookup that scrolled the page and the move. */\nexport const SCROLL_SETTLE_MS = 120\n\n/**\n * A scroll travels by the clock too, at a wheel's pace: 0.9 ms per px,\n * floored so a short flick still reads as motion and capped so a long page\n * does not crawl. Each tick moves the page's scroll container in the page\n * itself (recorder.ts says why not a wheel event, an animation frame or a\n * page timer).\n */\nexport const SCROLL_MS_PER_PX = 0.9\nexport const SCROLL_MIN_MS = 240\nexport const SCROLL_MAX_MS = 1000\n/** The hold after the last step, so the take does not cut on a press. */\nexport const TRAILING_HOLD_MS = 400\n\n/** How long the pointer takes to travel `dist` CSS px. */\nexport function scrollTravelMs(px: number): number {\n return Math.min(\n SCROLL_MAX_MS,\n Math.max(SCROLL_MIN_MS, Math.round(Math.abs(px) * SCROLL_MS_PER_PX)),\n )\n}\n\nexport function pointerTravelMs(dist: number): number {\n return Math.min(\n POINTER_MAX_MS,\n Math.max(POINTER_MIN_MS, Math.round(dist * POINTER_MS_PER_PX)),\n )\n}\n\n/**\n * A click's `ms` is READING time, held from the page's last visual change,\n * and the recorder pays the settle itself: the same `ms` was read on one\n * run and dead on the next because the hold started at the press and the\n * page's settle varied run to run (0.3 s to 0.7 s on the same step).\n *\n * The settle is watched on the screencast, which emits only on change:\n * after the press, a change that arrives within RESPONSE_MS says the page\n * is answering, and it has settled once QUIET_MS pass with no new frame.\n * No change within RESPONSE_MS means the page did not change (a click that\n * only moves state) and the settle is over. SETTLE_CAP_MS bounds a page\n * that never stops changing (a playing preview), which is a page nothing\n * is dead on, so the hold simply starts.\n */\nexport const RESPONSE_MS = 400\nexport const QUIET_MS = 250\nexport const SETTLE_CAP_MS = 1200\n\n/**\n * Is the page settled? Pure: the recorder feeds it what it knows at each\n * tick since the press.\n */\nexport function settleVerdict(\n t: {\n /** ms since the press. */\n sincePress: number\n /** ms since the last screencast frame, or null when none arrived since the press. */\n sinceChange: number | null\n },\n c = { response: RESPONSE_MS, quiet: QUIET_MS, cap: SETTLE_CAP_MS },\n): 'wait' | 'settled' {\n if (t.sincePress >= c.cap) return 'settled'\n if (t.sinceChange === null)\n return t.sincePress >= c.response ? 'settled' : 'wait'\n return t.sinceChange >= c.quiet ? 'settled' : 'wait'\n}\n\n/**\n * What is left of a hold once the settle is detected: the hold is measured\n * from the last change, so the quiet already spent counts toward it.\n */\nexport function holdLeftMs(holdMs: number, sinceChange: number | null): number {\n return Math.max(0, holdMs - (sinceChange ?? 0))\n}\n\n/** The settle after a step: its own `ms` when it names one, else the verb's. */\nexport function settleMs(step: { do: string; ms?: number }): number {\n if (typeof step.ms === 'number' && step.ms >= 0) return step.ms\n const d = step.do as keyof typeof SETTLE_MS\n return SETTLE_MS[d] ?? 0\n}\n\nexport const easeInOutCubic = (u: number): number =>\n u < 0.5 ? 4 * u * u * u : 1 - Math.pow(-2 * u + 2, 3) / 2\n\n/**\n * Drive a motion by the clock: `at(u)` is called with the eased progress\n * for each sample, and the loop ends when `dur` ms have elapsed, with the\n * last call at u = 1 exactly. Between samples it sleeps to the next tick\n * only when the sample came back early; a slow sample (a page busy\n * re-rendering) is followed at once, so the gesture keeps its length and\n * loses samples, never the other way round.\n */\nexport async function clockMotion(\n dur: number,\n at: (u: number) => Promise<void>,\n clock: { now: () => number; sleep: (ms: number) => Promise<void> },\n): Promise<number> {\n const start = clock.now()\n let samples = 0\n for (;;) {\n const tick = clock.now()\n const elapsed = tick - start\n if (elapsed >= dur) break\n await at(easeInOutCubic(Math.min(1, elapsed / dur)))\n samples++\n const next =\n start + Math.ceil((clock.now() - start) / MOTION_TICK_MS) * MOTION_TICK_MS\n const wait = Math.min(next, start + dur) - clock.now()\n if (wait > 0) await clock.sleep(wait)\n // A sample that cost no clock time still yields a tick. On a Worker the\n // clock moves only across I/O, so a sample that awaited nothing (a\n // scroll tick that owed no pixels yet) left `now` where it was, the wait\n // came out at zero, and the loop spun on a frozen clock for good: the\n // fleet's first three clock-driven scrolls did exactly that.\n else if (clock.now() === tick) await clock.sleep(MOTION_TICK_MS)\n }\n await at(1)\n return samples + 1\n}\n\n/**\n * Typing paced by the clock: the i-th character is due at `start + i·delay`;\n * after each keystroke the loop sleeps to the next due time only if the\n * keystroke came back early. A slow field (an editor re-rendering per key)\n * types as fast as it can and says so in the pace report.\n */\nexport async function clockTyping(\n chars: readonly string[],\n delay: number,\n type: (ch: string, index: number) => Promise<void>,\n clock: { now: () => number; sleep: (ms: number) => Promise<void> },\n): Promise<void> {\n const start = clock.now()\n for (let i = 0; i < chars.length; i++) {\n await type(chars[i], i)\n const due = start + (i + 1) * delay\n const wait = due - clock.now()\n if (wait > 0 && i < chars.length - 1) await clock.sleep(wait)\n // The same yield as clockMotion's: a keystroke that cost no clock time\n // must not let the loop outrun a clock that only moves across I/O.\n else if (i < chars.length - 1 && clock.now() === start + i * delay)\n await clock.sleep(1)\n }\n}\n\n/** One step's pace: what the script asked for it and what it took. */\nexport interface StepPace {\n step: number\n do: string\n /** The script's own ask: a wait's ms, a hover's dwell, a drag's ms, typing's chars × delay, a click's read after the settle; 0 for a scroll. */\n askedMs: number\n /** The gesture the recorder adds by design: pointer travel, the press, the settle. */\n gestureMs: number\n wallMs: number\n}\n\nexport interface PaceReport {\n askedMs: number\n gestureMs: number\n wallMs: number\n /** Wall time neither asked nor a gesture: what the page and the round trips cost. */\n overheadMs: number\n overheadPct: number\n /** The steps whose wall ran past their ask plus gesture by more than a third. */\n slow: { step: number; do: string; askedMs: number; wallMs: number }[]\n}\n\n/** What a script asks of a step, in ms: the part of its wall time that is the author's. */\nexport function askedMs(step: {\n do: string\n ms?: number\n text?: string\n delayMs?: number\n}): number {\n switch (step.do) {\n case 'wait':\n return step.ms ?? 0\n // A click's ms is the read after the page settled: the author's.\n case 'click':\n return step.ms ?? SETTLE_MS.click\n case 'hover':\n return step.ms ?? 700\n case 'drag':\n return step.ms ?? 700\n case 'type':\n return (step.text?.length ?? 0) * (step.delayMs ?? 40)\n case 'press':\n return step.ms ?? SETTLE_MS.press\n default:\n return 0\n }\n}\n\nexport function paceReport(steps: readonly StepPace[]): PaceReport {\n const askedMs = steps.reduce((a, s) => a + s.askedMs, 0)\n const gestureMs = steps.reduce((a, s) => a + s.gestureMs, 0)\n const wallMs = steps.reduce((a, s) => a + s.wallMs, 0)\n const overheadMs = Math.max(0, wallMs - askedMs - gestureMs)\n const slow = steps\n .filter((s) => s.wallMs > (s.askedMs + s.gestureMs) * 1.34 + 60)\n .map((s) => ({\n step: s.step,\n do: s.do,\n askedMs: s.askedMs,\n wallMs: s.wallMs,\n }))\n return {\n askedMs,\n gestureMs,\n wallMs,\n overheadMs,\n overheadPct: wallMs > 0 ? Math.round((overheadMs / wallMs) * 100) : 0,\n slow,\n }\n}\n\n/** The pace in one line for the log. */\nexport function paceLine(r: PaceReport): string {\n const s = (ms: number) => `${(ms / 1000).toFixed(1)} s`\n const slow = r.slow.length\n ? `; slow: ${r.slow.map((x) => `#${x.step} ${x.do} ${s(x.wallMs)} for ${s(x.askedMs)} asked`).join(', ')}`\n : ''\n return `pace: the script asked ${s(r.askedMs)}, the gestures added ${s(r.gestureMs)}, the take ran ${s(r.wallMs)} (${r.overheadPct} % overhead${slow})`\n}\n\n/**\n * DEAD TIME, the smoothness fact that replaces the freeze share as the\n * warning. A still frame is not a defect: a page the viewer is reading is\n * content, and a workspace tour is mostly still. What is dead is a still\n * frame under a PARKED cursor past the beat it takes to read what changed:\n * after that the picture, the pointer and the camera all hold and nothing\n * is being said. So the derivation reads, per step, when the page settled\n * after the step's act, how long the settled frame was held, and whether\n * the cursor moved in that hold; a hold past the reading beat is dead.\n *\n * The beat is longer after a page changed (a navigation shows a whole new\n * page to take in) than after a control changed (one thing to see).\n */\nexport const READ_BEAT_MS = { page: 1000, control: 600 } as const\n/** A dead stretch this long is a warning on its own, whatever the share. */\nexport const DEAD_STRETCH_WARN_MS = 1500\n/** The share of the take past which dead time is a warning. */\nexport const DEAD_SHARE_WARN_PCT = 20\n\nexport interface DeadStep {\n step: number\n id?: string\n do: string\n /** ms from the step's act (its press, else its start) to the last frame change in the step. */\n settledMs: number\n /** ms the settled frame was held before the step ended. */\n heldMs: number\n /** the hold past the reading beat, while the cursor was parked; 0 when the hold was read or the pointer moved. */\n deadMs: number\n}\n\nexport interface DeadReport {\n ms: number\n pct: number\n /** the steps that carried any dead time, in order. */\n steps: DeadStep[]\n /** the longest single dead hold. */\n longestMs: number\n}\n\nexport function deadTime(\n steps: readonly {\n step: number\n id?: string\n do: string\n tStart: number\n tEnd: number\n navigated?: boolean\n }[],\n frames: readonly { tMs: number }[],\n events: readonly { t: number; type: string }[],\n durationMs: number,\n): DeadReport {\n const out: DeadStep[] = []\n let ms = 0\n let longestMs = 0\n for (const s of steps) {\n // A check, a wait for the page or a download is not a hold the author\n // asked for: its time is the page's, and \"cut the step's ms\" is no\n // advice for a step that has none.\n if (s.do === 'expect' || s.do === 'await' || s.do === 'download') continue\n const t0 = s.tStart * 1000\n const t1 = s.tEnd * 1000\n if (!(t1 > t0)) continue\n // The act: the step's first press, else its start (a wait, a move).\n const press = events.find(\n (e) => e.type === 'down' && e.t >= t0 && e.t <= t1,\n )\n const act = press ? press.t : t0\n // The last visual change inside the step, after the act.\n let last = act\n for (const f of frames) {\n if (f.tMs > act && f.tMs <= t1) last = f.tMs\n }\n const settledMs = Math.round(last - act)\n const heldMs = Math.round(t1 - last)\n // Parked: no pointer motion while the settled frame was held.\n const moved = events.some(\n (e) =>\n (e.type === 'move' || e.type === 'scroll') && e.t > last && e.t <= t1,\n )\n // The opening step shows a page the viewer has not seen: a page beat.\n const beat =\n s.navigated || s.step === 0 ? READ_BEAT_MS.page : READ_BEAT_MS.control\n const deadMs = moved ? 0 : Math.max(0, heldMs - beat)\n if (deadMs > 0) {\n out.push({\n step: s.step,\n ...(s.id ? { id: s.id } : {}),\n do: s.do,\n settledMs,\n heldMs,\n deadMs,\n })\n ms += deadMs\n longestMs = Math.max(longestMs, deadMs)\n }\n }\n return {\n ms,\n pct: durationMs > 0 ? Math.round((ms / durationMs) * 100) : 0,\n steps: out,\n longestMs,\n }\n}\n\n/** Whether a dead report earns a warning: the share, or one long hold. */\nexport function deadWarns(r: DeadReport): boolean {\n return r.pct >= DEAD_SHARE_WARN_PCT || r.longestMs >= DEAD_STRETCH_WARN_MS\n}\n\n/** The dead time in words, naming the steps and what to cut. */\nexport function deadLine(r: DeadReport): string {\n const s = (ms: number) => `${(ms / 1000).toFixed(1)} s`\n if (!r.steps.length) return 'dead time: none'\n const parts = r.steps.map(\n (d) =>\n `#${d.step}${d.id ? ` (${d.id})` : ''} ${d.do} held ${s(d.heldMs)} after it settled, ${s(d.deadMs)} past the beat`,\n )\n return `dead time: ${s(r.ms)} (${r.pct} %), a still frame under a parked cursor past the reading beat: ${parts.join('; ')}. Cut those steps' ms; a hold is what it takes to read what changed.`\n}\n","/**\n * The wall check: did the recorder land where it was asked, or in front of\n * a sign-in? A take of a product behind a login, recorded without a session,\n * used to succeed: the footage was the login page (or wherever the site\n * sends a stranger), and the only symptom was a skipped selector. This says\n * it in words, before a frame is captured and before a re-record clears the\n * footage it would have replaced.\n *\n * Pure: the recorder gathers the evidence, this decides. A heuristic is\n * acceptable because both failure directions are cheap: a false refusal\n * costs one flag (`--allow-wall`), a false pass costs what every such take\n * cost before.\n */\n\n/** What the recorder saw once the first navigation settled. */\nexport interface Arrival {\n askedUrl: string\n landedUrl: string\n /** HTTP status of the main document, when the navigation produced one. */\n status?: number\n /** `input[type=password]` fields that are visible on the page. */\n passwordFields: number\n /** A password field marked `autocomplete=\"new-password\"` (a settings or sign-up form). */\n newPasswordField: boolean\n /** A visible one-time-code field (`autocomplete=\"one-time-code\"`). */\n oneTimeCodeField: boolean\n}\n\nexport type WallKind =\n /** the asked URL answered 401 or 403 */\n | 'status'\n /** landed on an identity provider's host */\n | 'idp'\n /** landed on a sign-in form or a sign-in path */\n | 'signin'\n /** sent somewhere else, with no sign-in in sight (a site that shows strangers a public page) */\n | 'redirect'\n\nexport interface WallVerdict {\n kind: WallKind\n /**\n * `hard` is refused always; `soft` is refused under `--strict` and said as\n * a warning otherwise, because a redirect alone is not proof of a wall.\n */\n level: 'hard' | 'soft'\n /** origin + path, never the query or hash (they can carry tokens). */\n asked: string\n landed: string\n message: string\n}\n\n/** Hosts that only ever mean \"sign in\". Suffix match on the label boundary. */\nconst IDP_HOSTS = [\n 'accounts.google.com',\n 'login.microsoftonline.com',\n 'login.live.com',\n 'appleid.apple.com',\n 'auth0.com',\n 'okta.com',\n 'onelogin.com',\n 'clerk.accounts.dev',\n 'accounts.dev',\n 'b2clogin.com',\n 'amazoncognito.com',\n 'workos.com',\n 'stytch.com',\n]\n\n/** Path segments that name a sign-in surface. Whole segments, never substrings. */\nconst SIGNIN_SEGMENTS = new Set([\n 'login',\n 'log-in',\n 'signin',\n 'sign-in',\n 'sign_in',\n 'sso',\n 'auth',\n 'authenticate',\n 'authorize',\n 'oauth',\n 'oauth2',\n 'saml',\n])\n\nfunction parse(url: string): URL | null {\n try {\n return new URL(url)\n } catch {\n return null\n }\n}\n\nconst bareHost = (h: string) => h.replace(/^www\\./, '').toLowerCase()\nconst trimSlash = (p: string) => (p.length > 1 ? p.replace(/\\/+$/, '') : p)\nconst place = (u: URL) => `${u.origin}${trimSlash(u.pathname)}`\n\nexport function isIdpHost(host: string): boolean {\n const h = host.toLowerCase()\n if (h.startsWith('clerk.')) return true\n return IDP_HOSTS.some((idp) => h === idp || h.endsWith(`.${idp}`))\n}\n\nexport function isSignInPath(pathname: string): boolean {\n const segs = pathname.toLowerCase().split('/').filter(Boolean)\n return segs.some((s) => SIGNIN_SEGMENTS.has(s))\n}\n\n/**\n * Sent AWAY, as opposed to sent deeper. `/` → `/en`, `/docs` → `/docs/start`\n * and `/pricing` → `/en/pricing` are a site arranging itself; `/dashboard` →\n * `/gallery` is a site declining to show the page. `www.` and the apex are\n * one host.\n */\nexport function redirectedAway(asked: URL, landed: URL): boolean {\n if (bareHost(asked.hostname) !== bareHost(landed.hostname)) return true\n const a = trimSlash(asked.pathname).toLowerCase()\n const l = trimSlash(landed.pathname).toLowerCase()\n if (a === l || a === '/') return false\n if (l.startsWith(`${a}/`)) return false\n if (l.endsWith(a)) return false\n return true\n}\n\nconst LADDER =\n 'This is a missing or expired session, not a script bug. Ways past, cheapest first: mint a session from the test auth the project already has; script the sign-in off camera and save the storage state; or have a person sign in once (npx playwright open --channel chrome --save-storage=<file> <url>). Then pass --storage-state <file>. The ladder: https://vos.so/llms-full.txt, \"Sessions\". A take OF this page is --allow-wall.'\n\nexport function wallVerdict(a: Arrival): WallVerdict | null {\n const asked = parse(a.askedUrl)\n const landed = parse(a.landedUrl)\n // A file: or data: take, or a URL we cannot read, has no wall to speak of.\n if (!asked || !landed) return null\n if (!/^https?:$/.test(asked.protocol)) return null\n\n const away = redirectedAway(asked, landed)\n const where = { asked: place(asked), landed: place(landed) }\n const host = bareHost(asked.hostname)\n\n if (a.status === 401 || a.status === 403) {\n return {\n kind: 'status',\n level: 'hard',\n ...where,\n message: `asked for ${asked.pathname}, answered ${a.status}: no session for ${host}. ${LADDER}`,\n }\n }\n\n // Someone who ASKED for the sign-in page and got it wants that take.\n const askedForSignIn =\n isSignInPath(asked.pathname) || isIdpHost(asked.hostname)\n if (askedForSignIn && !away) return null\n\n if (away && isIdpHost(landed.hostname) && !isIdpHost(asked.hostname)) {\n return {\n kind: 'idp',\n level: 'hard',\n ...where,\n message: `asked for ${asked.pathname}, landed on ${landed.hostname}: no session for ${host}. ${LADDER}`,\n }\n }\n\n // One password field that is not a new-password field is a sign-in form.\n // Two, or a new-password one, is a settings page or a sign-up.\n const signInForm =\n (a.passwordFields === 1 && !a.newPasswordField) || a.oneTimeCodeField\n if (\n (away && isSignInPath(landed.pathname)) ||\n (signInForm && !askedForSignIn)\n ) {\n const seen = away\n ? `landed on ${landed.pathname}`\n : 'the page is a sign-in form'\n return {\n kind: 'signin',\n level: 'hard',\n ...where,\n message: `asked for ${asked.pathname}, ${seen}: no session for ${host}. ${LADDER}`,\n }\n }\n\n if (away) {\n return {\n kind: 'redirect',\n level: 'soft',\n ...where,\n message: `asked for ${asked.pathname}, landed on ${landed.pathname}: the site sent the recorder elsewhere, which is what a page behind a login does to a stranger. If that is the page you meant, record it by its own URL. ${LADDER}`,\n }\n }\n return null\n}\n\n/** A take refused at the wall. Carries the verdict for `--json`. */\nexport class WallError extends Error {\n constructor(public verdict: WallVerdict) {\n super(verdict.message)\n this.name = 'WallError'\n }\n}\n\n/**\n * Evidence gathered in the page. A STRING, never a function: a serialized\n * function picks up the bundler's `__name` helper and dies in the page.\n */\nexport const WALL_PROBE = `(() => {\n const shown = (el) => {\n const r = el.getBoundingClientRect()\n if (r.width < 2 || r.height < 2) return false\n const s = getComputedStyle(el)\n return s.visibility !== 'hidden' && s.display !== 'none'\n }\n const pw = [...document.querySelectorAll('input[type=\"password\"]')].filter(shown)\n const otp = [...document.querySelectorAll('input[autocomplete=\"one-time-code\"]')].filter(shown)\n return {\n passwordFields: pw.length,\n newPasswordField: pw.some((el) => (el.getAttribute('autocomplete') || '').includes('new-password')),\n oneTimeCodeField: otp.length > 0,\n }\n})()`\n","/**\n * What a signed-in take SHOWS. Getting past the login is half the problem;\n * the other half is that the account's own data is now in the frame: an\n * email address in the header, a key on a settings page, a card number.\n * Asking nicely does not hold this line (a person asked to sign in with a\n * demo account signs in as themselves, because it is the account they have),\n * so the recorder looks.\n *\n * Two pieces, both run IN the page:\n *\n * - the EXPOSURE scan reads the text that is visible in the viewport after\n * each step and reports the KIND of thing it saw and where. Never the\n * string itself: a report that quotes the secret is a second leak.\n * - a MASK hides a selector before the first frame is captured and keeps it\n * hidden across navigations and re-renders, so the real value is never in\n * a frame, never in the recording, never pushed. `as: 'text'` swaps the\n * words (a product reads better than a redaction); `as: 'blur'` blurs.\n *\n * The matchers are ONE plain-JavaScript source string, evaluated in the page\n * and, by the tests, in Node: a function serialized out of a bundle picks up\n * the bundler's `__name` helper and dies in the page, and two copies of a\n * regex drift.\n */\nimport type { RecordingMeta } from '@vosjs/studio-core'\n\nexport type ExposureKind = 'email' | 'key' | 'card' | 'card-tail'\nexport type Exposure = NonNullable<RecordingMeta['exposures']>[number]\nexport type MaskReport = NonNullable<RecordingMeta['masks']>[number]\n\nexport interface MaskRule {\n selector: string\n /** `blur` (default) blurs the element; `text` swaps its words for `text`. */\n as?: 'blur' | 'text'\n text?: string\n}\n\n/**\n * `kindsIn(text)` → the kinds of sensitive-looking strings in `text`.\n *\n * - email: any address, EXCEPT one on a domain that can reach no one\n * (example.com/.org/.net, and the reserved .test/.example/.invalid/\n * .localhost TLDs), which is what demo data should use.\n * - key: the prefixes of keys people actually paste into dashboards, and a\n * JWT's three base64url parts.\n * - card: 13 to 19 digits that pass the Luhn check, so an order number or a\n * phone number is not a card.\n * - card-tail: a masked number's visible tail (•••• 4242).\n */\nexport const EXPOSURE_MATCHERS_SRC = `(() => {\n const EMAIL = /[A-Za-z0-9._%+-]+@((?:[A-Za-z0-9-]+\\\\.)+[A-Za-z]{2,})/g\n const SAFE_HOST = /(^|\\\\.)example\\\\.(com|org|net)$|\\\\.(test|example|invalid|localhost)$/i\n const KEY = new RegExp([\n '\\\\\\\\b[srp]k_(?:live|test)_[A-Za-z0-9]{8,}',\n '\\\\\\\\bgh[pousr]_[A-Za-z0-9]{20,}',\n '\\\\\\\\bgithub_pat_[A-Za-z0-9_]{20,}',\n '\\\\\\\\bxox[abprs]-[A-Za-z0-9-]{10,}',\n '\\\\\\\\bAKIA[0-9A-Z]{16}\\\\\\\\b',\n '\\\\\\\\bAIza[0-9A-Za-z_-]{30,}',\n '\\\\\\\\bvos_(?:sk|rg|ho)_[A-Za-z0-9]{8,}',\n '\\\\\\\\beyJ[A-Za-z0-9_-]{8,}\\\\\\\\.eyJ[A-Za-z0-9_-]{8,}\\\\\\\\.[A-Za-z0-9_-]{8,}',\n ].join('|'))\n const CARD = /(?:^|[^0-9])((?:[0-9][ -]?){12,18}[0-9])(?![0-9])/g\n const TAIL = /[\\\\u2022\\\\u00b7*xX]{2,}[ -]?[0-9]{4}(?![0-9])/\n const luhn = (digits) => {\n let sum = 0, alt = false\n for (let i = digits.length - 1; i >= 0; i--) {\n let d = digits.charCodeAt(i) - 48\n if (alt) { d *= 2; if (d > 9) d -= 9 }\n sum += d; alt = !alt\n }\n return sum % 10 === 0\n }\n const kindsIn = (text) => {\n const kinds = []\n if (!text || text.length < 6) return kinds\n EMAIL.lastIndex = 0\n for (let m; (m = EMAIL.exec(text)); ) {\n if (!SAFE_HOST.test(m[1])) { kinds.push('email'); break }\n }\n if (KEY.test(text)) kinds.push('key')\n CARD.lastIndex = 0\n for (let m; (m = CARD.exec(text)); ) {\n const digits = m[1].replace(/[ -]/g, '')\n if (digits.length >= 13 && digits.length <= 19 && !/^0+$/.test(digits) && luhn(digits)) { kinds.push('card'); break }\n }\n if (TAIL.test(text)) kinds.push('card-tail')\n return kinds\n }\n return { kindsIn }\n})()`\n\n/**\n * The scan: visible text in the viewport, plus the values of text inputs.\n * Skips anything inside a masked element, password fields, and text the eye\n * cannot see. Reports kind + a selector-ish name for the element + its rect.\n */\nexport const EXPOSURE_PROBE = `(() => {\n const { kindsIn } = ${EXPOSURE_MATCHERS_SRC}\n const vw = innerWidth, vh = innerHeight\n // A selector that reaches THIS element and no other, so it can be pasted\n // into \"mask\" as it is: climb until the path is unique, and say which\n // sibling wherever a tag-and-class alone would match several. What the\n // page wrote for people and tests comes first (an id, a test id, an\n // aria-label, a field's name or placeholder); utility classes are a\n // layout's, and they come last. A value that itself holds what the scan\n // looks for is never used: the selector would quote it.\n const attr = (v) => '\"' + v.replace(/\\\\\\\\/g, '\\\\\\\\\\\\\\\\').replace(/\"/g, '\\\\\\\\\"') + '\"'\n const quiet = (v) => !!v && v.length <= 80 && !kindsIn(v).length\n const segment = (el) => {\n const tag = el.tagName.toLowerCase()\n if (el.id && /^[A-Za-z_][\\\\w-]*$/.test(el.id) && !/\\\\d{2,}/.test(el.id) && quiet(el.id)) return tag + '#' + el.id\n const tid = el.getAttribute('data-testid')\n if (quiet(tid)) return tag + '[data-testid=' + attr(tid) + ']'\n const label = el.getAttribute('aria-label')\n if (quiet(label)) return tag + '[aria-label=' + attr(label) + ']'\n if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName)) {\n const nm = el.getAttribute('name')\n if (quiet(nm)) return tag + '[name=' + attr(nm) + ']'\n const ph = el.getAttribute('placeholder')\n if (quiet(ph)) return tag + '[placeholder=' + attr(ph) + ']'\n }\n const cls = [...el.classList].filter((c) => /^[A-Za-z_-][\\\\w-]*$/.test(c)).slice(0, 2)\n let seg = el.tagName.toLowerCase() + (cls.length ? '.' + cls.join('.') : '')\n const p = el.parentElement\n if (p && [...p.children].filter((c) => c.matches(seg)).length > 1)\n seg += ':nth-child(' + ([...p.children].indexOf(el) + 1) + ')'\n return seg\n }\n const name = (el) => {\n const parts = []\n for (let cur = el; cur && cur !== document.body && cur !== document.documentElement; cur = cur.parentElement) {\n parts.unshift(segment(cur))\n let n = 2\n try { n = document.querySelectorAll(parts.join(' > ')).length } catch {}\n // a bare tag is unique HERE and nowhere else: give it its parent too\n const bare = parts.length === 1 && !/[#.\\\\[]/.test(parts[0])\n if ((n === 1 && !bare) || parts.length >= 5) break\n }\n return parts.join(' > ')\n }\n const seen = (el) => {\n if (el.closest('[data-vos-masked]')) return null\n const r = el.getBoundingClientRect()\n if (r.width < 2 || r.height < 2) return null\n if (r.bottom <= 0 || r.right <= 0 || r.top >= vh || r.left >= vw) return null\n const s = getComputedStyle(el)\n if (s.visibility === 'hidden' || s.display === 'none' || +s.opacity === 0) return null\n return r\n }\n const out = [], keys = new Set()\n const add = (el, text) => {\n const kinds = kindsIn(text)\n if (!kinds.length) return\n const r = seen(el)\n if (!r) return\n const selector = name(el)\n for (const kind of kinds) {\n const k = kind + '|' + selector\n if (keys.has(k) || out.length >= 40) continue\n keys.add(k)\n out.push({ kind, selector, rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } })\n }\n }\n const walker = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT)\n for (let n; (n = walker.nextNode()); ) {\n const el = n.parentElement\n if (!el || /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(el.tagName)) continue\n add(el, n.nodeValue)\n }\n for (const el of document.querySelectorAll('input, textarea')) {\n if (/^(password|hidden|file|checkbox|radio)$/.test(el.type)) continue\n add(el, el.value)\n }\n const hits = {}\n for (const [sel, n] of Object.entries(window.__vosMaskHits || {})) hits[sel] = n\n return { exposures: out, maskHits: hits }\n})()`\n\n/**\n * The mask, as an init script: it runs at document start on EVERY navigation,\n * so a masked value is hidden before the page's first paint, and a\n * MutationObserver re-applies it after a client-side re-render. A form\n * control is blurred even when `as: 'text'` was asked for: writing into an\n * input would change what the app submits.\n */\nexport function maskInitScript(masks: MaskRule[]): string {\n const rules = masks.map((m) => ({\n selector: m.selector,\n as: m.as === 'text' ? 'text' : 'blur',\n text: m.text ?? '',\n }))\n return `(() => {\n const RULES = ${JSON.stringify(rules)}\n const hits = (window.__vosMaskHits = window.__vosMaskHits || {})\n for (const r of RULES) hits[r.selector] = hits[r.selector] || 0\n const css = RULES.map((r) => r.selector + '[data-vos-masked=\"blur\"]{filter:blur(7px) !important;user-select:none !important}').join('\\\\n')\n const paint = () => {\n const root = document.head || document.documentElement\n if (!root || document.getElementById('__vos-mask-style')) return\n const style = document.createElement('style')\n style.id = '__vos-mask-style'\n style.textContent = css\n root.appendChild(style)\n }\n const apply = () => {\n paint()\n for (const r of RULES) {\n let found\n try { found = document.querySelectorAll(r.selector) } catch { continue }\n if (found.length > hits[r.selector]) hits[r.selector] = found.length\n for (const el of found) {\n const form = /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName)\n const mode = r.as === 'text' && !form ? 'text' : 'blur'\n if (el.getAttribute('data-vos-masked') !== mode) el.setAttribute('data-vos-masked', mode)\n if (mode !== 'text') continue\n const texts = []\n const w = document.createTreeWalker(el, NodeFilter.SHOW_TEXT)\n for (let n; (n = w.nextNode()); ) texts.push(n)\n if (!texts.length) { if (el.textContent !== r.text) el.textContent = r.text; continue }\n texts.forEach((n, i) => { const want = i === 0 ? r.text : ''; if (n.nodeValue !== want) n.nodeValue = want })\n }\n }\n }\n new MutationObserver(apply).observe(document, { childList: true, subtree: true, characterData: true })\n document.addEventListener('DOMContentLoaded', apply)\n apply()\n})()`\n}\n\n/**\n * Accumulates scans across a take: an exposure is reported ONCE, at the\n * first step it was seen, with how many scans saw it.\n */\nexport class ExposureLog {\n private byKey = new Map<string, Exposure>()\n private maskHits = new Map<string, number>()\n\n constructor(masks: MaskRule[] = []) {\n for (const m of masks) this.maskHits.set(m.selector, 0)\n }\n\n add(\n step: number,\n scan: {\n exposures?: Omit<Exposure, 'step' | 'seen'>[]\n maskHits?: Record<string, number>\n } | null,\n ): void {\n if (!scan) return\n for (const e of scan.exposures ?? []) {\n const key = `${e.kind}|${e.selector}`\n const had = this.byKey.get(key)\n if (had) had.seen += 1\n else this.byKey.set(key, { step, ...e, seen: 1 })\n }\n for (const [sel, n] of Object.entries(scan.maskHits ?? {})) {\n if (n > (this.maskHits.get(sel) ?? 0)) this.maskHits.set(sel, n)\n }\n }\n\n exposures(): Exposure[] {\n return [...this.byKey.values()]\n }\n\n masks(rules: MaskRule[]): MaskReport[] {\n return rules.map((m) => ({\n selector: m.selector,\n as: m.as === 'text' ? 'text' : 'blur',\n hits: this.maskHits.get(m.selector) ?? 0,\n }))\n }\n}\n\nconst KIND_WORDS: Record<ExposureKind, string> = {\n email: 'an email address',\n key: 'something shaped like an API key or token',\n card: 'a card number',\n 'card-tail': \"a card's last digits\",\n}\n\n/** One exposure, in words. `step` -1 is the page as it opened. */\nexport function exposureLine(e: Exposure): string {\n const when = e.step < 0 ? 'as the page opened' : `at step #${e.step}`\n return `${KIND_WORDS[e.kind]} in ${e.selector} (${when}, ${e.rect.x},${e.rect.y} ${e.rect.w}×${e.rect.h})`\n}\n\nexport const EXPOSURE_ADVICE =\n 'The recording shows these. Record from a demo account, or hide them before the camera rolls with \"mask\" in actions.json: { \"selector\": \"…\", \"as\": \"text\", \"text\": \"demo@acme.test\" } swaps the words, \"as\": \"blur\" blurs. Then re-record.'\n","/**\n * `setup`: the steps that run BEFORE the camera rolls. A sign-in form, a\n * cookie banner, the \"choose your editor\" modal, an onboarding tour: things\n * a take must get past and must not show. They run after the first\n * navigation and before `Page.startScreencast`, with no cursor synthesis,\n * no pace accounting and nothing written to `meta.steps`. Then the recorder\n * navigates to `url` again and the take begins where the setup left it.\n *\n * A `type` step's `text` may be `{ \"env\": \"DEMO_PASSWORD\" }`: resolved at run\n * time from the `env` the caller hands in (the shell's for the CLI, the\n * job's own map for a hosted take), never logged, never stored. The\n * guarantee is narrow and real: the secret is never in a file that travels\n * (`actions.json` is committed and pushed with the take; `meta.json` is read\n * by the digest) and never in the footage.\n */\nimport type { RecorderPage } from './driver'\n\nexport type SetupText = string | { env: string }\n\nexport type SetupStep = (\n | { do: 'wait'; ms: number }\n | { do: 'click'; selector: string; ms?: number }\n | { do: 'type'; selector: string; text: SetupText; ms?: number }\n | { do: 'press'; key: string; ms?: number }\n | { do: 'goto'; url: string }\n) & { id?: string }\n\nconst VERBS = new Set(['wait', 'click', 'type', 'press', 'goto'])\n\n/**\n * Why a page address is not one the recorder opens, or null. A script's\n * `url` and a setup's `goto` open a browser, so only http and https are\n * taken: a `file:` address would read this machine's disk into a take\n * and a `javascript:` one would run in the page.\n */\nexport function urlSchemeProblem(url: string): string | null {\n let u: URL\n try {\n u = new URL(url)\n } catch {\n return `${url} is not a URL`\n }\n if (u.protocol !== 'http:' && u.protocol !== 'https:')\n return `${url} is not an http(s) address, and the recorder opens only http and https pages`\n return null\n}\n\n/** Structural validation, mirrored on `validateActions` for `steps`. */\nexport function validateSetup(value: unknown): string[] {\n const errors: string[] = []\n if (!Array.isArray(value)) return ['setup must be an array of steps']\n value.forEach((raw, i) => {\n const at = `setup[${i}]`\n if (typeof raw !== 'object' || raw === null) {\n errors.push(`${at}: must be an object`)\n return\n }\n const s = raw as Record<string, unknown>\n if (typeof s.do !== 'string' || !VERBS.has(s.do)) {\n errors.push(`${at}: \"do\" must be one of ${[...VERBS].join(', ')}`)\n return\n }\n if ((s.do === 'click' || s.do === 'type') && typeof s.selector !== 'string')\n errors.push(`${at}: ${s.do} needs a selector`)\n if (s.do === 'wait' && typeof s.ms !== 'number')\n errors.push(`${at}: wait needs ms`)\n if (s.do === 'press' && typeof s.key !== 'string')\n errors.push(`${at}: press needs a key`)\n if (s.do === 'goto') {\n if (typeof s.url !== 'string') errors.push(`${at}: goto needs a url`)\n else {\n const problem = urlSchemeProblem(s.url)\n if (problem) errors.push(`${at}: goto ${problem}`)\n }\n }\n if (s.do === 'type') {\n const t = s.text\n const isEnv =\n typeof t === 'object' &&\n t !== null &&\n typeof (t as { env?: unknown }).env === 'string' &&\n Object.keys(t).length === 1\n if (typeof t !== 'string' && !isEnv)\n errors.push(\n `${at}: type needs text, a string or { \"env\": \"NAME\" } read at run time`,\n )\n if (\n typeof t === 'string' &&\n /passw|secret|token/i.test(String(s.selector)) &&\n t.length > 0\n )\n errors.push(\n `${at}: a literal value typed into ${String(s.selector)} would live in actions.json, which is committed and pushed. Use { \"env\": \"NAME\" }`,\n )\n }\n })\n return errors\n}\n\n/** The names a setup reads from its env, so a host can say what it must supply. */\nexport function setupEnvNames(steps: SetupStep[] | undefined): string[] {\n const out = new Set<string>()\n for (const s of steps ?? []) {\n if (s.do === 'type' && typeof s.text === 'object') out.add(s.text.env)\n }\n return [...out]\n}\n\n/** A `{ env }` text resolved, or thrown in words. The value is never returned to a log. */\nexport function resolveSetupText(\n t: SetupText,\n env: Record<string, string | undefined>,\n): { value: string; secret: boolean } {\n if (typeof t === 'string') return { value: t, secret: false }\n const v = env[t.env]\n if (v === undefined || v === '')\n throw new SetupEnvError(\n `setup: the environment variable ${t.env} is not set, and a type step reads it. Export it in the shell that runs vos record; it is never written to a file`,\n )\n return { value: v, secret: true }\n}\n\nexport interface SetupResult {\n ran: number\n /** what the log may say about each step: the verb and the selector, never a typed value */\n lines: string[]\n /** a selector that never appeared; the take does not start */\n failed?: { step: number; do: string; selector?: string }\n}\n\n/**\n * Run the setup on a page, with plain Playwright actions: no humanized\n * pointer, no cursor events, no frames. A selector that never appears\n * fails the setup, because a take that begins at a half-finished sign-in is\n * the wall by another name.\n */\nexport async function runSetup(\n page: RecorderPage,\n steps: SetupStep[],\n opts: {\n sleep: (ms: number) => Promise<void>\n /** Absent means no env at all: a `{ env }` text then fails in words. */\n env?: Record<string, string | undefined>\n },\n): Promise<SetupResult> {\n const env = opts.env ?? {}\n const lines: string[] = []\n for (const [i, step] of steps.entries()) {\n const settle = 'ms' in step && typeof step.ms === 'number' ? step.ms : 150\n try {\n switch (step.do) {\n case 'wait':\n await opts.sleep(step.ms)\n lines.push(`setup #${i} wait ${step.ms}ms`)\n break\n case 'goto':\n await page\n .goto(step.url, { waitUntil: 'networkidle', timeout: 45000 })\n .catch(() => null)\n lines.push(`setup #${i} goto ${step.url}`)\n break\n case 'press':\n await page.keyboard.press(step.key)\n await opts.sleep(settle)\n lines.push(`setup #${i} press ${step.key}`)\n break\n case 'click': {\n const loc = page.locator(step.selector).first()\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n await loc.click()\n await opts.sleep(settle)\n lines.push(`setup #${i} click ${step.selector}`)\n break\n }\n case 'type': {\n const loc = page.locator(step.selector).first()\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n const { value, secret } = resolveSetupText(step.text, env)\n await loc.fill(value)\n await opts.sleep(settle)\n // The log names the field, never what went into it.\n lines.push(\n `setup #${i} type ${secret ? `\\${${(step.text as { env: string }).env}}` : `${value.length} chars`} into ${step.selector}`,\n )\n break\n }\n }\n } catch (e) {\n if (e instanceof SetupEnvError) throw e\n return {\n ran: i,\n lines,\n failed: {\n step: i,\n do: step.do,\n ...('selector' in step ? { selector: step.selector } : {}),\n },\n }\n }\n }\n return { ran: steps.length, lines }\n}\n\n/** A `{ env }` the shell did not provide: a usage error, not a page's. */\nexport class SetupEnvError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'SetupEnvError'\n }\n}\n\n/** A setup step whose selector never appeared: the take does not start. */\nexport class SetupError extends Error {\n constructor(public failed: NonNullable<SetupResult['failed']>) {\n super(\n `setup #${failed.step} ${failed.do}${failed.selector ? ` ${failed.selector}` : ''}: the selector never appeared, so the take would begin at a half-finished setup. Nothing was recorded. Fix the setup step (rehearse with --dry-run), then record.`,\n )\n this.name = 'SetupError'\n }\n}\n\n/** `--header name=value`, repeatable: extra request headers on every request. */\nexport function parseHeaders(\n given: string[] | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const h of given ?? []) {\n const i = h.indexOf('=')\n if (i <= 0) throw new Error(`--header wants name=value, got \"${h}\"`)\n out[h.slice(0, i).trim()] = h.slice(i + 1)\n }\n return out\n}\n","/**\n * The take's clock: ONE path from a wall-clock instant to footage time,\n * for the cursor events and for every screencast frame alike.\n *\n * Footage time is wall time since `t0` minus every off-camera stretch (an\n * `await`) that began before the instant; an instant inside a stretch reads\n * as the stretch's start, which is where the cut is. A frame is placed by\n * the instant it was CAPTURED, never by when its callback ran: a frame in\n * flight when the capture paused lands after the resume and must still sit\n * before the cut.\n *\n * Frame times are strictly increasing. The screencast does not promise it:\n * a frame can arrive after a later one, and a frame without a capture\n * timestamp is stamped by its arrival, a second clock. A frame whose time\n * is not later than the last one kept holds older pixels than what the\n * footage already shows, so it is DROPPED (never re-stamped forward, which\n * would put a stale picture after a newer one).\n */\nexport class TakeClock {\n private readonly pauses: { from: number; to: number | null }[] = []\n private lastFrameMs = -1\n\n constructor(readonly t0: number) {}\n\n /** Footage ms at a wall-clock instant (`Date.now()` space). */\n footageMs(wallMs: number): number {\n let off = 0\n for (const p of this.pauses) {\n if (wallMs <= p.from) break\n off += Math.min(wallMs, p.to ?? Infinity) - p.from\n }\n return wallMs - this.t0 - off\n }\n\n /** The camera stops at this instant; returns the cut's footage ms. */\n pause(wallMs: number): number {\n const at = this.footageMs(wallMs)\n this.pauses.push({ from: wallMs, to: null })\n return at\n }\n\n /** The camera rolls again; returns the wall ms the stretch lasted. */\n resume(wallMs: number): number {\n const open = this.pauses[this.pauses.length - 1] as\n | { from: number; to: number | null }\n | undefined\n if (!open || open.to !== null) return 0\n open.to = Math.max(open.from, wallMs)\n return open.to - open.from\n }\n\n /**\n * A captured frame's footage ms, or null when it is not later than the\n * last frame kept (the frame is dropped; see the module comment).\n */\n placeFrame(captureWallMs: number): number | null {\n const t = Math.max(0, Math.round(this.footageMs(captureWallMs)))\n if (t <= this.lastFrameMs) return null\n this.lastFrameMs = t\n return t\n }\n}\n","/**\n * The page's own console errors, as the recorder reports them. A page\n * under recording is someone else's, and its errors are context, never the\n * story: a third party's Content-Security-Policy violation runs to a few\n * kilobytes and repeats on every load, which buried the step lines. So the\n * log gets one line per distinct error, cut short, and a repeat is counted\n * instead of printed; the full text stays in the result (and a verbose\n * host prints every one whole).\n */\n\n/** How much of an error a log line keeps. */\nexport const PAGE_ERROR_LINE_CHARS = 160\n\nexport interface PageError {\n /** the full text, whitespace as the page wrote it */\n text: string\n count: number\n}\n\n/** One line of an error: whitespace collapsed, cut to the line's length. */\nexport function pageErrorLine(text: string): string {\n const one = text.replace(/\\s+/g, ' ').trim()\n return one.length > PAGE_ERROR_LINE_CHARS\n ? `${one.slice(0, PAGE_ERROR_LINE_CHARS - 1)}…`\n : one\n}\n\nexport class PageErrorLog {\n private readonly seen = new Map<string, PageError>()\n\n constructor(private readonly verbose = false) {}\n\n /** The line to log for this error now, or null when it repeats one already said. */\n add(text: string): string | null {\n const known = this.seen.get(text)\n if (known) {\n known.count++\n return this.verbose ? ` [page error] ${text}` : null\n }\n this.seen.set(text, { text, count: 1 })\n return ` [page error] ${this.verbose ? text : pageErrorLine(text)}`\n }\n\n /** Every distinct error with how often it came, in the order first seen. */\n entries(): PageError[] {\n return [...this.seen.values()].map((e) => ({ ...e }))\n }\n\n /** The closing lines: each error that repeated, with its count. */\n repeats(): string[] {\n if (this.verbose) return []\n return [...this.seen.values()]\n .filter((e) => e.count > 1)\n .map((e) => ` [page error ×${e.count}] ${pageErrorLine(e.text)}`)\n }\n}\n","import type { MaskRule } from './exposure'\nimport type { SetupStep } from './setup'\nimport { urlSchemeProblem, validateSetup } from './setup'\n\n/**\n * The action script — the declarative recipe an agent (or human) writes to\n * drive a take. Small on purpose: selectors + a handful of verbs. The recorder\n * executes it with humanized cursor motion and synthesizes the CursorTrack\n * from its own dispatches.\n */\nexport interface ActionsFile {\n /** Page to record. `--url` overrides. */\n url?: string\n /** Recording viewport in CSS px (default 1280x720). */\n viewport?: { width: number; height: number }\n /**\n * Hidden BEFORE the first frame is captured and kept hidden across\n * navigations: what a signed-in account shows that must not ship. `blur`\n * (default) blurs the element; `text` swaps its words for `text`, which is\n * for IDENTIFIERS (an email, a name, an account id), never for product\n * copy or numbers: the video must stay true to the product.\n */\n mask?: MaskRule[]\n /**\n * Run BEFORE the camera rolls, after the first navigation: a sign-in form,\n * a cookie banner, an onboarding tour. Plain actions with no cursor, no\n * frames, no pace and nothing in `meta.steps`; then the recorder opens\n * `url` again and the take begins where the setup left it. A `type`\n * step's text may be `{ env: 'NAME' }`, read at run time and never logged\n * or stored.\n */\n setup?: SetupStep[]\n steps: ActionStep[]\n}\n\nexport type ActionStep = (\n | { do: 'wait'; ms: number }\n | { do: 'hover'; selector: string; ms?: number }\n /** `ms` is the settle after the press (default 150). */\n | { do: 'click'; selector: string; ms?: number }\n /**\n * Type into `selector`. The recorder clicks the field first, which is what\n * opens the typing zoom on it; `focus: false` types into the field as it is\n * already focused, for a keystroke that follows earlier typing (a submitting\n * Enter) rather than starting it — a second click there rings a click effect\n * on empty space beside the text.\n */\n | {\n do: 'type'\n selector: string\n text: string\n delayMs?: number\n focus?: boolean\n /**\n * Select the field's value before typing, so what is typed REPLACES\n * it (a form that opens filled in, a search box with the last query).\n */\n replace?: boolean\n /**\n * Where the caret goes after the focusing click, before the first\n * character: `end` or `start` of the field (a code editor line is\n * typed at its end; a click lands the caret where the pointer hit).\n */\n at?: 'end' | 'start'\n /** the settle after the last character (default 150) */\n ms?: number\n }\n /**\n * One named key, recorded as a typing ping where the pointer is (or on\n * `selector` when given, with no click): Escape closes what a click\n * opened, Enter submits what was typed, Tab moves on, an arrow nudges.\n * Never a character: words are typed with `type`.\n */\n | { do: 'press'; key: PressKey; selector?: string; ms?: number }\n /** `ms` is the settle after the scroll lands (default 200). */\n | { do: 'scroll'; dy: number; ms?: number }\n | { do: 'move'; x: number; y: number }\n /**\n * Press-move-release — real edits (drag an element on the stage canvas,\n * slide a range input, move a timeline clip). Start = the selector's center\n * when given, else (x, y); end = (tx, ty); eased over ms (default 700).\n */\n | {\n do: 'drag'\n selector?: string\n x?: number\n y?: number\n tx: number\n ty: number\n ms?: number\n }\n /**\n * Check that the page is as the flow expects, with no cursor move: an\n * element visible (`selector`; with `enabled`, enabled or disabled), some\n * visible text containing `text`, or `gone` no longer visible. Exactly\n * one of the three. Waits up to `timeout` seconds (default 5); a\n * condition that never holds is a skip with its reason.\n */\n | {\n do: 'expect'\n selector?: string\n text?: string\n gone?: string\n enabled?: boolean\n timeout?: number\n }\n /**\n * Wait OFF CAMERA for something slow (a render, a generated result, a\n * deploy): the capture stops, the predicate is polled every `poll`\n * seconds (default 2) for up to `timeout` (default 600), reloading the\n * page between polls when `reload` is set, and the capture resumes when\n * it holds. The footage has no gap and no frozen stretch; the cut lands\n * in `meta.skips[]`. On timeout, `onTimeout: \"fail\"` (the default) stops\n * the take and `\"continue\"` resumes it.\n */\n | {\n do: 'await'\n until: AwaitUntil\n timeout?: number\n poll?: number\n reload?: boolean\n onTimeout?: 'fail' | 'continue'\n }\n /**\n * Keep a file the page makes: click `selector` and wait for the\n * browser's download, or fetch the `currentSrc` of the video, audio or\n * img element `src` names, with the page's own cookies. Saved under the\n * take's `outputs/` as `as`, else the name the page suggested, and listed\n * in `meta.outputs[]`.\n */\n | { do: 'download'; selector?: string; src?: string; as?: string }\n) & {\n /**\n * `\"spend\"`: the step costs something real (credits, a purchase, a\n * message sent). Only a click, a press or a type carries it, and it\n * needs an `id`. A rehearsal hovers it and never presses it; a recording\n * presses it only when the command names it (`--confirm <id>`) and\n * refuses before capturing anything otherwise.\n */\n guard?: StepGuard\n /**\n * Optional stable identity: anchors in doc.json name a step by this\n * id (else by index), so a step can move or gain neighbours across script\n * edits without breaking the cut anchored to it. Unique when present.\n */\n id?: string\n /**\n * A beat's caption, two to eight words: `vos deliver` lands it as a\n * lower-third at this step's moment on the cuts that take words, and\n * `vos actions script` leads the beat with it.\n */\n caption?: string\n /**\n * A selector whose words the recorder keeps once the step has settled\n * (`meta.steps[].text`: trimmed, whitespace collapsed, at most 2 KB), so\n * a layer quotes the take instead of a replay: the URL a share button\n * minted, the code a dialog printed, the status a request answered. On\n * a click it reads after the click's settle, so what the click opened is\n * what is read. Only what the flow names, never a secret it did not.\n */\n read?: string\n}\n\n/** What an `await` waits for: exactly one of the three. */\nexport interface AwaitUntil {\n selector?: string\n text?: string\n gone?: string\n}\n\n/** The guards a step may carry: one today, a step that spends. */\nexport const STEP_GUARDS = ['spend'] as const\nexport type StepGuard = (typeof STEP_GUARDS)[number]\n\n/** The verbs a guard may sit on: the ones that commit something. */\nconst GUARDABLE = new Set(['click', 'press', 'type'])\n\n/** How long an `expect` waits by default, in seconds. */\nexport const EXPECT_TIMEOUT_S = 5\n/** An `await`'s defaults, in seconds. */\nexport const AWAIT_TIMEOUT_S = 600\nexport const AWAIT_POLL_S = 2\n/** How long a `download` click waits for the browser's download, in seconds. */\nexport const DOWNLOAD_TIMEOUT_S = 30\n\nconst VERBS = new Set([\n 'wait',\n 'hover',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'move',\n 'drag',\n 'expect',\n 'await',\n 'download',\n])\n\n/** The keys a `press` step may name: navigation and control, never a character. */\nexport const PRESS_KEYS = [\n 'Escape',\n 'Enter',\n 'Tab',\n 'Backspace',\n 'Delete',\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n 'Space',\n] as const\nexport type PressKey = (typeof PRESS_KEYS)[number]\n\n/** Structural validation with actionable messages. Returns [] when valid. */\nexport function validateActions(value: unknown): string[] {\n const errors: string[] = []\n if (typeof value !== 'object' || value === null)\n return ['actions file must be a JSON object']\n const obj = value as Record<string, unknown>\n if (obj.url !== undefined) {\n if (typeof obj.url !== 'string') errors.push('url must be a string')\n else {\n const problem = urlSchemeProblem(obj.url)\n if (problem) errors.push(`url ${problem}`)\n }\n }\n if (obj.viewport !== undefined) {\n const v: unknown = obj.viewport\n if (typeof v !== 'object' || v === null) {\n errors.push('viewport must be { width, height }')\n } else {\n const vp = v as Record<string, unknown>\n if (typeof vp.width !== 'number' || typeof vp.height !== 'number') {\n errors.push('viewport must be { width, height }')\n }\n }\n }\n if (obj.setup !== undefined) errors.push(...validateSetup(obj.setup))\n if (obj.mask !== undefined) {\n if (!Array.isArray(obj.mask)) {\n errors.push('mask must be an array of { selector, as?, text? }')\n } else {\n obj.mask.forEach((raw, i) => {\n const at = `mask[${i}]`\n const m = (raw ?? {}) as Record<string, unknown>\n if (typeof m.selector !== 'string' || !m.selector.trim())\n errors.push(`${at}: needs a selector`)\n if (m.as !== undefined && m.as !== 'blur' && m.as !== 'text')\n errors.push(`${at}: as must be \"blur\" or \"text\"`)\n if (m.as === 'text' && (typeof m.text !== 'string' || !m.text))\n errors.push(`${at}: as \"text\" needs the text to show instead`)\n if (m.as !== 'text' && m.text !== undefined)\n errors.push(`${at}: text is only read with as \"text\"`)\n })\n }\n }\n if (!Array.isArray(obj.steps) || obj.steps.length === 0) {\n errors.push('steps must be a non-empty array')\n return errors\n }\n const seenIds = new Set<string>()\n obj.steps.forEach((raw, i) => {\n const at = `steps[${i}]`\n if (typeof raw !== 'object' || raw === null) {\n errors.push(`${at}: must be an object`)\n return\n }\n const s = raw as Record<string, unknown>\n if (s.read !== undefined && (typeof s.read !== 'string' || !s.read.trim()))\n errors.push(`${at}: read must be a selector`)\n if (typeof s.do !== 'string' || !VERBS.has(s.do)) {\n errors.push(`${at}: \"do\" must be one of ${[...VERBS].join(', ')}`)\n return\n }\n if (s.id !== undefined) {\n if (typeof s.id !== 'string' || !s.id.trim()) {\n errors.push(`${at}: id must be a non-empty string`)\n } else if (seenIds.has(s.id)) {\n errors.push(\n `${at}: duplicate id \"${s.id}\" — an anchor could not tell the two steps apart`,\n )\n } else {\n seenIds.add(s.id)\n }\n }\n const needSelector = s.do === 'hover' || s.do === 'click' || s.do === 'type'\n if (needSelector && typeof s.selector !== 'string')\n errors.push(`${at}: ${s.do} needs a selector`)\n if (s.do === 'wait' && typeof s.ms !== 'number')\n errors.push(`${at}: wait needs ms`)\n if (\n s.ms !== undefined &&\n (typeof s.ms !== 'number' || !Number.isFinite(s.ms) || s.ms < 0)\n )\n errors.push(`${at}: ms must be a number of milliseconds ≥ 0`)\n if (s.do === 'type' && typeof s.text !== 'string')\n errors.push(`${at}: type needs text`)\n if (\n s.do === 'type' &&\n s.focus !== undefined &&\n typeof s.focus !== 'boolean'\n )\n errors.push(`${at}: type focus must be true or false`)\n if (\n s.do === 'type' &&\n s.replace !== undefined &&\n typeof s.replace !== 'boolean'\n )\n errors.push(`${at}: type replace must be true or false`)\n if (\n s.do === 'type' &&\n s.at !== undefined &&\n s.at !== 'end' &&\n s.at !== 'start'\n )\n errors.push(`${at}: type at must be \"end\" or \"start\"`)\n if (s.do === 'press') {\n if (\n typeof s.key !== 'string' ||\n !(PRESS_KEYS as readonly string[]).includes(s.key)\n )\n errors.push(\n `${at}: press needs a key, one of ${PRESS_KEYS.join(', ')}; words are typed with type`,\n )\n if (s.selector !== undefined && typeof s.selector !== 'string')\n errors.push(`${at}: press selector must be a string`)\n }\n if (s.do === 'scroll' && typeof s.dy !== 'number')\n errors.push(`${at}: scroll needs dy`)\n if (\n s.do === 'move' &&\n (typeof s.x !== 'number' || typeof s.y !== 'number')\n ) {\n errors.push(`${at}: move needs x and y (CSS px)`)\n }\n if (s.guard !== undefined) {\n if (!(STEP_GUARDS as readonly unknown[]).includes(s.guard))\n errors.push(\n `${at}: guard must be ${STEP_GUARDS.map((g) => `\"${g}\"`).join(' or ')}`,\n )\n else if (!GUARDABLE.has(s.do))\n errors.push(\n `${at}: guard sits on a click, a press or a type, the steps that commit something; a ${s.do} spends nothing`,\n )\n else if (typeof s.id !== 'string' || !s.id.trim())\n errors.push(\n `${at}: a guarded step needs an id, which is what --confirm <id> names`,\n )\n }\n if (s.do === 'expect') {\n const given = (['selector', 'text', 'gone'] as const).filter(\n (k) => s[k] !== undefined,\n )\n if (given.length !== 1)\n errors.push(\n `${at}: expect needs exactly one of selector, text or gone${given.length ? ` (it has ${given.join(' and ')})` : ''}`,\n )\n for (const k of given)\n if (!isFilled(s[k]))\n errors.push(`${at}: expect ${k} must be a non-empty string`)\n if (s.enabled !== undefined) {\n if (typeof s.enabled !== 'boolean')\n errors.push(`${at}: expect enabled must be true or false`)\n else if (s.selector === undefined)\n errors.push(\n `${at}: expect enabled is about the selector's element, so it needs a selector`,\n )\n }\n errors.push(...secondsProblem(at, 'expect timeout', s.timeout))\n }\n if (s.do === 'await') {\n const u = s.until\n if (typeof u !== 'object' || u === null || Array.isArray(u)) {\n errors.push(\n `${at}: await needs until, one of { \"selector\" }, { \"text\" } or { \"gone\" }`,\n )\n } else {\n const until = u as Record<string, unknown>\n const keys = Object.keys(until)\n const known: string[] = keys.filter(\n (k) => k === 'selector' || k === 'text' || k === 'gone',\n )\n const unknown = keys.filter((k) => !known.includes(k))\n if (unknown.length)\n errors.push(\n `${at}: await until takes selector, text or gone, not ${unknown.join(', ')}`,\n )\n if (known.length !== 1)\n errors.push(\n `${at}: await until needs exactly one of selector, text or gone${known.length ? ` (it has ${known.join(' and ')})` : ''}`,\n )\n for (const k of known) {\n const v = until[k]\n if (typeof v !== 'string' || !v.trim())\n errors.push(`${at}: await until.${k} must be a non-empty string`)\n }\n }\n errors.push(...secondsProblem(at, 'await timeout', s.timeout))\n errors.push(...secondsProblem(at, 'await poll', s.poll))\n if (s.reload !== undefined && typeof s.reload !== 'boolean')\n errors.push(`${at}: await reload must be true or false`)\n if (\n s.onTimeout !== undefined &&\n s.onTimeout !== 'fail' &&\n s.onTimeout !== 'continue'\n )\n errors.push(`${at}: await onTimeout must be \"fail\" or \"continue\"`)\n }\n if (s.do === 'download') {\n const given = (['selector', 'src'] as const).filter(\n (k) => s[k] !== undefined,\n )\n if (given.length !== 1)\n errors.push(\n `${at}: download needs exactly one of selector (a control that downloads) or src (a video, audio or img element whose source is fetched)`,\n )\n for (const k of given)\n if (!isFilled(s[k]))\n errors.push(`${at}: download ${k} must be a non-empty string`)\n if (s.as !== undefined) {\n const problem =\n typeof s.as === 'string' ? fileNameProblem(s.as) : 'is not a string'\n if (problem) errors.push(`${at}: download as ${problem}`)\n }\n }\n if (s.do === 'drag') {\n if (typeof s.tx !== 'number' || typeof s.ty !== 'number') {\n errors.push(`${at}: drag needs tx and ty (CSS px)`)\n }\n const hasStart =\n typeof s.selector === 'string' ||\n (typeof s.x === 'number' && typeof s.y === 'number')\n if (!hasStart)\n errors.push(\n `${at}: drag needs a selector OR x and y as the start point`,\n )\n }\n })\n return errors\n}\n\nconst isFilled = (v: unknown): boolean =>\n typeof v === 'string' && v.trim().length > 0\n\nfunction secondsProblem(at: string, what: string, v: unknown): string[] {\n if (v === undefined) return []\n if (typeof v !== 'number' || !Number.isFinite(v) || v <= 0)\n return [`${at}: ${what} must be a number of seconds above 0`]\n return []\n}\n\n/**\n * Why a name is not one a download may be saved under, or null. A plain\n * file name only: the file lands in the take's `outputs/` and nowhere\n * else, so no separator, no `..`, nothing hidden, nothing empty.\n */\nexport function fileNameProblem(name: string): string | null {\n if (!name.trim()) return 'must be a file name'\n if (/[/\\\\]/.test(name))\n return `\"${name}\" must be a plain file name, with no path separator`\n if (name.includes('..'))\n return `\"${name}\" must be a plain file name, with no \"..\"`\n if (name.startsWith('.')) return `\"${name}\" must not be a hidden file`\n // eslint-disable-next-line no-control-regex\n if (/[\\u0000-\\u001f\\u007f]/.test(name))\n return `\"${name}\" must not hold control characters`\n if (name.length > 200) return 'must be at most 200 characters'\n return null\n}\n\n/** A guarded step of a script: where it is, what it is, the id that confirms it. */\nexport interface GuardedStep {\n step: number\n id: string\n do: string\n guard: StepGuard\n}\n\n/** The guarded steps of a script, in order. */\nexport function guardedSteps(\n actions: Pick<ActionsFile, 'steps'>,\n): GuardedStep[] {\n const out: GuardedStep[] = []\n actions.steps.forEach((s, i) => {\n if (s.guard)\n out.push({ step: i, id: s.id ?? String(i), do: s.do, guard: s.guard })\n })\n return out\n}\n\n/**\n * Whether a recording may run with the confirmations it was given: every\n * guarded step named by `--confirm`, and every name a guarded step. A\n * refusal is one sentence naming the steps and the flag, said before\n * anything is captured.\n */\nexport function guardVerdict(\n actions: Pick<ActionsFile, 'steps'>,\n confirm: readonly string[],\n):\n | { ok: true }\n | { ok: false; unconfirmed: string[]; unknown: string[]; message: string } {\n const guarded = guardedSteps(actions)\n const unconfirmed = guarded.filter((g) => !confirm.includes(g.id))\n const unknown = confirm.filter((c) => !guarded.some((g) => g.id === c))\n if (!unconfirmed.length && !unknown.length) return { ok: true }\n const parts: string[] = []\n if (unconfirmed.length) {\n const one = unconfirmed.length === 1\n parts.push(\n `${unconfirmed.map((g) => `#${g.step} ${g.id} (${g.do})`).join(', ')} ${one ? 'is' : 'are'} guarded (${unconfirmed[0].guard}): ${one ? 'it spends' : 'they spend'} something real, so the recorder presses ${one ? 'it' : 'them'} only when the command says so. Add ${unconfirmed.map((g) => `--confirm ${g.id}`).join(' ')} to record ${one ? 'it' : 'them'}, or rehearse with --dry-run, which hovers and never presses`,\n )\n }\n if (unknown.length)\n parts.push(\n `${unknown.map((c) => `--confirm ${c}`).join(', ')} names no guarded step${guarded.length ? ` (the guarded ones: ${guarded.map((g) => g.id).join(', ')})` : ''}`,\n )\n return {\n ok: false,\n unconfirmed: unconfirmed.map((g) => g.id),\n unknown,\n message: `${parts.join('. ')}. Nothing was recorded.`,\n }\n}\n\n/**\n * What a hosted recorder cannot do with a script, in words, or []: a\n * guarded step has nobody to confirm it on a fleet, and a download has no\n * take directory to land in there.\n */\nexport function hostedRefusals(actions: Pick<ActionsFile, 'steps'>): string[] {\n const out: string[] = []\n for (const g of guardedSteps(actions))\n out.push(\n `steps[${g.step}] (${g.id}) is guarded (${g.guard}), and a hosted take has no way to confirm it: record it on this machine with --confirm ${g.id}`,\n )\n actions.steps.forEach((s, i) => {\n if (s.do === 'download')\n out.push(\n `steps[${i}] is a download, which a hosted take does not keep: record it on this machine, where the file lands in the take's outputs/`,\n )\n })\n return out\n}\n","/**\n * What an `expect` and an `await` wait for: a condition on the page, read\n * without touching it (no cursor, no input), polled until it holds or the\n * time runs out. `expect` polls on camera for a few seconds; `await` polls\n * off camera for as long as a slow result takes. One reader for both, so\n * \"appeared\" means the same thing in either.\n */\nimport type { RecorderPage } from './driver'\n\nexport interface WaitCondition {\n /** an element matching this selector is visible */\n selector?: string\n /** some visible text on the page contains this */\n text?: string\n /** no element matching this selector is visible */\n gone?: string\n /** with `selector`: the element is enabled (true) or disabled (false) */\n enabled?: boolean\n}\n\n/** What the condition found the last time it looked: what a miss is said from. */\nexport interface ConditionState {\n holds: boolean\n /** with `selector`: whether a match was visible */\n visible?: boolean\n}\n\n/**\n * The visible text of the page contains `text`: `innerText` is what the\n * page renders, so a hidden element's words never count.\n */\nexport function visibleTextScript(text: string): string {\n return `(() => { const b = document.body; return !!b && (b.innerText || '').includes(${JSON.stringify(text)}) })()`\n}\n\n/** Read the condition once. A page mid-navigation reads as \"not yet\". */\nexport async function readCondition(\n page: RecorderPage,\n c: WaitCondition,\n): Promise<ConditionState> {\n try {\n if (c.text !== undefined)\n return { holds: await page.evaluate<boolean>(visibleTextScript(c.text)) }\n if (c.gone !== undefined)\n return { holds: !(await page.locator(c.gone).first().isVisible()) }\n if (c.selector !== undefined) {\n const loc = page.locator(c.selector).first()\n const visible = await loc.isVisible()\n if (!visible) return { holds: false, visible }\n if (c.enabled === undefined) return { holds: true, visible }\n const enabled = await loc.isEnabled({ timeout: 1000 })\n return { holds: enabled === c.enabled, visible }\n }\n } catch {\n // A navigation tore the context down under the read: look again.\n }\n return { holds: false }\n}\n\n/** What a poll found: whether the condition held, after how long, and the last read. */\nexport interface PollResult {\n ok: boolean\n ms: number\n last: ConditionState\n}\n\n/**\n * Poll the condition every `everyMs` until it holds or `timeoutMs` pass.\n * `between` runs before each look but the first (an `await`'s reload).\n * With `confirm`, a hold counts only once it has held on that many reads\n * in a row, `confirm.gapMs` apart: a page that renders after network quiet\n * reads half-built for a moment, and a `gone` condition holds on a list\n * that has not been drawn yet. The clock is the wall's: a rehearsal waits\n * as long as a take would, because how long a result takes is what a\n * rehearsal is for.\n */\nexport async function pollCondition(\n page: RecorderPage,\n c: WaitCondition,\n opts: {\n timeoutMs: number\n everyMs: number\n sleep: (ms: number) => Promise<void>\n now?: () => number\n between?: () => Promise<void>\n confirm?: { reads: number; gapMs: number }\n },\n): Promise<PollResult> {\n const now = opts.now ?? Date.now\n const start = now()\n const reads = Math.max(1, opts.confirm?.reads ?? 1)\n for (let first = true; ; first = false) {\n if (!first && opts.between) await opts.between()\n let last = await readCondition(page, c)\n for (let n = 1; last.holds && n < reads; n++) {\n await opts.sleep(opts.confirm?.gapMs ?? 0)\n last = await readCondition(page, c)\n }\n const ms = now() - start\n if (last.holds) return { ok: true, ms, last }\n const left = opts.timeoutMs - ms\n if (left <= 0) return { ok: false, ms, last }\n await opts.sleep(Math.min(opts.everyMs, left))\n }\n}\n\n/** The DOM counts as settled after this long with no change. */\nexport const DOM_QUIET_MS = 800\n/** The longest a settle waits on a page that never stops changing. */\nexport const DOM_SETTLE_CAP_MS = 5000\n\n/**\n * The page's own count of DOM changes: an observer installed once per\n * document, read back as a number. A string, the one evaluate shape every\n * driver shares.\n */\nexport const DOM_CHANGE_PROBE = `(() => {\n if (!window.__vosDomChanges) {\n window.__vosDomChanges = { n: 0 };\n new MutationObserver((list) => { window.__vosDomChanges.n += list.length })\n .observe(document, { subtree: true, childList: true, attributes: true, characterData: true });\n }\n return window.__vosDomChanges.n;\n})()`\n\n/**\n * Wait until the DOM has not changed for `quietMs`, at most `capMs`: what\n * a page does after its network went quiet (a list rendered from data, a\n * hydration). The count is polled from here rather than timed in the\n * page, because a background tab throttles its own timers.\n */\nexport async function domSettled(\n page: RecorderPage,\n opts: {\n sleep: (ms: number) => Promise<void>\n now?: () => number\n quietMs?: number\n capMs?: number\n tickMs?: number\n },\n): Promise<{ settled: boolean; ms: number }> {\n const now = opts.now ?? Date.now\n const quiet = opts.quietMs ?? DOM_QUIET_MS\n const cap = opts.capMs ?? DOM_SETTLE_CAP_MS\n const start = now()\n let seen = await page.evaluate<number>(DOM_CHANGE_PROBE).catch(() => -1)\n let since = start\n for (;;) {\n const t = now()\n if (t - since >= quiet) return { settled: true, ms: t - start }\n if (t - start >= cap) return { settled: false, ms: t - start }\n await opts.sleep(opts.tickMs ?? 100)\n const n = await page.evaluate<number>(DOM_CHANGE_PROBE).catch(() => -1)\n if (n !== seen) {\n seen = n\n since = now()\n }\n }\n}\n\n/** Seconds as the recorder says them: `5 s`, `2.5 s`, `3 min 20 s`. */\nexport function sayDuration(ms: number): string {\n const s = Math.round(ms / 100) / 10\n if (s < 60) return `${s} s`\n const m = Math.floor(s / 60)\n const rest = Math.round(s - m * 60)\n return rest ? `${m} min ${rest} s` : `${m} min`\n}\n\n/** What the condition waits for, in words: `'#result' to appear`. */\nexport function sayCondition(c: WaitCondition): string {\n if (c.text !== undefined) return `text \"${c.text}\" to show`\n if (c.gone !== undefined) return `'${c.gone}' to go`\n if (c.enabled === true) return `'${c.selector}' to be enabled`\n if (c.enabled === false) return `'${c.selector}' to be disabled`\n return `'${c.selector}' to appear`\n}\n\n/** Why the condition did not hold, in words: `'Generate' stayed disabled for 5 s`. */\nexport function conditionMiss(\n c: WaitCondition,\n last: ConditionState,\n ms: number,\n): string {\n const t = sayDuration(ms)\n if (c.text !== undefined)\n return `no visible text contained \"${c.text}\" for ${t}`\n if (c.gone !== undefined) return `'${c.gone}' was still there after ${t}`\n if (last.visible && c.enabled === true)\n return `'${c.selector}' stayed disabled for ${t}`\n if (last.visible && c.enabled === false)\n return `'${c.selector}' stayed enabled for ${t}`\n return `'${c.selector}' never appeared in ${t}`\n}\n","/**\n * What a `download` step keeps: the bytes of a file the page made, under a\n * plain name in the take's `outputs/`. The pure parts (the name, the byte\n * read, the in-page fetch) live here; the recorder drives the click or\n * the fetch, and the host's `OutputSink` puts the bytes somewhere.\n */\nimport { fileNameProblem } from './actions'\nimport type { RecorderMediaElement } from './driver'\n\n/** The most a download keeps: a file the page made, never a disk's worth. */\nexport const OUTPUT_MAX_BYTES = 512 * 1024 * 1024\n\n/**\n * A name the page suggested, made plain: its last path segment, control\n * characters and leading dots removed, or `fallback` when nothing usable\n * is left. A page chooses this name, so it is cleaned, never trusted.\n */\nexport function plainName(suggested: string, fallback: string): string {\n const last = suggested.split(/[/\\\\]/).pop() ?? ''\n const clean = last\n // eslint-disable-next-line no-control-regex\n .replace(/[\\u0000-\\u001f\\u007f]/g, '')\n .replace(/\\.\\.+/g, '.')\n .replace(/^\\.+/, '')\n .trim()\n .slice(0, 200)\n return clean && !fileNameProblem(clean) ? clean : fallback\n}\n\n/** The file name a URL's path ends in, decoded, or ''. */\nexport function nameFromUrl(url: string): string {\n try {\n const u = new URL(url)\n if (u.protocol === 'blob:' || u.protocol === 'data:') return ''\n const seg = u.pathname.split('/').filter(Boolean).pop() ?? ''\n return decodeURIComponent(seg)\n } catch {\n return ''\n }\n}\n\n/**\n * The name a download is saved under: the step's `as` when it gave one,\n * else the page's suggestion made plain, made unique among the names this\n * take already used (`clip.mp4`, `clip-2.mp4`).\n */\nexport function outputName(\n asked: string | undefined,\n suggested: string,\n fallback: string,\n used: ReadonlySet<string>,\n): string {\n const base = asked ?? plainName(suggested, fallback)\n if (!used.has(base)) return base\n const dot = base.lastIndexOf('.')\n const stem = dot > 0 ? base.slice(0, dot) : base\n const ext = dot > 0 ? base.slice(dot) : ''\n for (let n = 2; ; n++) {\n const next = `${stem}-${n}${ext}`\n if (!used.has(next)) return next\n }\n}\n\n/** A chunk of a byte stream as bytes: a Node Buffer is one already. */\nfunction chunkBytes(c: unknown): Uint8Array {\n if (c instanceof Uint8Array) return c\n if (typeof c === 'string') return new TextEncoder().encode(c)\n if (c instanceof ArrayBuffer) return new Uint8Array(c)\n throw new Error('the download stream gave something that is not bytes')\n}\n\n/** Read a stream of byte chunks whole, refusing past `max` bytes. */\nexport async function readAllBytes(\n stream: AsyncIterable<unknown>,\n max = OUTPUT_MAX_BYTES,\n): Promise<Uint8Array> {\n const parts: Uint8Array[] = []\n let n = 0\n for await (const c of stream) {\n const u = chunkBytes(c)\n n += u.length\n if (n > max)\n throw new Error(\n `the file is larger than ${Math.round(max / 1024 / 1024)} MB`,\n )\n parts.push(u)\n }\n const out = new Uint8Array(n)\n let at = 0\n for (const p of parts) {\n out.set(p, at)\n at += p.length\n }\n return out\n}\n\n/**\n * Read a media element's source, run in the page on the element the\n * step's selector matched through the locator engine: its `currentSrc`\n * (what it is actually playing), else its `src`, else the attribute; ''\n * while it has none yet. Self-contained, since it is serialized into the\n * page.\n */\nexport const readMediaSource = (el: RecorderMediaElement): string =>\n el.currentSrc || el.src || el.getAttribute('src') || ''\n\n/**\n * The expression that fetches a URL inside the page, for what the page\n * alone can read (a `blob:` or a `data:` source): base64 and the type, or\n * an error in words. Same-origin requests carry the page's cookies.\n */\nexport function fetchInPageScript(url: string): string {\n return `(async () => {\n try {\n const res = await fetch(${JSON.stringify(url)}, { credentials: 'include' });\n if (!res.ok) return { error: 'answered ' + res.status };\n const buf = new Uint8Array(await res.arrayBuffer());\n let bin = '';\n for (let i = 0; i < buf.length; i += 0x8000) bin += String.fromCharCode.apply(null, buf.subarray(i, i + 0x8000));\n return { b64: btoa(bin), type: res.headers.get('content-type') || '' };\n } catch (e) {\n return { error: String((e && e.message) || e) };\n }\n})()`\n}\n","/**\n * The recorder — a browser drives the action script while:\n * - CDP Page.startScreencast collects JPEG frames (epoch-timestamped;\n * hold-last-frame gaps are filled at encode time), and\n * - every dispatched input is logged as a CursorEvent (the synthesized track:\n * exact coords, exact times, fresh element rects — no capture needed).\n *\n * The MECHANISM, host-free (AN4): the browser arrives as a structural driver\n * (a launched Node Playwright browser from the CLI, a connected\n * @cloudflare/playwright browser from the fleet), frames leave through a\n * sink, the platform and the setup env are handed in, and nothing here\n * touches a filesystem or a process. The CLI's `recordTake` wraps this with\n * a take directory; the fleet's consumer wraps it with R2. Both produce the\n * same events, meta and frame index for the same script.\n */\nimport type {\n FrameSink,\n OutputSink,\n RecorderBrowser,\n RecorderClock,\n RecorderContext,\n} from './driver'\nimport { realSleep } from './driver'\nimport { capReached, cappedLine, clampWait } from './cap'\nimport {\n PRESS_HOLD_MS,\n PRESS_LEAD_MS,\n SCROLL_SETTLE_MS,\n TRAILING_HOLD_MS,\n askedMs,\n deadLine,\n deadTime,\n deadWarns,\n holdLeftMs,\n settleVerdict,\n clockMotion,\n clockTyping,\n paceLine,\n paceReport,\n pointerTravelMs,\n scrollTravelMs,\n settleMs,\n} from './pace'\nimport type { DeadReport, PaceReport, StepPace } from './pace'\nimport type {\n CursorEvent,\n RecordingMeta,\n RecordingOutput,\n RecordingSkip,\n Rect,\n StepSpan,\n} from '@vosjs/studio-core'\nimport { WALL_PROBE } from './wall'\nimport { EXPOSURE_PROBE, ExposureLog, maskInitScript } from './exposure'\nimport { SetupError, runSetup } from './setup'\nimport { TakeClock } from './takeClock'\nimport { PageErrorLog } from './pageErrors'\nimport type { PageError } from './pageErrors'\nimport {\n AWAIT_POLL_S,\n AWAIT_TIMEOUT_S,\n DOWNLOAD_TIMEOUT_S,\n EXPECT_TIMEOUT_S,\n guardVerdict,\n} from './actions'\nimport type { ActionsFile } from './actions'\nimport {\n conditionMiss,\n domSettled,\n pollCondition,\n sayCondition,\n sayDuration,\n} from './waits'\nimport type { PollResult, WaitCondition } from './waits'\nimport {\n OUTPUT_MAX_BYTES,\n readMediaSource,\n fetchInPageScript,\n nameFromUrl,\n outputName,\n readAllBytes,\n} from './outputs'\n\n/** How often an `expect` looks, in ms: on camera, so a beat, not a poll. */\nconst EXPECT_EVERY_MS = 100\n/** How long a `download` src waits for its element to have a source. */\nconst SRC_WAIT_MS = 8000\n/** How often a long `await` says it is still waiting, in ms. */\nexport const AWAIT_HEARTBEAT_MS = 30_000\n/** An `await` that held sooner than this cut nothing: no skip, no segment split. */\nexport const MIN_SKIP_MS = 250\n\n/** How long a `read` waits for its element after the step settled. */\nconst READ_WAIT_MS = 1500\n/** The most a step's `read` keeps: a payload, never a page. */\nconst READ_MAX_CHARS = 2048\n\n/**\n * The headers a request carries, or null to leave it alone: a job's\n * headers (a preview's bypass token) go to the ORIGIN the take is of and\n * nowhere else, since the recorded page embeds whatever third parties it\n * likes and a redirect can land anywhere.\n */\nexport function headersFor(\n requestUrl: string,\n entryUrl: string,\n headers: Record<string, string>,\n): Record<string, string> | null {\n try {\n return new URL(requestUrl).origin === new URL(entryUrl).origin\n ? headers\n : null\n } catch {\n return null\n }\n}\n\nasync function applyHeaders(\n context: RecorderContext,\n headers: Record<string, string>,\n entryUrl: string,\n log: (msg: string) => void,\n): Promise<void> {\n if (!context.route) {\n await context.setExtraHTTPHeaders(headers)\n log(' (this browser scopes no headers: they ride every request)')\n return\n }\n await context.route('**/*', async (route) => {\n const req = route.request()\n const scoped = headersFor(req.url(), entryUrl, headers)\n await route.continue(\n scoped ? { headers: { ...req.headers(), ...scoped } } : undefined,\n )\n })\n}\n\n/** A page URL as a take keeps it: origin and path, never a query or a hash. */\nexport function publicUrl(u: string): string {\n try {\n const x = new URL(u)\n return `${x.origin}${x.pathname}`\n } catch {\n return ''\n }\n}\nimport type { Arrival, WallVerdict } from './wall'\n\nexport interface FrameRec {\n file: string\n /** ms since t0 */\n tMs: number\n}\n\nexport interface SkippedStep {\n /** index into actions.steps */\n step: number\n id?: string\n do: string\n selector: string\n /** why, when it is not a selector that never appeared: an expect that never held, a download that never came */\n reason?: string\n}\n\n/** A click whose target was disabled when it was pressed: the press happened, and likely did nothing. */\nexport interface DisabledClick {\n step: number\n id?: string\n selector: string\n}\n\n/** An `await` that timed out with `onTimeout: \"fail\"`: the take stopped there. */\nexport interface StoppedTake {\n step: number\n id?: string\n reason: string\n}\n\n/** Thrown before anything is captured: a guarded step the command did not confirm, a download with nowhere to land. */\nexport class RecordRefusedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'RecordRefusedError'\n }\n}\n\n/** A stretch with no screencast frames — the page pixels did not change. */\nexport interface FreezeSpan {\n /** seconds into the take */\n from: number\n to: number\n ms: number\n}\n\nexport interface RecordResult {\n events: CursorEvent[]\n frames: FrameRec[]\n meta: RecordingMeta\n /** The take's pace: what the script asked, what the gestures added, what the page cost. */\n pace: PaceReport\n /** steps whose selector never became visible — the take continued without them. */\n skipped: SkippedStep[]\n /** the initial goto never reached networkidle (recording proceeded anyway). */\n navTimeout: boolean\n /** A wall the caller let through; null when the recorder landed where it was asked. */\n wall: WallVerdict | null\n /** Sensitive-looking text seen in the frame (kind + place, never the string). */\n exposures: NonNullable<RecordingMeta['exposures']>\n /** The script's masks with how many elements each reached; hits 0 hid nothing. */\n masks: NonNullable<RecordingMeta['masks']>\n /**\n * Smoothness telemetry: stretches ≥400ms with no visual change. Frozen\n * footage is the #1 enemy of a smooth product video — either the flow should\n * keep motion in frame (animate, hover a preview, scroll) or the doc should\n * trim/speed through these. freezePct = share of the take that is frozen.\n */\n freezes: FreezeSpan[]\n freezePct: number\n /**\n * The smoothness WARNING: still footage under a parked cursor past the\n * beat it takes to read what changed, per step (`deadTime`). A still page\n * being read is content; this is the part of a hold nobody is reading.\n */\n dead: DeadReport\n /** The take reached --max-duration and stopped there; later steps did not run. */\n capped: boolean\n /** Clicks pressed on a disabled target (reported; `--strict` fails on them). */\n disabled: DisabledClick[]\n /** The ids of the guarded steps this take pressed, because the command named them. */\n confirmed: string[]\n /** The cuts `await` steps made (also `meta.skips`). */\n skips: RecordingSkip[]\n /** The files `download` steps kept (also `meta.outputs`). */\n outputs: RecordingOutput[]\n /** An `await` timed out and the take stopped there; null when it ran to the end. */\n stopped: StoppedTake | null\n /** The page's own console errors, each distinct one with its full text and how often it came. */\n pageErrors: PageError[]\n /** The actions as recorded, `url` resolved: what a take directory writes back. */\n actions: ActionsFile\n}\n\nexport interface RecordOpts {\n /** Stop the capture at this many seconds (the hosted cap). */\n maxDurationSeconds?: number\n /**\n * Path to a Playwright storage state (cookies + origin storage), so the\n * recorder drives a SIGNED-IN product. A demo of anything behind a login\n * needs it, and a sign-in form cannot always be scripted (an emailed code,\n * an SSO hop). Export one from a real browser, or with\n * `context.storageState({ path })`.\n */\n storageState?: string\n /**\n * REHEARSE the flow: every step runs against the real page, in order,\n * because a later selector usually exists only after an earlier click. But\n * nothing is captured (no screencast, no frames), nothing is written, the\n * pointer lands instead of travelling and every pause is cut to a beat, so\n * a script that misses a selector says so in seconds instead of after a\n * full real-time take and its encode. Selector lookups keep their whole\n * timeout, so a miss here is a miss in the take.\n */\n dryRun?: boolean\n /**\n * Called once the first navigation has settled, BEFORE a frame is captured.\n * The caller judges the wall here and only then prepares the take\n * directory, so a take refused at a sign-in never clears the footage a\n * re-record would have replaced. A throw closes the context and propagates.\n */\n onArrival?: (\n arrival: Arrival,\n ) => Promise<WallVerdict | null | void> | WallVerdict | null | void\n /** Extra request headers on every request (`--header name=value`). */\n headers?: Record<string, string>\n /**\n * A ready-made context to record IN, instead of one made from `browser`:\n * `--session <name>`, a persistent profile the person signed in to. The\n * recorder still sizes the viewport and closes it at the end.\n */\n context?: RecorderContext\n /**\n * The environment a setup's `{ env }` texts resolve from: the shell's\n * for the CLI, the job's own map on the fleet. Absent means no env at\n * all, so a setup that reads one fails in words.\n */\n env?: Record<string, string | undefined>\n /** The platform the take is recorded on, for `meta.platform`. */\n platform?: RecordingMeta['platform']\n /**\n * The ids of the guarded steps this recording may press (`--confirm`).\n * A guarded step not named here refuses the take before anything is\n * captured; a rehearsal hovers every guarded step and presses none.\n */\n confirm?: readonly string[]\n /**\n * Where a `download` step's file goes. A host that hands in none cannot\n * keep a download: such a script is refused before anything is captured.\n * A rehearsal fetches the file and keeps nothing.\n */\n outputs?: OutputSink\n /** Print every page error whole, each time it comes; by default one cut line per distinct error. */\n verbose?: boolean\n /**\n * Structured progress for a host that reports it (the CLI's `--json`):\n * an `await`'s start, a heartbeat while it waits, and its end.\n */\n onEvent?: (event: Record<string, unknown>) => void\n /** How often a long `await` reports it is still waiting (default 30 s). */\n awaitHeartbeatMs?: number\n}\n\n/** The longest any pause lasts in a rehearsal. */\nconst DRY_PAUSE_MS = 120\n\n/**\n * The expression a scroll tick evaluates: move the first scrollable\n * ancestor of the element under the cursor by `dy`, else the window, the\n * container a wheel at that point would have moved. A string, so no host\n * helper (`__name`) has to exist in the page.\n */\nexport function scrollByScript(x: number, y: number, dy: number): string {\n return `(() => {\n let el = document.elementFromPoint(${Math.round(x)}, ${Math.round(y)});\n while (el && el !== document.body && el !== document.documentElement) {\n const cs = getComputedStyle(el);\n if (/(auto|scroll)/.test(cs.overflowY) && el.scrollHeight > el.clientHeight + 1) {\n el.scrollBy(0, ${dy});\n return 'el';\n }\n el = el.parentElement;\n }\n window.scrollBy(0, ${dy});\n return 'window';\n})()`\n}\n\n/** Minimal JPEG SOF parse for real encoded dimensions. */\nexport function jpegDims(buf: Uint8Array): { w: number; h: number } | null {\n const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength)\n let i = 2\n while (i < buf.length - 9) {\n if (buf[i] !== 0xff) return null\n const marker = buf[i + 1]\n const len = view.getUint16(i + 2)\n if (\n marker >= 0xc0 &&\n marker <= 0xcf &&\n marker !== 0xc4 &&\n marker !== 0xc8 &&\n marker !== 0xcc\n ) {\n return { h: view.getUint16(i + 5), w: view.getUint16(i + 7) }\n }\n i += 2 + len\n }\n return null\n}\n\n/** Base64 to bytes without Node's Buffer, so the fleet's isolate runs it too. */\nexport function base64Bytes(data: string): Uint8Array {\n const bin = atob(data)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nexport async function recordTake(\n browser: RecorderBrowser,\n url: string,\n actions: ActionsFile,\n sink: FrameSink,\n log: (msg: string) => void,\n opts: RecordOpts = {},\n): Promise<RecordResult> {\n const dry = opts.dryRun === true\n const sleep = dry\n ? (ms: number) => realSleep(Math.min(ms, DRY_PAUSE_MS))\n : realSleep\n // A rehearsal is not held to the recording cap: its clock is not the take's.\n const maxSeconds = dry ? Infinity : (opts.maxDurationSeconds ?? Infinity)\n // Refused BEFORE a browser context exists: a step that spends something\n // real runs only when the command names it, and a download needs a place\n // to land. A rehearsal presses no guarded step and keeps no file.\n if (!dry) {\n const guard = guardVerdict(actions, opts.confirm ?? [])\n if (!guard.ok) throw new RecordRefusedError(guard.message)\n const download = actions.steps.findIndex((s) => s.do === 'download')\n if (download >= 0 && !opts.outputs)\n throw new RecordRefusedError(\n `steps[${download}] is a download, and this recorder has nowhere to keep a file. Nothing was recorded.`,\n )\n }\n const vw = actions.viewport?.width ?? 1280\n const vh = actions.viewport?.height ?? 720\n const context =\n opts.context ??\n (await browser.newContext({\n viewport: { width: vw, height: vh },\n deviceScaleFactor: 1,\n ...(opts.storageState ? { storageState: opts.storageState } : {}),\n }))\n if (opts.headers && Object.keys(opts.headers).length)\n await applyHeaders(context, opts.headers, url, log)\n // Masks go in as an init script, so they are in force at document start on\n // every navigation: the real value never reaches a painted frame.\n const masks = actions.mask ?? []\n if (masks.length) await context.addInitScript(maskInitScript(masks))\n const exposureLog = new ExposureLog(masks)\n const page = await context.newPage()\n // What the frame shows, read after each step. A few ms in the page; a scan\n // that fails (mid-navigation) is skipped, never fatal.\n const scanExposures = async (step: number) => {\n const scan = await page.evaluate(EXPOSURE_PROBE).catch(() => null)\n exposureLog.add(step, scan as Parameters<ExposureLog['add']>[1])\n }\n // One line per distinct page error, cut short; repeats are counted and\n // said once at the end (pageErrors.ts). The full text rides the result.\n const pageErrors = new PageErrorLog(opts.verbose === true)\n page.on('console', (m) => {\n if (m.type() !== 'error') return\n const line = pageErrors.add(m.text())\n if (line) log(line)\n })\n\n log(`goto ${url}`)\n let navTimeout = false\n let response = await page\n .goto(url, { waitUntil: 'networkidle', timeout: 45000 })\n .catch(() => {\n navTimeout = true\n log(' (networkidle timeout — continuing)')\n return null\n })\n await sleep(800) // hydration settle\n\n // The setup: off camera, before the wall is judged, because a setup that\n // signs in is exactly what makes the wall not there. A selector that never\n // appears fails the take here, in words, before anything is captured.\n const setup = actions.setup ?? []\n if (setup.length) {\n log(`setup: ${setup.length} step(s), off camera`)\n const result = await runSetup(page, setup, {\n sleep: realSleep,\n env: opts.env ?? {},\n })\n for (const line of result.lines) log(` ${line}`)\n if (result.failed) {\n await context.close().catch(() => {})\n throw new SetupError(result.failed)\n }\n // Back to the page the take is OF, signed in and past the banners.\n log(`goto ${url} (after setup)`)\n response = await page\n .goto(url, { waitUntil: 'networkidle', timeout: 45000 })\n .catch(() => null)\n await sleep(800)\n }\n\n // A wall the caller let through (--allow-wall, or a soft one without\n // --strict) rides the take's meta, so a digest made later still says so.\n let wall: WallVerdict | null = null\n if (opts.onArrival) {\n const seen = (await page.evaluate(WALL_PROBE).catch(() => null)) as Pick<\n Arrival,\n 'passwordFields' | 'newPasswordField' | 'oneTimeCodeField'\n > | null\n try {\n wall =\n (await opts.onArrival({\n askedUrl: url,\n landedUrl: page.url(),\n ...(response ? { status: response.status() } : {}),\n passwordFields: seen?.passwordFields ?? 0,\n newPasswordField: seen?.newPasswordField ?? false,\n oneTimeCodeField: seen?.oneTimeCodeField ?? false,\n })) ?? null\n } catch (e) {\n await context.close().catch(() => {})\n throw e\n }\n }\n\n await scanExposures(-1)\n\n const cdp = await context.newCDPSession(page)\n const frames: FrameRec[] = []\n let frameIdx = 0\n let t0 = 0\n // The take's clock runs only while the camera does: an `await` stops the\n // capture and polls off camera, and its wall time is taken out of the\n // footage clock, the cursor clock and every frame stamp alike, through\n // ONE mapping (takeClock.ts), which also keeps frame times strictly\n // increasing. Made for real once t0 is stamped below.\n let takeClock = new TakeClock(0)\n // Written from the screencast callback, so the read below does not\n // narrow: a box, not a plain local.\n const first: { dims: { w: number; h: number } | null } = { dims: null }\n // Frames are handed to the sink in order; the chain keeps a slow sink\n // (R2) from reordering them and is awaited before the meta is built.\n let sinkChain: Promise<void> = Promise.resolve()\n if (!dry)\n cdp.on('Page.screencastFrame', (ev) => {\n // Every frame is acked, kept or not, or the screencast stalls.\n cdp\n .send('Page.screencastFrameAck', { sessionId: ev.sessionId })\n .catch(() => {})\n const tsMs = ev.metadata.timestamp\n ? ev.metadata.timestamp * 1000\n : Date.now()\n // Placed by when it was captured; null = not later than the last\n // frame kept, so older pixels than the footage already shows.\n const tMs = takeClock.placeFrame(tsMs)\n if (tMs === null) return\n const file = `frame-${String(frameIdx++).padStart(5, '0')}.jpg`\n const bytes = base64Bytes(ev.data)\n if (!first.dims) first.dims = jpegDims(bytes)\n frames.push({ file, tMs })\n sinkChain = sinkChain.then(() => sink.frame(file, bytes)).catch(() => {})\n })\n\n const screencast = {\n format: 'jpeg',\n quality: 90,\n maxWidth: vw,\n maxHeight: vh,\n everyNthFrame: 1,\n }\n t0 = Date.now()\n takeClock = new TakeClock(t0)\n if (!dry) await cdp.send('Page.startScreencast', screencast)\n\n const events: CursorEvent[] = []\n const cur = { x: 48, y: 48 }\n const now = () => takeClock.footageMs(Date.now())\n\n /**\n * Run `fn` OFF CAMERA: the screencast stops, nothing is emitted, and on\n * the way back the wall time it took is taken out of the take's clock,\n * so the footage runs straight from the moment before to the moment\n * after. Returns the cut's footage time and the wall time spent.\n */\n const offCamera = async <T>(\n fn: () => Promise<T>,\n ): Promise<{ out: T; at: number; ms: number }> => {\n // In a rehearsal the clock pauses too, so `at` and `ms` read the same.\n const at = takeClock.pause(Date.now())\n if (!dry) await cdp.send('Page.stopScreencast').catch(() => {})\n const out = await fn()\n const ms = takeClock.resume(Date.now())\n if (!dry) await cdp.send('Page.startScreencast', screencast).catch(() => {})\n return { out, at, ms }\n }\n const emit = (e: Omit<CursorEvent, 't'>) => events.push({ t: now(), ...e })\n\n await page.mouse.move(cur.x, cur.y)\n emit({ x: cur.x, y: cur.y, type: 'move' })\n\n const clock: RecorderClock = { now: () => Date.now(), sleep }\n // The pointer's travel is driven by the CLOCK (pace.ts): its position is\n // a function of the elapsed time and it ends when the travel's duration\n // has elapsed, so a page that answers each mouse.move slowly costs\n // samples, never seconds. Every sample the page took is a cursor event\n // at its real time, which is what the smoothing and the follow read.\n const moveTo = async (tx: number, ty: number) => {\n const dist = Math.hypot(tx - cur.x, ty - cur.y)\n const from = { ...cur }\n await clockMotion(\n dry ? 0 : pointerTravelMs(dist),\n async (u) => {\n cur.x = from.x + (tx - from.x) * u\n cur.y = from.y + (ty - from.y) * u\n await page.mouse.move(cur.x, cur.y)\n emit({ x: Math.round(cur.x), y: Math.round(cur.y), type: 'move' })\n },\n clock,\n )\n }\n\n /**\n * The words under a selector once a step has settled: trimmed,\n * whitespace collapsed, bounded. Null when nothing matches in time, which\n * the step line says; a missing payload never fails a take.\n */\n const readText = async (\n pg: typeof page,\n selector: string,\n ): Promise<string | null> => {\n try {\n await pg\n .locator(selector)\n .first()\n .waitFor({ state: 'visible', timeout: READ_WAIT_MS })\n // The probe is a string, the one evaluate shape every driver shares.\n // A field's words are its VALUE (what was typed), which textContent\n // never carries; everything else keeps its textContent.\n const raw = await pg.evaluate<string>(\n `(() => { const el = document.querySelector(${JSON.stringify(selector)}); if (!el) return ''; if ('value' in el && typeof el.value === 'string' && /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName)) return el.value; return el.textContent || '' })()`,\n )\n const words = raw.replace(/\\s+/g, ' ').trim()\n return words ? words.slice(0, READ_MAX_CHARS) : null\n } catch {\n return null\n }\n }\n const boxOf = async (selector: string): Promise<Rect | null> => {\n const loc = page.locator(selector).first()\n try {\n await loc.waitFor({ state: 'visible', timeout: 8000 })\n const before = await page\n .evaluate(() => [window.scrollX, window.scrollY])\n .catch(() => [0, 0])\n await loc.scrollIntoViewIfNeeded()\n const after = await page\n .evaluate(() => [window.scrollX, window.scrollY])\n .catch(() => before)\n // A lookup that scrolled the page lets the scroll land; one that\n // did not costs nothing.\n if (before[0] !== after[0] || before[1] !== after[1])\n await sleep(SCROLL_SETTLE_MS)\n const bb = await loc.boundingBox()\n if (!bb) return null\n return { x: bb.x, y: bb.y, w: bb.width, h: bb.height }\n } catch {\n log(` (selector not found, skipping: ${selector})`)\n return null\n }\n }\n\n /**\n * A media element's source, through the page's locator engine like every\n * other step's selector (`video >> nth=0`, `text=…`, `role=…` all hold):\n * waited for until attached (an `<audio>` is never visible), then read\n * until it has a source. Null when no element matches in time, '' when\n * one does and has no source yet.\n */\n const srcOf = async (selector: string): Promise<string | null> => {\n const deadline = Date.now() + SRC_WAIT_MS\n const loc = page.locator(selector).first()\n try {\n await loc.waitFor({ state: 'attached', timeout: SRC_WAIT_MS })\n } catch {\n return null\n }\n for (;;) {\n const v = await loc.evaluate(readMediaSource).catch(() => '')\n if (v || Date.now() >= deadline) return v\n await realSleep(200)\n }\n }\n\n /**\n * Fetch a source with the page's own request context (its cookies), or\n * inside the page for what only the page can read (a `blob:`, a\n * `data:`). An address that fails is said without its query.\n */\n const fetchSource = async (\n src: string,\n ): Promise<{\n bytes: Uint8Array\n suggested: string\n contentType?: string\n }> => {\n const abs = new URL(src, page.url()).href\n const suggested = nameFromUrl(abs)\n if (page.request && /^https?:/i.test(abs)) {\n const res = await page.request.get(abs, {\n timeout: DOWNLOAD_TIMEOUT_S * 1000,\n })\n if (!res.ok())\n throw new Error(\n `fetching ${publicUrl(abs) || 'the source'} answered ${res.status()}`,\n )\n const bytes = await res.body()\n if (bytes.length > OUTPUT_MAX_BYTES)\n throw new Error(\n `the file is larger than ${OUTPUT_MAX_BYTES / 1024 / 1024} MB`,\n )\n const type = res.headers()['content-type']?.split(';')[0].trim()\n return { bytes, suggested, ...(type ? { contentType: type } : {}) }\n }\n const r = await page.evaluate<{\n b64?: string\n type?: string\n error?: string\n } | null>(fetchInPageScript(abs))\n if (!r || r.error || r.b64 === undefined)\n throw new Error(\n `fetching the source in the page failed: ${r?.error ?? 'no answer'}`,\n )\n const type = r.type?.split(';')[0].trim()\n return {\n bytes: base64Bytes(r.b64),\n suggested,\n ...(type ? { contentType: type } : {}),\n }\n }\n\n const clickAt = async (rect: Rect) => {\n await moveTo(rect.x + rect.w / 2, rect.y + rect.h / 2)\n await sleep(PRESS_LEAD_MS)\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button: 0,\n rect,\n })\n await page.mouse.down()\n await sleep(PRESS_HOLD_MS)\n await page.mouse.up()\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'up',\n button: 0,\n rect,\n })\n }\n\n /**\n * Wait for the page to settle after a press, reading the screencast:\n * returns ms since the last change (null when nothing changed). A dry\n * run has no frames and settles at once.\n */\n const waitSettled = async (): Promise<number | null> => {\n if (dry) return null\n const pressAt = now()\n const before = frames.length\n for (;;) {\n const t = now()\n const last = frames.length > before ? frames[frames.length - 1] : null\n const sinceChange = last ? t - last.tMs : null\n if (settleVerdict({ sincePress: t - pressAt, sinceChange }) === 'settled')\n return sinceChange\n await sleep(40)\n }\n }\n\n const skipped: SkippedStep[] = []\n // The step timeline: when each step ran, in source seconds — what\n // lets a cut anchored to steps re-time onto a NEW recording of the same\n // script (`vos plan --reuse`). Every step that STARTED is recorded; a\n // skipped selector is marked, never silently absent.\n const stepSpans: StepSpan[] = []\n const paces: StepPace[] = []\n const disabled: DisabledClick[] = []\n const confirmed: string[] = []\n const skips: RecordingSkip[] = []\n const outputs: RecordingOutput[] = []\n const outputNames = new Set<string>()\n let stopped: StoppedTake | null = null\n // The last guarded step a rehearsal left unpressed: what follows it and\n // waits for its result (an expect, an await) cannot see that result.\n let unpressedGuard: number | null = null\n let capped = false\n for (const [stepIdx, step] of actions.steps.entries()) {\n // The cap is checked between steps (a step is one gesture and runs\n // whole); only a wait is cut short, since it is the one step that can\n // sit past the cap on its own.\n if (capReached(now(), maxSeconds)) {\n capped = true\n break\n }\n const stepStart = now()\n // The gesture the recorder adds by design around this step's ask: the\n // pointer's travel, the press, the settle. Everything else the step's\n // wall time holds is the page's (a slow round trip, a scroll landing).\n let gestureMs = 0\n const gesture = async <T>(fn: () => Promise<T>): Promise<T> => {\n const t = now()\n const out = await fn()\n gestureMs += now() - t\n return out\n }\n const skippedBefore = skipped.length\n // A step that changes the page's URL (a click that navigates, the\n // wait that lets the load land) is marked: the planner proposes a\n // transition at the page change.\n const urlBefore = page.url()\n // The selector's box at the gesture: kept on the step so a layer can\n // name what the step touched (`overlays[].pin.step`).\n let stepRect: Rect | null = null\n // What this step adds to its `meta.steps` entry beyond the common fields.\n const extra: Partial<StepSpan> = {}\n const tag = `#${stepIdx}${step.id ? ` ${step.id}` : ''}`\n const skip = (selector: string, reason?: string) => {\n skipped.push({\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n do: step.do,\n selector,\n ...(reason ? { reason } : {}),\n })\n if (reason) extra.reason = reason\n }\n if (step.guard) extra.guard = step.guard\n /**\n * A rehearsal never presses a step that spends: the pointer goes to its\n * target, so the selector is proven, and the press is left out. True\n * when the step was rehearsed that way and its case must stop there.\n */\n const rehearseGuard = async (sel: string | undefined): Promise<boolean> => {\n if (!step.guard || !dry) return false\n const rect = sel ? await boxOf(sel) : null\n stepRect = rect\n if (sel && !rect) skip(sel)\n else {\n if (rect)\n await gesture(() => moveTo(rect.x + rect.w / 2, rect.y + rect.h / 2))\n log(\n `${tag}: guarded (${step.guard}), ${rect ? 'hovered' : 'left alone'}, not pressed`,\n )\n }\n unpressedGuard = stepIdx\n return true\n }\n /**\n * In a rehearsal, an expect or an await after an unpressed guarded step\n * waits for a result that cannot come: it is said and counted as\n * resolved, never waited out. True when the case must stop there.\n */\n const notWaited = (): boolean => {\n if (!dry || unpressedGuard === null) return false\n extra.followsGuard = unpressedGuard\n log(\n `${tag} ${step.do}: not waited: it follows #${unpressedGuard} (guarded, not pressed)`,\n )\n return true\n }\n switch (step.do) {\n case 'wait':\n await sleep(clampWait(step.ms, now(), maxSeconds))\n break\n case 'move':\n await moveTo(step.x, step.y)\n break\n case 'hover': {\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (rect) {\n await gesture(() => moveTo(rect.x + rect.w / 2, rect.y + rect.h / 2))\n log(`hover ${step.selector}`)\n await sleep(step.ms ?? 700) // parked cursor = dwell signal for the planner\n } else\n skipped.push({ step: stepIdx, do: step.do, selector: step.selector })\n break\n }\n case 'click': {\n if (await rehearseGuard(step.selector)) break\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (rect) {\n // A press on a disabled control still happens (the flow is the\n // flow), and is reported: it most likely did nothing, and a take\n // built on it shows a button that never answered.\n const enabled = await page\n .locator(step.selector)\n .first()\n .isEnabled({ timeout: 1000 })\n .catch(() => true)\n if (!enabled) {\n disabled.push({\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n selector: step.selector,\n })\n log(\n ` (${tag} click: ${step.selector} is disabled; pressed anyway)`,\n )\n }\n await gesture(() => clickAt(rect))\n log(`click ${step.selector}`)\n // The settle is the recorder's (watched on the screencast); the\n // hold is the author's, from the page's last change.\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\n } else\n skipped.push({ step: stepIdx, do: step.do, selector: step.selector })\n break\n }\n case 'type': {\n if (await rehearseGuard(step.selector)) break\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (rect) {\n // The click is what opens the typing zoom on the field. A step that\n // only finishes earlier typing (a submitting Enter) passes\n // focus:false: the field is already focused and a second click\n // rings a click effect on empty space beside the text.\n if (step.focus !== false) await gesture(() => clickAt(rect))\n // Where the caret stands before the first character: a click\n // lands it where the pointer hit, and a code editor line is\n // typed at its end. `replace` selects the value so the typing\n // replaces it (a form that opens filled in).\n if (step.at === 'end') await page.keyboard.press('End')\n else if (step.at === 'start') await page.keyboard.press('Home')\n if (step.replace) await page.keyboard.press('ControlOrMeta+a')\n // Typing-activity pings (TZ): one per ~350ms while characters land,\n // plus one at completion so the planner's hold starts at the true\n // typing end. When-and-where only — a ping never carries the text.\n // ~0.6s+ of typing earns the zoom (TYPING_MIN_DUR + ping floor), so\n // pace delayMs like a person for a camera moment, not a paste.\n const delay = step.delayMs ?? 40\n const ping = () =>\n emit({\n x: Math.round(rect.x + rect.w / 2),\n y: Math.round(rect.y + rect.h / 2),\n type: 'key',\n rect,\n })\n let lastPing = -Infinity\n await clockTyping(\n [...step.text],\n delay,\n async (ch) => {\n if (now() - lastPing >= 350) {\n lastPing = now()\n ping()\n }\n await page.keyboard.type(ch)\n },\n clock,\n )\n ping()\n log(`type ${step.text.length} chars into ${step.selector}`)\n await gesture(() => sleep(settleMs(step)))\n } else\n skipped.push({ step: stepIdx, do: step.do, selector: step.selector })\n break\n }\n case 'press': {\n if (await rehearseGuard(step.selector)) break\n // One named key, recorded as a typing ping (when-and-where only,\n // never the key) so the planner's typing session holds through a\n // submitting Enter or an Escape that closes what a click opened.\n // No click: the field is as the flow left it. With a selector the\n // ping (and the step's rect) is that element's; without, the\n // pointer's.\n let rect: Rect | null = null\n if (step.selector) {\n rect = await boxOf(step.selector)\n stepRect = rect\n if (!rect) {\n skipped.push({\n step: stepIdx,\n do: step.do,\n selector: step.selector,\n })\n break\n }\n }\n emit({\n x: Math.round(rect ? rect.x + rect.w / 2 : cur.x),\n y: Math.round(rect ? rect.y + rect.h / 2 : cur.y),\n type: 'key',\n ...(rect ? { rect } : {}),\n })\n await page.keyboard.press(step.key)\n log(`press ${step.key}`)\n const sinceChange = await gesture(() => waitSettled())\n await sleep(holdLeftMs(settleMs(step), sinceChange))\n break\n }\n case 'scroll': {\n // The scroll travels by the clock, like the pointer, and each tick\n // moves the scroll container under the cursor INSIDE the page\n // (`Runtime.evaluate` returns at once). Not wheel events: CDP's\n // wheel dispatch waits for the renderer to handle the event, and a\n // tab that paints no frame for a small delta, which a fleet browser's\n // background tab is, never answers, so a clock-driven wheel stalled\n // there for good. And not requestAnimationFrame or an in-page timer,\n // which such a tab never fires or throttles to once a second. The\n // screencast captures whatever the compositor paints between ticks,\n // and a layout moved by scrollTo is never a torn composite.\n const total = Math.abs(step.dy)\n const dir = Math.sign(step.dy)\n const sent = { px: 0 }\n await gesture(() =>\n clockMotion(\n dry ? 0 : scrollTravelMs(total),\n async (u) => {\n const target = Math.round(total * u)\n const delta = target - sent.px\n if (delta <= 0) return\n sent.px = target\n await page\n .evaluate(scrollByScript(cur.x, cur.y, dir * delta))\n .catch(() => undefined)\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'scroll',\n })\n },\n clock,\n ),\n )\n await gesture(() => sleep(settleMs(step)))\n break\n }\n case 'drag': {\n // Start point: selector center when given, else explicit coords.\n let start: { x: number; y: number } | null = null\n let rect: Rect | undefined\n if (step.selector) {\n const box = await boxOf(step.selector)\n stepRect = box\n if (box) {\n rect = box\n start = { x: box.x + box.w / 2, y: box.y + box.h / 2 }\n } else {\n skipped.push({\n step: stepIdx,\n do: step.do,\n selector: step.selector,\n })\n break\n }\n } else if (typeof step.x === 'number' && typeof step.y === 'number') {\n start = { x: step.x, y: step.y }\n }\n if (!start) break\n await gesture(() => moveTo(start.x, start.y))\n await gesture(() => sleep(PRESS_LEAD_MS))\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'down',\n button: 0,\n rect,\n })\n await page.mouse.down()\n await gesture(() => sleep(PRESS_HOLD_MS))\n // The drag is the ask: `ms` of travel by the clock, however slowly\n // the page answers each move (a slider re-rendering per sample).\n const dur = step.ms ?? 700\n const from = { ...cur }\n await clockMotion(\n dur,\n async (u) => {\n cur.x = from.x + (step.tx - from.x) * u\n cur.y = from.y + (step.ty - from.y) * u\n await page.mouse.move(cur.x, cur.y)\n emit({ x: Math.round(cur.x), y: Math.round(cur.y), type: 'move' })\n },\n clock,\n )\n await gesture(() => sleep(settleMs({ do: 'drag' })))\n await page.mouse.up()\n emit({\n x: Math.round(cur.x),\n y: Math.round(cur.y),\n type: 'up',\n button: 0,\n rect,\n })\n log(\n `drag ${step.selector ?? `${start.x},${start.y}`} → ${step.tx},${step.ty}`,\n )\n await sleep(400)\n break\n }\n case 'expect': {\n if (notWaited()) break\n // A check, on camera, with no cursor move and no input: the page is\n // read until the condition holds or the step's time runs out.\n const cond: WaitCondition = step\n const timeoutMs = (step.timeout ?? EXPECT_TIMEOUT_S) * 1000\n const res = await pollCondition(page, cond, {\n timeoutMs,\n everyMs: EXPECT_EVERY_MS,\n sleep: realSleep,\n })\n if (res.ok) log(`expect ${sayCondition(cond)}: holds`)\n else {\n const reason = conditionMiss(cond, res.last, timeoutMs)\n skip(step.selector ?? step.gone ?? step.text ?? '', reason)\n log(` (${tag} expect: ${reason})`)\n }\n break\n }\n case 'await': {\n if (notWaited()) break\n // OFF CAMERA: the capture stops, the page is polled, and the take\n // resumes the moment the condition holds, so a 40-second render is\n // a cut in the footage, never 40 seconds of a spinner.\n const cond: WaitCondition = step.until\n const timeoutMs = (step.timeout ?? AWAIT_TIMEOUT_S) * 1000\n const reload = step.reload\n ? async () => {\n const opts = {\n waitUntil: 'networkidle' as const,\n timeout: Math.min(45000, timeoutMs),\n }\n await (\n page.reload ? page.reload(opts) : page.goto(page.url(), opts)\n ).catch(() => null)\n // Network quiet is not a drawn page: a list rendered from its\n // data lands after it. Let the DOM settle before the look.\n await domSettled(page, { sleep: realSleep })\n }\n : undefined\n log(`await ${sayCondition(cond)} (off camera)…`)\n const awaitEvent = {\n event: 'await',\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n }\n opts.onEvent?.({ ...awaitEvent, phase: 'start' })\n // A long wait says it is still waiting, so a host reading the\n // events is never left with minutes of silence.\n const beatMs = opts.awaitHeartbeatMs ?? AWAIT_HEARTBEAT_MS\n const waitFrom = Date.now()\n const beat = setInterval(() => {\n const elapsedMs = Date.now() - waitFrom\n opts.onEvent?.({ ...awaitEvent, phase: 'wait', elapsedMs })\n log(` still waiting, ${sayDuration(elapsedMs)} so far`)\n }, beatMs)\n let waited: { out: PollResult; at: number; ms: number }\n try {\n waited = await offCamera(() =>\n pollCondition(page, cond, {\n timeoutMs,\n everyMs: (step.poll ?? AWAIT_POLL_S) * 1000,\n sleep: realSleep,\n between: reload,\n // After a reload the condition must hold on two reads in a\n // row, or a half-built page ends the wait early.\n ...(reload ? { confirm: { reads: 2, gapMs: 500 } } : {}),\n }),\n )\n } finally {\n clearInterval(beat)\n }\n const { out, at, ms } = waited\n opts.onEvent?.({ ...awaitEvent, phase: 'end', ms, held: out.ok })\n extra.offCameraMs = ms\n if (!out.ok) extra.timedOut = true\n // A wait that held at once (the page already showed it) cut\n // nothing worth a segment: the step reports it, the footage does\n // not split on it.\n if (!dry && (ms >= MIN_SKIP_MS || !out.ok))\n skips.push({\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n at: +(at / 1000).toFixed(3),\n ms,\n ...(out.ok ? {} : { timedOut: true }),\n })\n if (out.ok) log(` held after ${sayDuration(ms)} off camera`)\n else if ((step.onTimeout ?? 'fail') === 'continue')\n log(\n ` (${tag} await: ${conditionMiss(cond, out.last, ms)}; going on, as onTimeout says)`,\n )\n else {\n stopped = {\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n reason: `${tag} await: ${conditionMiss(cond, out.last, ms)}, so the take stopped there. Raise its timeout, or set onTimeout: \"continue\" to go on without it`,\n }\n extra.reason = stopped.reason\n log(` ${stopped.reason}`)\n }\n break\n }\n case 'download': {\n // A file the page makes, kept in the take's outputs/: by the click\n // that downloads it (the press is on camera, like any click), or by\n // fetching what a media element plays with the page's own cookies.\n let got: {\n bytes: Uint8Array\n suggested: string\n contentType?: string\n } | null = null\n let reason: string | null = null\n const target = step.selector ?? step.src ?? ''\n try {\n if (step.selector !== undefined) {\n const rect = await boxOf(step.selector)\n stepRect = rect\n if (!rect) {\n skip(step.selector)\n break\n }\n if (!page.waitForEvent) {\n reason = 'this browser reports no downloads'\n } else {\n const waitMs = DOWNLOAD_TIMEOUT_S * 1000\n const arriving = page\n .waitForEvent('download', { timeout: waitMs })\n .catch(() => null)\n await gesture(() => clickAt(rect))\n log(`click ${step.selector} (download)`)\n const dl = await arriving\n if (!dl)\n reason = `no download arrived within ${sayDuration(waitMs)} of the click on '${step.selector}'`\n else {\n const stream = await dl.createReadStream()\n if (!stream) reason = 'the download failed in the browser'\n else\n got = {\n bytes: await readAllBytes(stream),\n suggested: dl.suggestedFilename(),\n // A browser download carries no headers here: the type is\n // read from the name the page gave it.\n ...typeOfName(dl.suggestedFilename()),\n }\n }\n }\n } else if (step.src !== undefined) {\n const src = await srcOf(step.src)\n if (src === null) reason = `no element matches '${step.src}'`\n else if (!src) reason = `'${step.src}' has no source to fetch`\n else got = await fetchSource(src)\n }\n } catch (e) {\n reason = e instanceof Error ? e.message : String(e)\n }\n if (got) {\n const name = outputName(\n step.as,\n got.suggested,\n `download-${stepIdx}${extForType(got.contentType)}`,\n outputNames,\n )\n outputNames.add(name)\n if (!dry) await opts.outputs?.save(name, got.bytes, got.contentType)\n outputs.push({\n step: stepIdx,\n ...(step.id ? { id: step.id } : {}),\n name,\n bytes: got.bytes.length,\n ...(got.contentType ? { contentType: got.contentType } : {}),\n })\n log(\n `download → outputs/${name} (${got.bytes.length} bytes)${dry ? ', not kept in a rehearsal' : ''}`,\n )\n } else {\n const why = reason ?? 'nothing came'\n skip(target, why)\n log(` (${tag} download: ${why})`)\n }\n break\n }\n }\n // A guarded step that ran in a recording ran because the command named it.\n if (step.guard && !dry && skipped.length === skippedBefore) {\n confirmed.push(step.id ?? String(stepIdx))\n extra.confirmed = true\n }\n const stepInfo = step as {\n id?: string\n selector?: string\n read?: string\n src?: string\n gone?: string\n until?: { selector?: string; gone?: string }\n }\n // The element the step is about: an await names what it waited on, a\n // download by src the element it fetched.\n const about =\n stepInfo.selector ??\n stepInfo.until?.selector ??\n stepInfo.until?.gone ??\n stepInfo.gone ??\n stepInfo.src\n // The take carries its payload: the page the step left (origin and\n // path, never a query or a hash) and, when the step named a `read`,\n // that element's words once the step has settled, so a layer quotes\n // the take instead of a replay of it.\n const urlAfter = publicUrl(page.url())\n const text = stepInfo.read ? await readText(page, stepInfo.read) : null\n if (stepInfo.read && text === null)\n log(` (read ${stepInfo.read}: nothing there after the step)`)\n stepSpans.push({\n step: stepIdx,\n ...(stepInfo.id ? { id: stepInfo.id } : {}),\n do: step.do,\n ...(about ? { selector: about } : {}),\n tStart: +(stepStart / 1000).toFixed(3),\n tEnd: +(now() / 1000).toFixed(3),\n ...(skipped.length > skippedBefore ? { skipped: true } : {}),\n ...(page.url() !== urlBefore ? { navigated: true } : {}),\n ...(urlAfter ? { url: urlAfter } : {}),\n ...(text !== null ? { text } : {}),\n ...(stepRect\n ? {\n rect: {\n x: +stepRect.x.toFixed(1),\n y: +stepRect.y.toFixed(1),\n w: +stepRect.w.toFixed(1),\n h: +stepRect.h.toFixed(1),\n },\n }\n : {}),\n ...extra,\n })\n paces.push({\n step: stepIdx,\n do: step.do,\n askedMs: askedMs(step as Parameters<typeof askedMs>[0]),\n gestureMs,\n wallMs: now() - stepStart,\n })\n // After the pace is taken: the scan's few ms are not the step's.\n await scanExposures(stepIdx)\n // An await that timed out with onTimeout \"fail\": the take ends here.\n if (stopped) break\n }\n if (!capped && !stopped) await sleep(TRAILING_HOLD_MS) // trailing hold\n if (capped || capReached(now(), maxSeconds)) {\n capped = true\n log(` ${cappedLine(maxSeconds)}`)\n }\n\n const durationMs = capped ? Math.min(now(), maxSeconds * 1000) : now()\n await cdp.send('Page.stopScreencast').catch(() => {})\n await sleep(200)\n const pageTitle = await page.title().catch(() => '')\n for (const line of pageErrors.repeats()) log(line)\n await context.close()\n // Every frame the screencast delivered has reached the sink.\n await sinkChain\n\n const meta: RecordingMeta = {\n dpr: 1,\n zoom: 1,\n t0,\n durationMs,\n width: vw,\n height: vh,\n fps: 30,\n hasAudio: false,\n captureWidth: first.dims?.w ?? vw,\n captureHeight: first.dims?.h ?? vh,\n captureSurface: 'tab',\n // The take keeps the address, never its query or hash, which is where\n // a token or a magic link would ride.\n pageUrl: publicUrl(url) || url,\n pageTitle,\n platform: opts.platform ?? 'linux',\n producer: 'cli',\n steps: stepSpans,\n ...(wall\n ? { wall: { kind: wall.kind, asked: wall.asked, landed: wall.landed } }\n : {}),\n ...(exposureLog.exposures().length\n ? { exposures: exposureLog.exposures() }\n : {}),\n ...(masks.length ? { masks: exposureLog.masks(masks) } : {}),\n ...(skips.length ? { skips } : {}),\n ...(outputs.length ? { outputs } : {}),\n }\n\n // Smoothness telemetry: screencast emits only on visual change, so frame\n // gaps = frozen pixels. ≥400ms reads as dead time in a product video.\n const freezes: FreezeSpan[] = []\n for (let i = 1; i < frames.length; i++) {\n const gap = frames[i].tMs - frames[i - 1].tMs\n if (gap >= 400) {\n freezes.push({\n from: +(frames[i - 1].tMs / 1000).toFixed(2),\n to: +(frames[i].tMs / 1000).toFixed(2),\n ms: gap,\n })\n }\n }\n const frozenMs = freezes.reduce((sum, f) => sum + f.ms, 0)\n const freezePct =\n durationMs > 0 ? Math.round((frozenMs / durationMs) * 100) : 0\n // The freeze share is a FACT (a workspace tour is mostly still and fine);\n // the warning is dead time: a hold nobody is reading, named per step.\n const dead = deadTime(stepSpans, frames, events, durationMs)\n if (deadWarns(dead)) log(` WARNING: ${deadLine(dead)}`)\n\n const pace = paceReport(paces)\n if (!dry) log(` ${paceLine(pace)}`)\n return {\n events,\n frames,\n meta,\n pace,\n skipped,\n navTimeout,\n wall,\n exposures: exposureLog.exposures(),\n masks: exposureLog.masks(masks),\n freezes,\n freezePct,\n dead,\n capped,\n disabled,\n confirmed,\n skips,\n outputs,\n stopped,\n pageErrors: pageErrors.entries(),\n actions: { ...actions, url },\n }\n}\n\n/** A download's extension from its type, for a name the page did not give. */\nconst EXT_FOR_TYPE: Record<string, string> = {\n 'video/mp4': '.mp4',\n 'video/webm': '.webm',\n 'video/quicktime': '.mov',\n 'audio/mpeg': '.mp3',\n 'audio/mp4': '.m4a',\n 'audio/wav': '.wav',\n 'audio/ogg': '.ogg',\n 'image/png': '.png',\n 'image/jpeg': '.jpg',\n 'image/webp': '.webp',\n 'image/gif': '.gif',\n 'image/svg+xml': '.svg',\n 'application/pdf': '.pdf',\n 'application/json': '.json',\n 'text/csv': '.csv',\n 'application/zip': '.zip',\n}\n\nexport function extForType(type: string | undefined): string {\n return (type && EXT_FOR_TYPE[type.split(';')[0].trim().toLowerCase()]) ?? ''\n}\n\n/** A download's type from its name's extension, as `{ contentType }`, or `{}` when the extension says nothing. */\nexport function typeOfName(name: string): { contentType?: string } {\n const ext = name.slice(name.lastIndexOf('.')).toLowerCase()\n if (!name.includes('.')) return {}\n for (const [type, e] of Object.entries(EXT_FOR_TYPE))\n if (e === ext) return { contentType: type }\n return ext === '.jpeg' ? { contentType: 'image/jpeg' } : {}\n}\n","/**\n * Frames → CFR WebM, as a PAGE. The VFR screencast JPEGs are drawn\n * hold-last-frame onto a canvas at a fixed 30fps and encoded with\n * mediabunny (WebCodecs) inside a headless page — no ffmpeg dependency.\n * The CLI serves the take directory to it and reads the bytes back through\n * its own `/save`; the fleet serves the frames through the ingest route and\n * the page PUTs the recording to the same route. One page, two hosts: the\n * URLs and the way out are the host's, the encode is not.\n */\n\nconst MEDIABUNNY_URL = 'https://esm.sh/mediabunny@1.55.7?target=es2022'\n\nexport interface EncodePageOptions {\n /** Where `frames.json` (the index `[{file, tMs}]`) is fetched from. */\n framesIndexUrl: string\n /** Where `meta.json` is fetched from. */\n metaUrl: string\n /** `<framesBaseUrl><file>` is each JPEG. */\n framesBaseUrl: string\n /** The way out: a POST to the CLI's take server, or a PUT to the ingest route. */\n save: { method: 'POST' | 'PUT'; url: string }\n /** Optional `?rt=`-style query the frame fetches must carry (the fleet's token). */\n frameQuery?: string\n /** Where mediabunny loads from (a host's mirror); esm.sh by default. */\n mediabunnyUrl?: string\n}\n\nexport function buildEncodePage(o: EncodePageOptions): string {\n const q = o.frameQuery ? `?${o.frameQuery}` : ''\n const mediabunnyUrl = o.mediabunnyUrl ?? MEDIABUNNY_URL\n return `<!doctype html><html><head><meta charset=\"utf-8\"></head><body>\n<script type=\"module\">\ntry {\n const MB = await import(${JSON.stringify(mediabunnyUrl)})\n const frames = await (await fetch(${JSON.stringify(o.framesIndexUrl)})).json()\n const meta = await (await fetch(${JSON.stringify(o.metaUrl)})).json()\n const W = meta.captureWidth ?? meta.width, H = meta.captureHeight ?? meta.height\n const FPS = 30\n const durSec = meta.durationMs / 1000\n const cv = document.createElement('canvas')\n cv.width = W; cv.height = H\n const c2 = cv.getContext('2d')\n const output = new MB.Output({ format: new MB.WebMOutputFormat(), target: new MB.BufferTarget() })\n const src = new MB.CanvasSource(cv, { codec: 'vp9', bitrate: 8_000_000 })\n output.addVideoTrack(src, { frameRate: FPS })\n await output.start()\n let fi = -1\n const total = Math.ceil(durSec * FPS)\n for (let i = 0; i < total; i++) {\n const t = i / FPS\n let next = fi\n while (next + 1 < frames.length && frames[next + 1].tMs <= t * 1000) next++\n if (next < 0) next = 0\n if (next !== fi) {\n fi = next\n const blob = await (await fetch(${JSON.stringify(o.framesBaseUrl)} + frames[fi].file + ${JSON.stringify(q)})).blob()\n const bmp = await createImageBitmap(blob)\n c2.drawImage(bmp, 0, 0, W, H)\n bmp.close()\n }\n await src.add(t, 1 / FPS)\n window.__progress = i / total\n }\n await output.finalize()\n const buf = output.target.buffer\n const res = await fetch(${JSON.stringify(o.save.url)}, { method: ${JSON.stringify(o.save.method)}, headers: { 'content-type': 'video/webm' }, body: buf })\n if (!res.ok) throw new Error('save failed: ' + res.status)\n // Two hosts, two completion words: the CLI's take server polls __done,\n // the fleet's page runner polls __renderComplete.\n window.__done = { ok: true, bytes: buf.byteLength }\n window.__renderComplete = { success: true, size: buf.byteLength, uploaded: true }\n} catch (e) {\n window.__error = String(e && e.stack || e)\n window.__renderComplete = { success: false, error: String(e && e.message || e) }\n}\n</script></body></html>`\n}\n","/**\n * The FRESH plan of a take: what `vos record` writes as doc.json the moment\n * a recording lands, and what a hosted take gets on the fleet. One\n * composition, so a take recorded anywhere opens on the same camera: the\n * artifact becomes a document (`projectFromArtifact`), the zooms are\n * planned from the cursor track, the speed spans from the same track. The\n * backdrop is a host's PICK (vosso's house set, the CLI's `--background`),\n * handed in as a wire row; studio-core carries only the mechanism.\n *\n * The CLI's `vos plan` is the fuller verb (reuse, style, motion, a still);\n * this is its fresh branch, byte-identical to it.\n */\nimport {\n DEFAULT_FRAME_STYLE,\n planAutoSpeed,\n planAutoZoom,\n projectFromArtifact,\n withBackdrop,\n} from '@vosjs/studio-core'\nimport type {\n Backdrop,\n ProjectDoc,\n RecordingArtifact,\n} from '@vosjs/studio-core'\n\nexport interface FreshPlanOptions {\n /** The backdrop the document opens on; absent keeps the bare frame. */\n backdrop?: Backdrop | null\n /** A digest's activity bins, when one exists (the speed planner's witness). */\n activity?: readonly number[] | null\n}\n\nexport function planFreshTake(\n artifact: RecordingArtifact,\n recordingName: string,\n opts: FreshPlanOptions = {},\n): ProjectDoc {\n const ingest = opts.backdrop\n ? { frame: withBackdrop(DEFAULT_FRAME_STYLE, opts.backdrop) }\n : {}\n const doc = projectFromArtifact(artifact, recordingName, ingest).doc\n doc.segments = splitSegmentsAtSkips(doc.segments, artifact.meta.skips)\n doc.zoom = planAutoZoom(doc.source.cursor, {\n width: doc.source.meta.width,\n height: doc.source.meta.height,\n duration: doc.source.meta.durationMs / 1000,\n style: doc.zoomStyle,\n params: doc.zoomParams,\n })\n doc.speed = planAutoSpeed(doc.source.cursor, {\n durationMs: doc.source.meta.durationMs,\n params: doc.speedParams,\n activity: opts.activity,\n })\n return doc\n}\n\n/**\n * The footage's segments split at every cut an `await` made\n * (`meta.skips[].at`, source seconds), so each cut is a real segment\n * boundary: the timeline shows it, a transition can sit on it, a trim can\n * take either side. A cut at an edge or outside a segment splits nothing,\n * and a segment of another media is left alone. A split segment keeps its\n * arrival on its first piece and its leaving on its last.\n */\nexport function splitSegmentsAtSkips(\n segments: ProjectDoc['segments'],\n skips: readonly { at: number }[] | undefined,\n): ProjectDoc['segments'] {\n if (!skips?.length) return segments\n const cuts = [...new Set(skips.map((s) => s.at))].sort((a, b) => a - b)\n const out: ProjectDoc['segments'] = []\n for (const seg of segments) {\n const inside = seg.media\n ? []\n : cuts.filter((at) => at > seg.in + 1e-3 && at < seg.out - 1e-3)\n if (!inside.length) {\n out.push(seg)\n continue\n }\n const { anim, hold, ...plain } = seg\n const edges = [seg.in, ...inside, seg.out]\n for (let i = 0; i < edges.length - 1; i++) {\n const first = i === 0\n const last = i === edges.length - 2\n const pieceAnim =\n anim && (first || last)\n ? {\n ...(first && anim.enter ? { enter: anim.enter } : {}),\n ...(last && anim.exit ? { exit: anim.exit } : {}),\n }\n : null\n out.push({\n ...plain,\n in: edges[i],\n out: edges[i + 1],\n ...(pieceAnim && Object.keys(pieceAnim).length\n ? { anim: pieceAnim }\n : {}),\n ...(last && hold !== undefined ? { hold } : {}),\n })\n }\n }\n return out\n}\n"],"mappings":"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","names":["askedMs","VERBS","type","opts"]}